Restructure repository

* Move /common/src to /src
* Move services to net.psforever package
* Move /pslogin to /server
This commit is contained in:
Jakob Gillich 2020-08-23 03:26:06 +02:00
parent 89a30ae6f6
commit f4fd78fc5d
958 changed files with 527 additions and 725 deletions

View file

@ -0,0 +1,110 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.GlobalDefinitions._
import net.psforever.objects._
import net.psforever.objects.avatar.{Avatar, BattleRank, Implant}
import net.psforever.objects.definition.ImplantDefinition
import net.psforever.types.{CharacterGender, CharacterVoice, ImplantType, PlanetSideEmpire}
import org.specs2.mutable._
class AvatarTest extends Specification {
def CreatePlayer(): (Player, Avatar) = {
val avatar = Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 41, CharacterVoice.Voice1)
val player = Player(avatar)
player.Slot(0).Equipment = Tool(beamer)
player.Slot(2).Equipment = Tool(suppressor)
player.Slot(4).Equipment = Tool(forceblade)
player.Slot(6).Equipment = AmmoBox(bullet_9mm)
player.Slot(9).Equipment = AmmoBox(bullet_9mm)
player.Slot(12).Equipment = AmmoBox(bullet_9mm)
player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
player.Slot(36).Equipment = AmmoBox(energy_cell)
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
(player, avatar)
}
"construct" in {
val av = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
av.name mustEqual "Chord"
av.faction mustEqual PlanetSideEmpire.TR
av.sex mustEqual CharacterGender.Male
av.head mustEqual 0
av.voice mustEqual CharacterVoice.Voice5
av.bep mustEqual 0
av.cep mustEqual 0
av.certifications mustEqual Set.empty
av.definition.ObjectId mustEqual 121
}
"can not maintain experience point values below zero" in {
val av = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
av.bep mustEqual 0
av.copy(bep = -1) must throwA[AssertionError]
av.copy(cep = -1) must throwA[AssertionError]
}
//refer to ImplantTest.scala for more tests
"maximum of three implant slots" in {
val obj = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.implants.length mustEqual 3
obj.implants(0) must beNone
obj.implants(1) must beNone
obj.implants(2) must beNone
obj.implants.lift(3) must beNone
}
"can install an implant" in {
val testplant = Implant(new ImplantDefinition(ImplantType.AdvancedRegen))
var obj = Avatar(
0,
"Chord",
PlanetSideEmpire.TR,
CharacterGender.Male,
0,
CharacterVoice.Voice5,
bep = BattleRank.BR6.experience
)
obj.implants.nonEmpty must beTrue
obj.implants.length mustEqual 3
obj = obj.copy(implants = obj.implants.updated(0, Some(testplant)))
obj.implants.flatten.find(_.definition.implantType == ImplantType.AdvancedRegen) match {
case Some(slot) =>
slot.definition mustEqual testplant.definition
case _ =>
ko
}
ok
}
"can not install the same type of implant twice" in {
val testplant1 = Implant(new ImplantDefinition(ImplantType.AdvancedRegen))
val testplant2 = Implant(new ImplantDefinition(ImplantType.AdvancedRegen))
val obj = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.copy(implants = obj.implants.updated(0, Some(testplant1)).updated(1, Some(testplant2))) must throwA[
AssertionError
]
}
"can not install more implants than slots available" in {
val testplant1 = Implant(new ImplantDefinition(ImplantType.AdvancedRegen))
val testplant2 = Implant(new ImplantDefinition(ImplantType.Surge))
val testplant3 = Implant(new ImplantDefinition(ImplantType.DarklightVision))
val obj = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.copy(
bep = BattleRank.BR12.value,
implants = Seq(Some(testplant1), Some(testplant2), Some(testplant3))
) must throwA[
AssertionError
]
}
"the fifth slot is the locker wrapped in an EquipmentSlot" in {
val (_, avatar) = CreatePlayer()
avatar.fifthSlot().Equipment match {
case Some(slot: LockerEquipment) => slot.Inventory mustEqual avatar.locker.Inventory
case _ => ko
}
}
}

View file

@ -0,0 +1,122 @@
// Copyright (c) 2017 PSForever
package objects
import base.ActorTest
import net.psforever.actors.zone.BuildingActor
import net.psforever.objects.{Default, GlobalDefinitions}
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.structures._
import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable.Specification
import akka.actor.typed.scaladsl.adapter._
class AmenityTest extends Specification {
val definition = new AmenityDefinition(0) {
//intentionally blank
}
class AmenityObject extends Amenity {
def Definition: AmenityDefinition = definition
}
"Amenity" should {
"construct" in {
val ao = new AmenityObject()
ao.Owner mustEqual Building.NoBuilding
}
"can be owned by a building" in {
val ao = new AmenityObject()
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
ao.Owner = bldg
ao.Owner mustEqual bldg
}
"be owned by a vehicle" in {
import net.psforever.objects.Vehicle
val ao = new AmenityObject()
val veh = Vehicle(GlobalDefinitions.quadstealth)
ao.Owner = veh
ao.Owner mustEqual veh
}
"not be owned by an unexpected object" in {
val ao = new AmenityObject()
//ao.Owner = net.psforever.objects.serverobject.mblocker.Locker() //will not compile
ok
}
"confer faction allegiance through ownership" in {
//see FactionAffinityTest
val ao = new AmenityObject()
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
ao.Owner = bldg
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
ao.Faction mustEqual PlanetSideEmpire.NEUTRAL
bldg.Faction = PlanetSideEmpire.TR
bldg.Faction mustEqual PlanetSideEmpire.TR
ao.Faction mustEqual PlanetSideEmpire.TR
}
}
}
class BuildingTest extends Specification {
"Building" should {
"construct" in {
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
bldg.MapId mustEqual 10
bldg.Actor mustEqual Default.Actor
bldg.Amenities mustEqual Nil
bldg.Zone mustEqual Zone.Nowhere
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
}
"change faction affinity" in {
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
bldg.Faction = PlanetSideEmpire.TR
bldg.Faction mustEqual PlanetSideEmpire.TR
}
"keep track of amenities" in {
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
val door1 = Door(GlobalDefinitions.door)
val door2 = Door(GlobalDefinitions.door)
bldg.Amenities mustEqual Nil
bldg.Amenities = door2
bldg.Amenities mustEqual List(door2)
bldg.Amenities = door1
bldg.Amenities mustEqual List(door2, door1)
door1.Owner mustEqual bldg
door2.Owner mustEqual bldg
}
}
}
class WarpGateTest extends Specification {
"WarpGate" should {
"construct" in {
val bldg = WarpGate("WarpGate", 0, 10, Zone.Nowhere, GlobalDefinitions.warpgate)
bldg.MapId mustEqual 10
bldg.Actor mustEqual Default.Actor
bldg.Amenities mustEqual Nil
bldg.Zone mustEqual Zone.Nowhere
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
}
}
}
class BuildingActor1Test extends ActorTest {
"Building Control" should {
"construct" in {
val bldg = Building("Building", 0, 10, Zone.Nowhere, StructureType.Building)
bldg.Actor = system.spawn(BuildingActor(Zone.Nowhere, bldg), "test").toClassic
assert(bldg.Actor != Default.Actor)
}
}
}

View file

@ -0,0 +1,59 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot}
import net.psforever.objects.inventory.{Container, GridInventory, InventoryEquipmentSlot}
import net.psforever.objects.{GlobalDefinitions, OffhandEquipmentSlot, Tool}
import net.psforever.types.PlanetSideGUID
import org.specs2.mutable._
import scala.util.Success
class ContainerTest extends Specification {
"Container" should {
"construct" in {
val obj = new ContainerTest.CObject
obj.VisibleSlots mustEqual (0 until 9).toSet
obj.Inventory.Size mustEqual 0
obj.Inventory.Capacity mustEqual 9
obj.Find(PlanetSideGUID(0)) mustEqual None
obj.Slot(0).isInstanceOf[OffhandEquipmentSlot] mustEqual true
obj.Slot(0).isInstanceOf[InventoryEquipmentSlot] mustEqual true
obj.Slot(0).isInstanceOf[EquipmentSlot] mustEqual true
obj.Slot(0).Size mustEqual EquipmentSize.Inventory
obj.Slot(0).Equipment mustEqual None
obj.Collisions(0, 2, 2) mustEqual Success(List())
}
"Collisions can Find items in Inventory (default behavior)" in {
val obj = new ContainerTest.CObject
val weapon = Tool(GlobalDefinitions.beamer)
weapon.GUID = PlanetSideGUID(1)
obj.Inventory += 0 -> weapon
obj.Find(PlanetSideGUID(1)) match {
case Some(index) =>
obj.Inventory.Items(index).obj mustEqual weapon
case None =>
ko
}
obj.Collisions(1, 1, 1) match {
case Success(items) =>
items.length mustEqual 1
items.head.obj mustEqual weapon
case _ => ;
ko
}
}
}
}
object ContainerTest {
class CObject extends Container {
private val inv = GridInventory(3, 3)
def Inventory: GridInventory = inv
def VisibleSlots: Set[Int] = Set[Int](0, 1, 2, 3, 4, 5, 6, 7, 8)
}
}

View file

@ -0,0 +1,949 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.definition.converter.{CharacterSelectConverter, DestroyedVehicleConverter, REKConverter}
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.definition._
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vehicles.UtilityType
import net.psforever.packet.game.objectcreate._
import net.psforever.types._
import org.specs2.mutable.Specification
import scala.util.{Failure, Success}
class ConverterTest extends Specification {
"AmmoBox" should {
val bullet_9mm = AmmoBoxDefinition(28)
bullet_9mm.Capacity = 50
"convert to packet" in {
val obj = AmmoBox(bullet_9mm)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedAmmoBoxData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
bops = false,
alternate = false,
true,
None,
false,
None,
None,
PlanetSideGUID(0)
),
obj.Capacity
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual CommonFieldData(
PlanetSideEmpire.NEUTRAL,
bops = false,
alternate = false,
false,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
case _ =>
ko
}
}
}
"Tool" should {
"convert to packet (1 fire mode slot)" in {
val obj: Tool = Tool(GlobalDefinitions.flechette)
obj.AmmoSlot.Box.GUID = PlanetSideGUID(90)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedWeaponData(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
0,
List(InternalSlot(Ammo.shotgun_shell.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 12)))
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual WeaponData(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
0,
List(
InternalSlot(
Ammo.shotgun_shell.id,
PlanetSideGUID(90),
0,
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
false,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
)
)
case _ =>
ko
}
}
"convert to packet (2 fire mode slots)" in {
val obj: Tool = Tool(GlobalDefinitions.punisher)
obj.AmmoSlots.head.Box.GUID = PlanetSideGUID(90)
obj.AmmoSlots(1).Box.GUID = PlanetSideGUID(91)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedWeaponData(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
0,
List(
InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, DetailedAmmoBoxData(8, 30)),
InternalSlot(Ammo.rocket.id, PlanetSideGUID(91), 1, DetailedAmmoBoxData(8, 1))
)
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual WeaponData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL, //TODO need faction affinity
bops = false,
alternate = false,
true,
None,
false,
None,
None,
PlanetSideGUID(0)
),
0,
List(
InternalSlot(Ammo.bullet_9mm.id, PlanetSideGUID(90), 0, CommonFieldData()(false)),
InternalSlot(Ammo.rocket.id, PlanetSideGUID(91), 1, CommonFieldData()(false))
)
)
case _ =>
ko
}
}
}
"Kit" should {
"convert to packet" in {
val kdef = KitDefinition(Kits.medkit)
val obj = Kit(kdef)
obj.GUID = PlanetSideGUID(90)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedAmmoBoxData(0, 1)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual CommonFieldData()(false)
case _ =>
ko
}
}
"ConstructionItem" should {
"convert to packet" in {
val obj = ConstructionItem(GlobalDefinitions.ace)
obj.GUID = PlanetSideGUID(90)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedConstructionToolData(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual HandheldData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
true,
None,
false,
None,
None,
PlanetSideGUID(0)
)
)
case _ =>
ko
}
}
}
}
"SimpleItem" should {
"convert to packet" in {
val sdef = SimpleItemDefinition(SItem.remote_electronics_kit)
sdef.Packet = new REKConverter()
val obj = SimpleItem(sdef)
obj.GUID = PlanetSideGUID(90)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedREKData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL, //TODO faction affinity
false,
false,
true,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual REKData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
true,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
case _ =>
ko
}
}
}
"BoomerTrigger" should {
"convert" in {
val obj = new BoomerTrigger
obj.GUID = PlanetSideGUID(90)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedConstructionToolData(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0))
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual HandheldData(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, false, None, false, None, None, PlanetSideGUID(0))
)
case _ =>
ko
}
}
}
"Telepad" should {
"convert (success)" in {
val obj = new Telepad(GlobalDefinitions.router_telepad)
obj.Router = PlanetSideGUID(1001)
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual HandheldData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
false,
None,
false,
None,
Some(1001),
PlanetSideGUID(0)
)
)
case _ =>
ko
}
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedConstructionToolData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
true,
None,
false,
None,
Some(1001),
PlanetSideGUID(0)
)
)
case _ =>
ko
}
}
"convert (failure; no router)" in {
val obj = new Telepad(GlobalDefinitions.router_telepad)
//obj.Router = PlanetSideGUID(1001)
obj.Definition.Packet.ConstructorData(obj).isFailure mustEqual true
obj.Definition.Packet.DetailedConstructorData(obj).isFailure mustEqual true
}
}
"SmallDeployable" should {
"convert" in {
val obj = new SensorDeployable(GlobalDefinitions.motionalarmsensor)
obj.Faction = PlanetSideEmpire.TR
obj.Definition.Packet.DetailedConstructorData(obj).isFailure mustEqual true
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual CommonFieldDataWithPlacement(
PlacementData(Vector3.Zero, Vector3.Zero),
CommonFieldData(
PlanetSideEmpire.TR,
false,
false,
false,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
case _ =>
ko
}
}
}
"SmallTurret" should {
"convert" in {
val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
obj.Weapons(1).Equipment.get.GUID = PlanetSideGUID(91)
obj.Weapons(1).Equipment.get.asInstanceOf[Tool].AmmoSlot.Box.GUID = PlanetSideGUID(92)
obj.Definition.Packet.DetailedConstructorData(obj).isFailure mustEqual true
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual SmallTurretData(
CommonFieldDataWithPlacement(
PlacementData(Vector3.Zero, Vector3.Zero),
CommonFieldData(
PlanetSideEmpire.TR,
false,
false,
false,
None,
false,
Some(true),
None,
PlanetSideGUID(0)
)
),
255,
InventoryData(
List(
InternalSlot(
ObjectClass.spitfire_weapon,
PlanetSideGUID(91),
1,
WeaponData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
true,
None,
false,
None,
None,
PlanetSideGUID(0)
),
0,
List(
InternalSlot(
Ammo.spitfire_ammo.id,
PlanetSideGUID(92),
0,
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
false,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
)
)
)
)
)
)
case _ =>
ko
}
}
}
"FieldTurret" should {
"convert" in {
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
obj.Weapons(1).Equipment.get.GUID = PlanetSideGUID(91)
obj.Weapons(1).Equipment.get.asInstanceOf[Tool].AmmoSlot.Box.GUID = PlanetSideGUID(92)
obj.Definition.Packet.DetailedConstructorData(obj).isFailure mustEqual true
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual OneMannedFieldTurretData(
CommonFieldDataWithPlacement(
PlacementData(Vector3.Zero, Vector3.Zero),
CommonFieldData(
PlanetSideEmpire.TR,
false,
false,
true,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
),
255,
InventoryData(
List(
InternalSlot(
ObjectClass.energy_gun_tr,
PlanetSideGUID(91),
1,
WeaponData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
true,
None,
false,
None,
None,
PlanetSideGUID(0)
),
0,
List(
InternalSlot(
Ammo.energy_gun_ammo.id,
PlanetSideGUID(92),
0,
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
false,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
)
)
)
)
)
)
case _ =>
ko
}
}
}
"TRAP" should {
"convert" in {
val obj = new TrapDeployable(GlobalDefinitions.tank_traps)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
obj.Definition.Packet.DetailedConstructorData(obj).isFailure mustEqual true
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual TRAPData(
CommonFieldDataWithPlacement(
PlacementData(Vector3.Zero, Vector3.Zero),
CommonFieldData(
PlanetSideEmpire.TR,
bops = false,
alternate = false,
true,
None,
false,
Some(true),
None,
PlanetSideGUID(0)
)
),
255
)
case _ =>
ko
}
}
}
"ShieldGenerator" should {
"convert" in {
val obj = new ShieldGeneratorDeployable(GlobalDefinitions.deployable_shield_generator)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
obj.Definition.Packet.DetailedConstructorData(obj).isFailure mustEqual true
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual AegisShieldGeneratorData(
CommonFieldDataWithPlacement(
PlacementData(Vector3.Zero, Vector3.Zero),
PlanetSideEmpire.TR,
0
),
255
)
case _ =>
ko
}
}
}
"TelepadDeployable" should {
"convert (success)" in {
val obj = new TelepadDeployable(GlobalDefinitions.router_telepad_deployable)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
obj.Router = PlanetSideGUID(1001)
obj.Owner = PlanetSideGUID(5001)
obj.Health = 1
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DroppedItemData(
PlacementData(Vector3.Zero, Vector3.Zero),
TelepadDeployableData(
CommonFieldData(
PlanetSideEmpire.TR,
bops = false,
alternate = false,
true,
None,
false,
None,
Some(1001),
PlanetSideGUID(5001)
),
unk1 = 87,
unk2 = 12
)
)
case _ =>
ko
}
}
"convert (success; destroyed)" in {
val obj = new TelepadDeployable(GlobalDefinitions.router_telepad_deployable)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
obj.Router = PlanetSideGUID(1001)
obj.Owner = PlanetSideGUID(5001)
obj.Health = 0
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DroppedItemData(
PlacementData(Vector3.Zero, Vector3.Zero),
TelepadDeployableData(
CommonFieldData(
PlanetSideEmpire.TR,
bops = false,
alternate = true,
true,
None,
false,
None,
Some(1001),
PlanetSideGUID(0)
),
unk1 = 0,
unk2 = 6
)
)
case _ =>
ko
}
}
"convert (failure; no router)" in {
val obj = new TelepadDeployable(GlobalDefinitions.router_telepad_deployable)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
//obj.Router = PlanetSideGUID(1001)
obj.Owner = PlanetSideGUID(5001)
obj.Health = 1
obj.Definition.Packet.ConstructorData(obj).isFailure mustEqual true
obj.Router = PlanetSideGUID(0)
obj.Definition.Packet.ConstructorData(obj).isFailure mustEqual true
}
"convert (failure; detailed)" in {
val obj = new TelepadDeployable(GlobalDefinitions.router_telepad_deployable)
obj.Faction = PlanetSideEmpire.TR
obj.GUID = PlanetSideGUID(90)
obj.Router = PlanetSideGUID(1001)
obj.Owner = PlanetSideGUID(5001)
obj.Health = 1
obj.Definition.Packet.DetailedConstructorData(obj).isFailure mustEqual true
}
}
"Player" should {
var avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val obj: Player = {
/*
Create an AmmoBoxDefinition with which to build two AmmoBoxes
Create a ToolDefinition with which to create a Tool
Load one of the AmmoBoxes into that Tool
Create a Player
Give the Player's Holster (2) the Tool
Place the remaining AmmoBox into the Player's inventory in the third slot (8)
*/
val tdef = ToolDefinition(1076)
tdef.Name = "sample_weapon"
tdef.Size = EquipmentSize.Rifle
tdef.AmmoTypes += GlobalDefinitions.bullet_9mm
tdef.FireModes += new FireModeDefinition
tdef.FireModes.head.AmmoTypeIndices += 0
tdef.FireModes.head.AmmoSlotIndex = 0
tdef.FireModes.head.Magazine = 18
val tool = Tool(tdef)
tool.GUID = PlanetSideGUID(92)
tool.AmmoSlot.Box.GUID = PlanetSideGUID(90)
val obj = Player(avatar)
obj.GUID = PlanetSideGUID(93)
obj.Slot(2).Equipment = tool
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(94)
obj.Inventory += 8 -> AmmoBox(GlobalDefinitions.bullet_9mm)
obj.Slot(8).Equipment.get.GUID = PlanetSideGUID(91)
obj
}
val converter = new CharacterSelectConverter
"convert to packet (BR < 24)" in {
avatar = avatar.copy(bep = 0)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(_) =>
ok
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(_) =>
ok
case _ =>
ko
}
}
"convert to packet (BR >= 24)" in {
avatar = avatar.copy(bep = 10000000)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(_) =>
ok
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(_) =>
ok
case _ =>
ko
}
}
"convert to simple packet (BR < 24)" in {
avatar = avatar.copy(bep = 0)
converter.DetailedConstructorData(obj) match {
case Success(_) =>
ok
case _ =>
ko
}
converter.ConstructorData(obj).isFailure mustEqual true
converter.ConstructorData(obj).get must throwA[Exception]
}
"convert to simple packet (BR >= 24)" in {
avatar = avatar.copy(bep = 10000000)
converter.DetailedConstructorData(obj) match {
case Success(_) =>
ok
case _ =>
ko
}
converter.ConstructorData(obj).isFailure mustEqual true
converter.ConstructorData(obj).get must throwA[Exception]
}
}
"LockerContainer" should {
"convert to packet (empty)" in {
val obj = new LockerEquipment(LockerContainer())
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedLockerContainerData(
CommonFieldData(PlanetSideEmpire.NEUTRAL, false, false, true, None, false, None, None, PlanetSideGUID(0)),
None
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual LockerContainerData(None)
case _ =>
ko
}
}
"convert to packet (occupied)" in {
import GlobalDefinitions._
val obj = new LockerEquipment(LockerContainer())
val rek = SimpleItem(remote_electronics_kit)
rek.GUID = PlanetSideGUID(1)
obj.Inventory += 0 -> rek
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual DetailedLockerContainerData(
8,
InternalSlot(
remote_electronics_kit.ObjectId,
PlanetSideGUID(1),
0,
DetailedREKData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
true,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
) :: Nil
)
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual LockerContainerData(
InventoryData(
InternalSlot(
remote_electronics_kit.ObjectId,
PlanetSideGUID(1),
0,
REKData(
CommonFieldData(
PlanetSideEmpire.NEUTRAL,
false,
false,
true,
None,
false,
Some(false),
None,
PlanetSideGUID(0)
)
)
) :: Nil
)
)
case _ =>
ko
}
}
}
"Terminal" should {
"convert to packet" in {
val obj = Terminal(GlobalDefinitions.order_terminala)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Failure(err) =>
err.isInstanceOf[NoSuchMethodException] mustEqual true
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(false)
case _ =>
ko
}
}
}
"Spawn Tube" should {
"convert to packet" in {
val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
obj.Definition.Packet.DetailedConstructorData(obj) match {
case Failure(err) =>
err.isInstanceOf[NoSuchMethodException] mustEqual true
case _ =>
ko
}
obj.Definition.Packet.ConstructorData(obj) match {
case Success(pkt) =>
pkt mustEqual CommonFieldData(PlanetSideEmpire.NEUTRAL)(false)
case _ =>
ko
}
}
}
"Vehicle" should {
"convert to packet (1)" in {
val hellfire_ammo = AmmoBoxDefinition(Ammo.hellfire_ammo.id)
val fury_weapon_systema_def = ToolDefinition(ObjectClass.fury_weapon_systema)
fury_weapon_systema_def.Size = EquipmentSize.VehicleWeapon
fury_weapon_systema_def.AmmoTypes += GlobalDefinitions.hellfire_ammo
fury_weapon_systema_def.FireModes += new FireModeDefinition
fury_weapon_systema_def.FireModes.head.AmmoTypeIndices += 0
fury_weapon_systema_def.FireModes.head.AmmoSlotIndex = 0
fury_weapon_systema_def.FireModes.head.Magazine = 2
val fury_def = VehicleDefinition(ObjectClass.fury)
fury_def.Seats += 0 -> new SeatDefinition()
fury_def.Seats(0).Bailable = true
fury_def.Seats(0).ControlledWeapon = Some(1)
fury_def.MountPoints += 0 -> 0
fury_def.MountPoints += 2 -> 0
fury_def.Weapons += 1 -> fury_weapon_systema_def
fury_def.TrunkSize = InventoryTile(11, 11)
fury_def.TrunkOffset = 30
val hellfire_ammo_box = AmmoBox(hellfire_ammo)
hellfire_ammo_box.GUID = PlanetSideGUID(432)
val fury = Vehicle(fury_def)
fury.GUID = PlanetSideGUID(413)
fury.Faction = PlanetSideEmpire.VS
fury.Position = Vector3(3674.8438f, 2732f, 91.15625f)
fury.Orientation = Vector3(0.0f, 0.0f, 90.0f)
fury.WeaponControlledFromSeat(0).get.GUID = PlanetSideGUID(400)
fury.WeaponControlledFromSeat(0).get.asInstanceOf[Tool].AmmoSlots.head.Box = hellfire_ammo_box
fury.Definition.Packet.ConstructorData(fury).isSuccess mustEqual true
ok //TODO write more of this test
}
"convert to packet (2)" in {
val ams = Vehicle(GlobalDefinitions.ams)
ams.GUID = PlanetSideGUID(413)
ams.Utilities(1)().GUID = PlanetSideGUID(414)
ams.Utilities(2)().GUID = PlanetSideGUID(415)
ams.Utilities(3)().GUID = PlanetSideGUID(416)
ams.Utilities(4)().GUID = PlanetSideGUID(417)
ams.Definition.Packet.ConstructorData(ams).isSuccess mustEqual true
}
"convert to packet (3)" in {
val ams = Vehicle(GlobalDefinitions.ams)
ams.GUID = PlanetSideGUID(413)
ams.Health = 0 //destroyed vehicle
ams.Definition.Packet.ConstructorData(ams).isSuccess mustEqual true
//did not initialize the utilities, but the converter did not fail
}
"convert to packet (4)" in {
val router = Vehicle(GlobalDefinitions.router)
router.GUID = PlanetSideGUID(413)
router.Utility(UtilityType.teleportpad_terminal).get.GUID = PlanetSideGUID(1413)
router.Utility(UtilityType.internal_router_telepad_deployable).get.GUID = PlanetSideGUID(2413)
router.Definition.Packet.ConstructorData(router).isSuccess mustEqual true
}
}
"DestroyedVehicle" should {
"not convert a working vehicle" in {
val ams = Vehicle(GlobalDefinitions.ams)
ams.GUID = PlanetSideGUID(413)
(ams.Health > 0) mustEqual true //not destroyed vehicle
DestroyedVehicleConverter.converter.ConstructorData(ams).isFailure mustEqual true
}
"convert to packet" in {
val ams = Vehicle(GlobalDefinitions.ams)
ams.GUID = PlanetSideGUID(413)
ams.Health = 0
DestroyedVehicleConverter.converter.ConstructorData(ams).isSuccess mustEqual true
//did not initialize the utilities, but the converter did not fail
}
"not convert into a detailed packet" in {
val ams = Vehicle(GlobalDefinitions.ams)
ams.GUID = PlanetSideGUID(413)
ams.Health = 0
DestroyedVehicleConverter.converter.DetailedConstructorData(ams).isFailure mustEqual true
}
}
}

View file

@ -0,0 +1,608 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects._
import net.psforever.objects.vital.damage.{DamageCalculations, DamageModifiers, DamageProfile}
import DamageCalculations._
import net.psforever.objects.vital.resistance.ResistanceCalculations
import ResistanceCalculations._
import net.psforever.objects.vital.resolution.ResolutionCalculations
import ResolutionCalculations._
import net.psforever.objects.ballistics._
import net.psforever.objects.definition.{ProjectileDefinition, VehicleDefinition}
import net.psforever.objects.vital.{DamageType, Vitality}
import net.psforever.packet.game.objectcreate.ObjectClass
import net.psforever.types._
import org.specs2.mutable.Specification
import net.psforever.objects.avatar.Avatar
class DamageCalculationsTests extends Specification {
"DamageCalculations" should {
val wep = GlobalDefinitions.galaxy_gunship_cannon
val wep_fmode = Tool(wep).FireMode
val wep_prof = wep_fmode.Add
val proj = DamageModelTests.projectile
val proj_prof = proj.asInstanceOf[DamageProfile]
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
val target = Vehicle(GlobalDefinitions.fury)
target.Position = Vector3(10, 0, 0)
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(15, 0, 0)
)
"extract no damage numbers" in {
AgainstNothing(proj_prof) mustEqual 0
}
"extract damage against exosuit target" in {
AgainstExoSuit(proj_prof) == proj_prof.Damage0 mustEqual true
}
"extract damage against MAX target" in {
AgainstMaxSuit(proj_prof) == proj_prof.Damage3 mustEqual true
}
"extract damage against vehicle target" in {
AgainstVehicle(proj_prof) == proj_prof.Damage1 mustEqual true
}
"extract damage against aircraft target" in {
AgainstAircraft(proj_prof) == proj_prof.Damage2 mustEqual true
}
"extract damage against battleframe robotics" in {
AgainstBFR(proj_prof) == proj_prof.Damage4 mustEqual true
}
"no degrade damage modifier" in {
DamageModifiers.SameHit.Calculate(100, resprojectile) mustEqual 100
}
"degrade over distance damage modifier (no degrade)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(10, 0, 0)
)
DamageModifiers.DistanceDegrade.Calculate(100, resprojectile2) == 100 mustEqual true
}
"degrade over distance damage modifier (some degrade)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(100, 0, 0)
)
val damage = DamageModifiers.DistanceDegrade.Calculate(100, resprojectile2)
damage < 100 && damage > 0 mustEqual true
}
"degrade over distance damage modifier (zero'd)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(1000, 0, 0)
)
DamageModifiers.DistanceDegrade.Calculate(100, resprojectile2) == 0 mustEqual true
}
"degrade at radial distance damage modifier (no degrade)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(10, 0, 0)
)
DamageModifiers.RadialDegrade.Calculate(100, resprojectile2) == 100 mustEqual true
}
"degrade at radial distance damage modifier (some degrade)" in {
val damage = DamageModifiers.RadialDegrade.Calculate(100, resprojectile)
damage < 100 && damage > 0 mustEqual true
}
"degrade at radial distance damage modifier (zero'd)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(1000, 0, 0)
)
DamageModifiers.RadialDegrade.Calculate(100, resprojectile2) == 0 mustEqual true
}
"lash degrade (no lash; too close)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Lash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(5, 0, 0) //compared to Vector3(2, 2, 0)
)
DamageModifiers.Lash.Calculate(100, resprojectile2) == 0 mustEqual true
}
"lash degrade (lash)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Lash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(20, 0, 0)
)
val damage = DamageModifiers.Lash.Calculate(100, resprojectile2)
damage < 100 && damage > 0 mustEqual true
}
"lash degrade (no lash; too far)" in {
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Lash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3(1000, 0, 0)
)
DamageModifiers.Lash.Calculate(100, resprojectile2) == 0 mustEqual true
}
"extract a complete damage profile" in {
val result1 = DamageModifiers.RadialDegrade.Calculate(
AgainstVehicle(proj_prof) + AgainstVehicle(wep_prof),
resprojectile
)
val result2 = DamageCalculations.DamageWithModifiers(AgainstVehicle, resprojectile)
result1 mustEqual result2
}
}
}
class ResistanceCalculationsTests extends Specification {
val wep = GlobalDefinitions.galaxy_gunship_cannon
val wep_fmode = Tool(wep).FireMode
val proj = DamageModelTests.projectile
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
"ResistanceCalculations" should {
"ignore all targets" in {
val target = Vehicle(GlobalDefinitions.fury)
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3.Zero
)
InvalidTarget(resprojectile).isFailure mustEqual true
}
"discern standard infantry targets" in {
val target = player
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3.Zero
)
ValidInfantryTarget(resprojectile).isSuccess mustEqual true
ValidMaxTarget(resprojectile).isSuccess mustEqual false
ValidVehicleTarget(resprojectile).isSuccess mustEqual false
ValidAircraftTarget(resprojectile).isSuccess mustEqual false
}
"discern mechanized infantry targets" in {
val target = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
target.ExoSuit = ExoSuitType.MAX
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3.Zero
)
ValidInfantryTarget(resprojectile).isSuccess mustEqual false
ValidMaxTarget(resprojectile).isSuccess mustEqual true
ValidVehicleTarget(resprojectile).isSuccess mustEqual false
ValidAircraftTarget(resprojectile).isSuccess mustEqual false
}
"discern ground vehicle targets" in {
val target = Vehicle(GlobalDefinitions.fury)
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3.Zero
)
ValidInfantryTarget(resprojectile).isSuccess mustEqual false
ValidMaxTarget(resprojectile).isSuccess mustEqual false
ValidVehicleTarget(resprojectile).isSuccess mustEqual true
ValidAircraftTarget(resprojectile).isSuccess mustEqual false
}
"discern flying vehicle targets" in {
val target = Vehicle(GlobalDefinitions.mosquito)
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3.Zero
)
ValidInfantryTarget(resprojectile).isSuccess mustEqual false
ValidMaxTarget(resprojectile).isSuccess mustEqual false
ValidVehicleTarget(resprojectile).isSuccess mustEqual false
ValidAircraftTarget(resprojectile).isSuccess mustEqual true
}
"extract no resistance values" in {
NoResistExtractor(SourceEntry(player)) mustEqual 0
}
"extract resistance values from exo-suit" in {
val pSource = PlayerSource(player)
ExoSuitDirectExtractor(pSource) mustEqual 4
ExoSuitSplashExtractor(pSource) mustEqual 15
ExoSuitAggravatedExtractor(pSource) mustEqual 8
ExoSuitRadiationExtractor(pSource) mustEqual 0
}
"extract resistance values from vehicle" in {
val vSource = VehicleSource(Vehicle(GlobalDefinitions.fury))
VehicleDirectExtractor(vSource) mustEqual 0
VehicleSplashExtractor(vSource) mustEqual 0
VehicleAggravatedExtractor(vSource) mustEqual 0
VehicleRadiationExtractor(vSource) mustEqual 0
}
}
}
class ResolutionCalculationsTests extends Specification {
val wep = GlobalDefinitions.galaxy_gunship_cannon
val wep_fmode = Tool(wep).FireMode
val proj = DamageModelTests.projectile
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
player.Spawn()
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
"ResolutionCalculations" should {
"calculate no damage" in {
val target = player
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target),
target.DamageModel,
Vector3.Zero
)
ResolutionCalculations.NoDamage(resprojectile)(50, 50) mustEqual 0
}
"calculate no infantry damage for vehicles" in {
val target1 = Vehicle(GlobalDefinitions.fury) //!
val resprojectile1 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target1),
target1.DamageModel,
Vector3.Zero
)
InfantryDamageAfterResist(resprojectile1)(50, 10) mustEqual (0, 0)
val target2 = player
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target2),
target2.DamageModel,
Vector3.Zero
)
InfantryDamageAfterResist(resprojectile2)(50, 10) mustEqual (40, 10)
}
"calculate health and armor damage for infantry target" in {
InfantryDamageAfterResist(100, 100)(50, 10) mustEqual (40, 10)
}
"calculate health and armor damage, with bleed through damage, for infantry target" in {
//health = 100, armor = 5 -> resist 10 but only have 5, so rollover extra -> damages (40+5, 5)
InfantryDamageAfterResist(100, 5)(50, 10) mustEqual (45, 5)
}
"calculate health damage for infantry target" in {
//health = 100, armor = 0
InfantryDamageAfterResist(100, 0)(50, 10) mustEqual (50, 0)
}
"calculate armor damage for infantry target" in {
//resistance > damage
InfantryDamageAfterResist(100, 100)(50, 60) mustEqual (0, 50)
}
val player2 = Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
player2.ExoSuit = ExoSuitType.MAX
player2.Spawn()
"calculate no max damage for vehicles" in {
val target1 = Vehicle(GlobalDefinitions.fury) //!
val resprojectile1 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target1),
target1.DamageModel,
Vector3.Zero
)
MaxDamageAfterResist(resprojectile1)(50, 10) mustEqual (0, 0)
val target2 = player2
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target2),
target2.DamageModel,
Vector3.Zero
)
MaxDamageAfterResist(resprojectile2)(50, 10) mustEqual (0, 40)
}
"calculate health and armor damage for max target" in {
MaxDamageAfterResist(100, 5)(50, 10) mustEqual (35, 5)
}
"calculate health damage for max target" in {
//health = 100, armor = 0
MaxDamageAfterResist(100, 0)(50, 10) mustEqual (40, 0)
}
"calculate armor damage for max target" in {
//resistance > damage
MaxDamageAfterResist(100, 100)(50, 10) mustEqual (0, 40)
}
"do not care if target is infantry for vehicle calculations" in {
val target1 = player
val resprojectile1 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target1),
target1.DamageModel,
Vector3.Zero
)
VehicleDamageAfterResist(resprojectile1)(50, 10) mustEqual 40
val target2 = Vehicle(GlobalDefinitions.fury) //!
val resprojectile2 = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(target2),
target2.DamageModel,
Vector3.Zero
)
VehicleDamageAfterResist(resprojectile2)(50, 10) mustEqual 40
}
"calculate resisted damage for vehicle target" in {
VehicleDamageAfterResist(50, 10) mustEqual 40
}
"calculate un-resisted damage for vehicle target" in {
VehicleDamageAfterResist(50, 0) mustEqual 50
}
}
}
class DamageModelTests extends Specification {
val wep = GlobalDefinitions.galaxy_gunship_cannon
val wep_tool = Tool(wep)
val wep_fmode = wep_tool.FireMode
val proj = DamageModelTests.projectile
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
player.Spawn()
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
"DamageModel" should {
"be a part of vitality" in {
player.isInstanceOf[Vitality] mustEqual true
try {
player.getClass.getDeclaredMethod("DamageModel").hashCode()
} catch {
case _: Exception =>
ko //the method doesn't exist
}
wep_tool.isInstanceOf[Vitality] mustEqual false
try {
wep_tool.getClass.getDeclaredMethod("DamageModel").hashCode()
ko
} catch {
case _: Exception =>
ok //the method doesn't exist
}
ok
}
"resolve infantry targets" in {
val tplayer =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
tplayer.Spawn()
tplayer.Health mustEqual 100
tplayer.Armor mustEqual 50
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(tplayer),
tplayer.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(tplayer)
tplayer.Health mustEqual 54
tplayer.Armor mustEqual 46
}
"resolve infantry targets in a specific way" in {
val tplayer =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
tplayer.Spawn()
tplayer.Health mustEqual 100
tplayer.Armor mustEqual 50
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(tplayer),
tplayer.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile =
resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
func(tplayer)
tplayer.Health mustEqual 65
tplayer.Armor mustEqual 35
}
"resolve infantry targets, with damage overflow" in {
val tplayer =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
tplayer.Spawn()
tplayer.Health mustEqual 100
tplayer.Armor mustEqual 50
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(tplayer),
tplayer.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
tplayer.Armor = 0
func(tplayer)
tplayer.Health mustEqual 50
tplayer.Armor mustEqual 0
}
"resolve vehicle targets" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
vehicle.Health mustEqual 650
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(vehicle),
vehicle.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(vehicle)
vehicle.Health mustEqual 518
}
"resolve vehicle targets (with shields)" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
vehicle.Shields = 10
vehicle.Health mustEqual 650
vehicle.Shields mustEqual 10
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(vehicle),
vehicle.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(vehicle)
vehicle.Health mustEqual 528
vehicle.Shields mustEqual 0
}
"resolve vehicle targets (losing shields)" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
vehicle.Shields = 10
vehicle.Health mustEqual 650
vehicle.Shields mustEqual 10
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(vehicle),
vehicle.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile = resprojectile.damage_model.Calculate(resprojectile)
func(vehicle)
vehicle.Health mustEqual 528
vehicle.Shields mustEqual 0
func(vehicle)
vehicle.Health mustEqual 396
vehicle.Shields mustEqual 0
}
"resolve vehicle targets in a specific way" in {
val vehicle = Vehicle(DamageModelTests.vehicle)
vehicle.Health mustEqual 650
val resprojectile = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
SourceEntry(vehicle),
vehicle.DamageModel,
Vector3.Zero
)
val func: Any => ResolvedProjectile =
resprojectile.damage_model.Calculate(resprojectile, ProjectileResolution.Splash)
func(vehicle)
vehicle.Health mustEqual 518
}
}
}
object DamageModelTests {
final val projectile = new ProjectileDefinition(Projectiles.heavy_grenade_projectile.id) {
Damage0 = 50
Damage1 = 82
Damage2 = 82
Damage3 = 75
Damage4 = 66
DamageAtEdge = 0.1f
DamageRadius = 5f
DegradeMultiplier = 0.5f
LashRadius = 5f
ProjectileDamageType = DamageType.Splash
InitialVelocity = 75
Lifespan = 5f
ProjectileDefinition.CalculateDerivedFields(pdef = this)
Modifiers = DamageModifiers.RadialDegrade
}
final val vehicle = new VehicleDefinition(ObjectClass.fury) {
MaxHealth = 650
Damageable = true
Repairable = true
RepairIfDestroyed = false
MaxShields = 130 + 1
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
// Copyright (c) 2020 PSForever
package objects
import akka.actor.DeadLetter
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects.Default
import org.specs2.mutable.Specification
import scala.concurrent.duration._
class DefaultTest extends Specification {
"Default.Cancellable" should {
"always act like it can be cancelled successfully" in {
Default.Cancellable.cancel() mustEqual true
}
"always act like it was cancelled successfully" in {
Default.Cancellable.isCancelled mustEqual true
}
}
}
class DefaultActorStartedTest extends ActorTest {
"Default.Actor" should {
"send messages to deadLetters" in {
//after being started
Default(system)
val probe = new TestProbe(system)
system.eventStream.subscribe(probe.ref, classOf[DeadLetter])
Default.Actor ! "hello world"
val msg1 = probe.receiveOne(250 milliseconds)
assert(msg1.isInstanceOf[DeadLetter])
assert(msg1.asInstanceOf[DeadLetter].message equals "hello world")
//if it was stopped
system.stop(Default.Actor)
Default.Actor ! "hello world"
val msg2 = probe.receiveOne(250 milliseconds)
assert(msg2.isInstanceOf[DeadLetter])
assert(msg2.asInstanceOf[DeadLetter].message equals "hello world")
}
}
}
object DefaultActorTest {
//due to being a singleton, the original original value of the Default.Actor is cached here
val Original = Default.Actor
}

View file

@ -0,0 +1,817 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, Props}
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects.ballistics._
import net.psforever.objects.ce.DeployedItem
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.objects.{TurretDeployable, _}
import net.psforever.packet.game.{DeployableIcon, DeployableInfo, DeploymentAction}
import net.psforever.types._
import org.specs2.mutable.Specification
import net.psforever.services.{RemoverActor, Service}
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import net.psforever.services.support.SupportActor
import net.psforever.objects.avatar.Avatar
import scala.concurrent.duration._
class DeployableTest extends Specification {
"Deployable" should {
"know its owner by GUID" in {
val obj = new ExplosiveDeployable(GlobalDefinitions.he_mine)
obj.Owner.isEmpty mustEqual true
obj.Owner = PlanetSideGUID(10)
obj.Owner.contains(PlanetSideGUID(10)) mustEqual true
}
"know its owner by GUID" in {
val obj = new ExplosiveDeployable(GlobalDefinitions.he_mine)
obj.OwnerName.isEmpty mustEqual true
obj.OwnerName = "TestCharacter"
obj.OwnerName.contains("TestCharacter") mustEqual true
}
"know its faction allegiance" in {
val obj = new ExplosiveDeployable(GlobalDefinitions.he_mine)
obj.Faction mustEqual PlanetSideEmpire.NEUTRAL
obj.Faction = PlanetSideEmpire.TR
obj.Faction mustEqual PlanetSideEmpire.TR
}
}
}
class SensorDeployableTest extends Specification {
"SensorDeployable" should {
"construct" in {
new SensorDeployable(GlobalDefinitions.motionalarmsensor)
ok
}
}
}
class ExplosiveDeployableTest extends Specification {
"ExplosiveDeployable" should {
"construct" in {
val obj = new ExplosiveDeployable(GlobalDefinitions.he_mine)
obj.Destroyed mustEqual false
}
"explode" in {
val obj = new ExplosiveDeployable(GlobalDefinitions.he_mine)
obj.Destroyed mustEqual false
obj.Destroyed = true
obj.Destroyed mustEqual true
}
}
}
class BoomerDeployableTest extends Specification {
"BoomerDeployable" should {
"construct" in {
val obj = new BoomerDeployable(GlobalDefinitions.boomer)
obj.Destroyed mustEqual false
obj.Trigger.isEmpty mustEqual true
}
"explode" in {
val obj = new BoomerDeployable(GlobalDefinitions.boomer)
obj.Destroyed mustEqual false
obj.Destroyed = true
obj.Destroyed mustEqual true
}
"manage its trigger" in {
val obj = new BoomerDeployable(GlobalDefinitions.boomer)
obj.Trigger.isEmpty mustEqual true
val trigger = new BoomerTrigger
obj.Trigger = trigger
obj.Trigger.contains(trigger) mustEqual true
obj.Trigger = None
obj.Trigger.isEmpty mustEqual true
}
}
}
class TrapDeployableTest extends Specification {
"SensorDeployable" should {
"construct" in {
val obj = new TrapDeployable(GlobalDefinitions.tank_traps)
obj.Health mustEqual GlobalDefinitions.tank_traps.MaxHealth
}
"update health values" in {
val obj = new TrapDeployable(GlobalDefinitions.tank_traps)
obj.Health mustEqual GlobalDefinitions.tank_traps.MaxHealth
obj.Health = 0
obj.Health mustEqual 0
}
}
}
class TurretDeployableTest extends Specification {
"TurretDeployable" should {
"define (valid turret objects)" in {
List(
DeployedItem.spitfire_turret.id,
DeployedItem.spitfire_cloaked.id,
DeployedItem.spitfire_aa.id,
DeployedItem.portable_manned_turret.id,
DeployedItem.portable_manned_turret_tr.id,
DeployedItem.portable_manned_turret_nc.id,
DeployedItem.portable_manned_turret_vs.id
).foreach(id => {
try { new TurretDeployableDefinition(id) }
catch { case _: Exception => ko }
})
ok
}
"define (invalid object)" in {
new TurretDeployableDefinition(5) must throwA[NoSuchElementException] //wrong object id altogether
}
"construct" in {
val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret)
obj.Health mustEqual obj.MaxHealth
}
"update health values" in {
val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret)
obj.Health mustEqual GlobalDefinitions.spitfire_turret.MaxHealth
obj.Health = 0
obj.Health mustEqual 0
}
"may have mount point" in {
new TurretDeployable(GlobalDefinitions.spitfire_turret).MountPoints mustEqual Map()
new TurretDeployable(GlobalDefinitions.portable_manned_turret_vs).MountPoints mustEqual Map(1 -> 0, 2 -> 0)
}
}
}
class DeployableMake extends Specification {
"Deployables.Make" should {
"construct a boomer" in {
val func = Deployables.Make(DeployedItem.boomer)
func() match {
case _: BoomerDeployable => ok
case _ => ko
}
}
"construct an he mine" in {
val func = Deployables.Make(DeployedItem.he_mine)
func() match {
case obj: ExplosiveDeployable if obj.Definition == GlobalDefinitions.he_mine => ok
case _ => ko
}
}
"construct a disruptor mine" in {
val func = Deployables.Make(DeployedItem.jammer_mine)
func() match {
case obj: ExplosiveDeployable if obj.Definition == GlobalDefinitions.jammer_mine => ok
case _ => ko
}
}
"construct a spitfire turret" in {
val func = Deployables.Make(DeployedItem.spitfire_turret)
func() match {
case obj: TurretDeployable if obj.Definition == GlobalDefinitions.spitfire_turret => ok
case _ => ko
}
}
"construct a shadow turret" in {
val func = Deployables.Make(DeployedItem.spitfire_cloaked)
func() match {
case obj: TurretDeployable if obj.Definition == GlobalDefinitions.spitfire_cloaked => ok
case _ => ko
}
}
"construct a cerebus turret" in {
val func = Deployables.Make(DeployedItem.spitfire_aa)
func() match {
case obj: TurretDeployable if obj.Definition == GlobalDefinitions.spitfire_aa => ok
case _ => ko
}
}
"construct a motion sensor" in {
val func = Deployables.Make(DeployedItem.motionalarmsensor)
func() match {
case obj: SensorDeployable if obj.Definition == GlobalDefinitions.motionalarmsensor => ok
case _ => ko
}
}
"construct a sensor disruptor" in {
val func = Deployables.Make(DeployedItem.sensor_shield)
func() match {
case obj: SensorDeployable if obj.Definition == GlobalDefinitions.sensor_shield => ok
case _ => ko
}
}
"construct three metal i-beams so huge that a driver must be blind to drive into them but does anyway" in {
val func = Deployables.Make(DeployedItem.tank_traps)
func() match {
case obj: TrapDeployable if obj.Definition == GlobalDefinitions.tank_traps => ok
case _ => ko
}
}
"construct a generic field turret" in {
val func = Deployables.Make(DeployedItem.portable_manned_turret)
func() match {
case obj: TurretDeployable if obj.Definition == GlobalDefinitions.portable_manned_turret => ok
case _ => ko
}
}
"construct an avenger turret" in {
val func = Deployables.Make(DeployedItem.portable_manned_turret_tr)
func() match {
case obj: TurretDeployable if obj.Definition == GlobalDefinitions.portable_manned_turret_tr => ok
case _ => ko
}
}
"construct an aegis shield generator" in {
val func = Deployables.Make(DeployedItem.deployable_shield_generator)
func() match {
case obj: ShieldGeneratorDeployable if obj.Definition == GlobalDefinitions.deployable_shield_generator => ok
case _ => ko
}
}
"construct a telepad" in {
val func = Deployables.Make(DeployedItem.router_telepad_deployable)
func() match {
case obj: TelepadDeployable if obj.Definition == GlobalDefinitions.router_telepad_deployable => ok
case _ => ko
}
}
"construct an osprey turret" in {
val func = Deployables.Make(DeployedItem.portable_manned_turret_nc)
func() match {
case obj: TurretDeployable if obj.Definition == GlobalDefinitions.portable_manned_turret_nc => ok
case _ => ko
}
}
"construct an orion turret" in {
val func = Deployables.Make(DeployedItem.portable_manned_turret_vs)
func() match {
case obj: TurretDeployable if obj.Definition == GlobalDefinitions.portable_manned_turret_vs => ok
case _ => ko
}
}
}
}
class ShieldGeneratorDeployableTest extends Specification {
"ShieldGeneratorDeployable" should {
"construct" in {
val obj = new ShieldGeneratorDeployable(GlobalDefinitions.deployable_shield_generator)
obj.Health mustEqual obj.MaxHealth
}
"update health values" in {
val obj = new ShieldGeneratorDeployable(GlobalDefinitions.deployable_shield_generator)
obj.Health mustEqual GlobalDefinitions.deployable_shield_generator.MaxHealth
obj.Health = 0
obj.Health mustEqual 0
}
}
}
class ExplosiveDeployableJammerTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val localProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
zone.LocalEvents = localProbe.ref
val j_mine = Deployables.Make(DeployedItem.jammer_mine)().asInstanceOf[ExplosiveDeployable] //guid=1
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=4
player2.Spawn()
val weapon = Tool(GlobalDefinitions.jammer_grenade) //guid=5
guid.register(j_mine, 1)
guid.register(player1, 3)
guid.register(player2, 4)
guid.register(weapon, 5)
j_mine.Zone = zone
j_mine.Owner = player2
j_mine.OwnerName = player2.Name
j_mine.Faction = PlanetSideEmpire.NC
j_mine.Actor = system.actorOf(Props(classOf[ExplosiveDeployableControl], j_mine), "j-mine-control")
val jMineSource = SourceEntry(j_mine)
val pSource = PlayerSource(player1)
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
jMineSource,
j_mine.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageToJ = resolved.damage_model.Calculate(resolved)
"ExplosiveDeployable" should {
"handle being jammered appropriately (no detonation)" in {
assert(!j_mine.Destroyed)
j_mine.Actor ! Vitality.Damage(applyDamageToJ)
val msg_local = localProbe.receiveN(4, 200 milliseconds)
val msg_avatar = avatarProbe.receiveOne(200 milliseconds)
activityProbe.expectNoMessage(200 milliseconds)
assert(
msg_local.head match {
case LocalServiceMessage("TestCharacter2", LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) =>
target eq j_mine
case _ => false
}
)
assert(
msg_local(1) match {
case LocalServiceMessage(
"NC",
LocalAction.DeployableMapIcon(
PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(1), DeployableIcon.DisruptorMine, _, PlanetSideGUID(0))
)
) =>
true
case _ => false
}
)
assert(
msg_local(2) match {
case LocalServiceMessage.Deployables(SupportActor.ClearSpecific(List(target), _zone)) =>
(target eq j_mine) && (_zone eq zone)
case _ => false
}
)
assert(
msg_local(3) match {
case LocalServiceMessage.Deployables(RemoverActor.AddTask(target, _zone, _)) =>
(target eq j_mine) && (_zone eq zone)
case _ => false
}
)
assert(
msg_avatar match {
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(1), _, Service.defaultPlayerGUID, _)) =>
true
case _ => false
}
)
assert(j_mine.Destroyed)
}
}
}
class ExplosiveDeployableJammerExplodeTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val localProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
zone.LocalEvents = localProbe.ref
val h_mine = Deployables.Make(DeployedItem.he_mine)().asInstanceOf[ExplosiveDeployable] //guid=2
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=4
player2.Spawn()
val weapon = Tool(GlobalDefinitions.jammer_grenade) //guid=5
guid.register(h_mine, 2)
guid.register(player1, 3)
guid.register(player2, 4)
guid.register(weapon, 5)
h_mine.Zone = zone
h_mine.Owner = player2
h_mine.OwnerName = player2.Name
h_mine.Faction = PlanetSideEmpire.NC
h_mine.Actor = system.actorOf(Props(classOf[ExplosiveDeployableControl], h_mine), "h-mine-control")
val hMineSource = SourceEntry(h_mine)
val pSource = PlayerSource(player1)
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
hMineSource,
h_mine.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageToH = resolved.damage_model.Calculate(resolved)
"ExplosiveDeployable" should {
"handle being jammered appropriately (detonation)" in {
assert(!h_mine.Destroyed)
h_mine.Actor ! Vitality.Damage(applyDamageToH)
val msg_local = localProbe.receiveN(5, 200 milliseconds)
val msg_avatar = avatarProbe.receiveOne(200 milliseconds)
val msg_activity = activityProbe.receiveOne(200 milliseconds)
assert(
msg_local.head match {
case LocalServiceMessage("test", LocalAction.Detonate(PlanetSideGUID(2), target)) => target eq h_mine
case _ => false
}
)
assert(
msg_local(1) match {
case LocalServiceMessage("TestCharacter2", LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) =>
target eq h_mine
case _ => false
}
)
assert(
msg_local(2) match {
case LocalServiceMessage(
"NC",
LocalAction.DeployableMapIcon(
PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(2), DeployableIcon.HEMine, _, PlanetSideGUID(0))
)
) =>
true
case _ => false
}
)
assert(
msg_local(3) match {
case LocalServiceMessage.Deployables(SupportActor.ClearSpecific(List(target), _zone)) =>
(target eq h_mine) && (_zone eq zone)
case _ => false
}
)
assert(
msg_local(4) match {
case LocalServiceMessage.Deployables(RemoverActor.AddTask(target, _zone, _)) =>
(target eq h_mine) && (_zone eq zone)
case _ => false
}
)
assert(
msg_avatar match {
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, Service.defaultPlayerGUID, _)) =>
true
case _ => false
}
)
assert(
msg_activity match {
case Zone.HotSpot.Activity(target, attacker, _) => (target eq hMineSource) && (attacker eq pSource)
case _ => false
}
)
assert(h_mine.Destroyed)
}
}
}
class ExplosiveDeployableDestructionTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val localProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
zone.LocalEvents = localProbe.ref
val h_mine = Deployables.Make(DeployedItem.he_mine)().asInstanceOf[ExplosiveDeployable] //guid=2
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=4
player2.Spawn()
val weapon = Tool(GlobalDefinitions.suppressor) //guid=5
guid.register(h_mine, 2)
guid.register(player1, 3)
guid.register(player2, 4)
guid.register(weapon, 5)
h_mine.Zone = zone
h_mine.Owner = player2
h_mine.OwnerName = player2.Name
h_mine.Faction = PlanetSideEmpire.NC
h_mine.Actor = system.actorOf(Props(classOf[ExplosiveDeployableControl], h_mine), "h-mine-control")
val hMineSource = SourceEntry(h_mine)
val pSource = PlayerSource(player1)
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(projectile, weapon.Definition, weapon.FireMode, pSource, 0, Vector3.Zero, Vector3.Zero),
hMineSource,
h_mine.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
"ExplosiveDeployable" should {
"handle being destroyed" in {
h_mine.Health = h_mine.Definition.DamageDestroysAt + 1
assert(h_mine.Health > h_mine.Definition.DamageDestroysAt)
assert(!h_mine.Destroyed)
h_mine.Actor ! Vitality.Damage(applyDamageTo)
val msg_local = localProbe.receiveN(5, 200 milliseconds)
val msg_avatar = avatarProbe.receiveOne(200 milliseconds)
activityProbe.expectNoMessage(200 milliseconds)
assert(
msg_local.head match {
case LocalServiceMessage("TestCharacter2", LocalAction.AlertDestroyDeployable(PlanetSideGUID(0), target)) =>
target eq h_mine
case _ => false
}
)
assert(
msg_local(1) match {
case LocalServiceMessage(
"NC",
LocalAction.DeployableMapIcon(
PlanetSideGUID(0),
DeploymentAction.Dismiss,
DeployableInfo(PlanetSideGUID(2), DeployableIcon.HEMine, _, PlanetSideGUID(0))
)
) =>
true
case _ => false
}
)
assert(
msg_local(2) match {
case LocalServiceMessage.Deployables(SupportActor.ClearSpecific(List(target), _zone)) =>
(target eq h_mine) && (_zone eq zone)
case _ => false
}
)
assert(
msg_local(3) match {
case LocalServiceMessage.Deployables(RemoverActor.AddTask(target, _zone, _)) =>
(target eq h_mine) && (_zone eq zone)
case _ => false
}
)
assert(
msg_local(4) match {
case LocalServiceMessage("test", LocalAction.TriggerEffect(_, "detonate_damaged_mine", PlanetSideGUID(2))) =>
true
case _ => false
}
)
assert(
msg_avatar match {
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, Service.defaultPlayerGUID, _)) =>
true
case _ => false
}
)
assert(h_mine.Health <= h_mine.Definition.DamageDestroysAt)
assert(h_mine.Destroyed)
}
}
}
class TurretControlConstructTest extends ActorTest {
"TurretControl" should {
"construct" in {
val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret)
system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test")
}
}
}
class TurretControlInitializeTest extends ActorTest {
"TurretControl" should {
"initialize" in {
val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret)
obj.GUID = PlanetSideGUID(1)
assert(obj.Actor == Default.Actor)
val init = system.actorOf(Props(classOf[DeployableTest.TurretInitializer], obj), "init_turret_test")
init ! "initialize"
expectNoMessage(200 milliseconds)
assert(obj.Actor != Default.Actor)
}
}
}
class TurretControlUninitializeTest extends ActorTest {
"TurretControl" should {
"uninitialize" in {
val obj = new TurretDeployable(GlobalDefinitions.spitfire_turret)
val init = system.actorOf(Props(classOf[DeployableTest.TurretInitializer], obj), "init_turret_test")
obj.GUID = PlanetSideGUID(1)
init ! "initialize"
expectNoMessage(200 milliseconds)
assert(obj.Actor != Default.Actor)
init ! "uninitialize"
expectNoMessage(200 milliseconds)
assert(obj.Actor == Default.Actor)
}
}
}
class TurretControlMountTest extends ActorTest {
"TurretControl" should {
"control mounting" in {
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).Occupant.isEmpty)
val player1 = Player(Avatar(0, "test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
obj.Actor ! Mountable.TryMount(player1, 0)
val reply1a = receiveOne(200 milliseconds)
assert(reply1a.isInstanceOf[Mountable.MountMessages])
val reply1b = reply1a.asInstanceOf[Mountable.MountMessages]
assert(reply1b.player == player1)
assert(reply1b.response.isInstanceOf[Mountable.CanMount])
assert(obj.Seats(0).Occupant.contains(player1))
}
}
}
class TurretControlBlockMountTest extends ActorTest {
"TurretControl" should {
"block mounting by others if already mounted by someone" in {
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).Occupant.isEmpty)
val player1 = Player(Avatar(0, "test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
obj.Actor ! Mountable.TryMount(player1, 0)
val reply1a = receiveOne(200 milliseconds)
assert(reply1a.isInstanceOf[Mountable.MountMessages])
val reply1b = reply1a.asInstanceOf[Mountable.MountMessages]
assert(reply1b.player == player1)
assert(reply1b.response.isInstanceOf[Mountable.CanMount])
assert(obj.Seats(0).Occupant.contains(player1))
val player2 = Player(Avatar(1, "test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
obj.Actor ! Mountable.TryMount(player2, 0)
val reply2a = receiveOne(200 milliseconds)
assert(reply2a.isInstanceOf[Mountable.MountMessages])
val reply2b = reply2a.asInstanceOf[Mountable.MountMessages]
assert(reply2b.player == player2)
assert(reply2b.response.isInstanceOf[Mountable.CanNotMount])
}
}
}
class TurretControlBlockBetrayalMountTest extends ActorTest {
"TurretControl" should {
"block mounting by players of another faction" in {
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).Occupant.isEmpty)
val player = Player(Avatar(0, "test", PlanetSideEmpire.VS, CharacterGender.Male, 0, CharacterVoice.Mute))
obj.Actor ! Mountable.TryMount(player, 0)
val reply1a = receiveOne(200 milliseconds)
assert(reply1a.isInstanceOf[Mountable.MountMessages])
val reply1b = reply1a.asInstanceOf[Mountable.MountMessages]
assert(reply1b.player == player)
assert(reply1b.response.isInstanceOf[Mountable.CanNotMount])
assert(obj.Seats(0).Occupant.isEmpty)
}
}
}
class TurretControlDismountTest extends ActorTest {
"TurretControl" should {
"control dismounting" in {
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_tr) { GUID = PlanetSideGUID(1) }
obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).Occupant.isEmpty)
val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
obj.Actor ! Mountable.TryMount(player, 0)
val reply1a = receiveOne(200 milliseconds)
assert(reply1a.isInstanceOf[Mountable.MountMessages])
val reply1b = reply1a.asInstanceOf[Mountable.MountMessages]
assert(reply1b.player == player)
assert(reply1b.response.isInstanceOf[Mountable.CanMount])
assert(obj.Seats(0).Occupant.contains(player))
obj.Actor ! Mountable.TryDismount(player, 0)
val reply2a = receiveOne(200 milliseconds)
assert(reply2a.isInstanceOf[Mountable.MountMessages])
val reply2b = reply2a.asInstanceOf[Mountable.MountMessages]
assert(reply2b.player == player)
assert(reply2b.response.isInstanceOf[Mountable.CanDismount])
assert(obj.Seats(0).Occupant.isEmpty)
}
}
}
class TurretControlBetrayalMountTest extends ActorTest {
"TurretControl" should {
"allow all allegiances" in {
val obj = new TurretDeployable(
new TurretDeployableDefinition(685) { FactionLocked = false } //required (defaults to true)
) { GUID = PlanetSideGUID(1) }
obj.Faction = PlanetSideEmpire.TR
obj.Actor = system.actorOf(Props(classOf[TurretControl], obj), s"${obj.Definition.Name}_test")
assert(obj.Seats(0).Occupant.isEmpty)
val player = Player(Avatar(0, "test", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Mute))
assert(player.Faction != obj.Faction)
obj.Actor ! Mountable.TryMount(player, 0)
val reply1a = receiveOne(200 milliseconds)
assert(reply1a.isInstanceOf[Mountable.MountMessages])
val reply1b = reply1a.asInstanceOf[Mountable.MountMessages]
assert(reply1b.player == player)
assert(reply1b.response.isInstanceOf[Mountable.CanMount])
assert(obj.Seats(0).Occupant.contains(player))
}
}
}
class TelepadDeployableTest extends Specification {
"Telepad" should {
"construct" in {
val obj = new Telepad(GlobalDefinitions.router_telepad)
obj.Active mustEqual false
obj.Router.isEmpty mustEqual true
}
"activate and deactivate" in {
val obj = new Telepad(GlobalDefinitions.router_telepad)
obj.Active mustEqual false
obj.Active = true
obj.Active mustEqual true
obj.Active = false
obj.Active mustEqual false
}
"keep track of a Router" in {
val obj = new Telepad(GlobalDefinitions.router_telepad)
obj.Router.isEmpty mustEqual true
obj.Router = PlanetSideGUID(1)
obj.Router.contains(PlanetSideGUID(1)) mustEqual true
obj.Router = None
obj.Router.isEmpty mustEqual true
obj.Router = PlanetSideGUID(1)
obj.Router.contains(PlanetSideGUID(1)) mustEqual true
obj.Router = PlanetSideGUID(0)
obj.Router.isEmpty mustEqual true
}
}
}
object DeployableTest {
class TurretInitializer(obj: TurretDeployable) extends Actor {
def receive: Receive = {
case "initialize" =>
obj.Definition.Initialize(obj, context)
case "uninitialize" =>
obj.Definition.Uninitialize(obj, context)
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,268 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.{GlobalDefinitions, Vehicle}
import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.types.{DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3}
import org.specs2.mutable.Specification
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.concurrent.duration.Duration
class DeploymentTest extends Specification {
"Deployment" should {
"construct" in {
val obj = new DeploymentTest.DeploymentObject()
obj.DeploymentState mustEqual DriveState.Mobile
obj.DeployTime mustEqual 0
obj.UndeployTime mustEqual 0
}
"change deployment state" in {
val obj = new DeploymentTest.DeploymentObject()
obj.DeploymentState mustEqual DriveState.Mobile
obj.DeploymentState = DriveState.Deployed
obj.DeploymentState mustEqual DriveState.Deployed
obj.DeploymentState = DriveState.Deploying
obj.DeploymentState mustEqual DriveState.Deploying
obj.DeploymentState = DriveState.Undeploying
obj.DeploymentState mustEqual DriveState.Undeploying
obj.DeploymentState = DriveState.State7
obj.DeploymentState mustEqual DriveState.State7
}
"have custom deployment time by object" in {
val ams = Vehicle(GlobalDefinitions.ams)
(ams.DeployTime == 0) mustEqual false //not default
(ams.UndeployTime == 0) mustEqual false //not default
}
}
}
class DeploymentBehavior1Test extends ActorTest {
"Deployment" should {
"construct" in {
val obj = DeploymentTest.SetUpAgent
assert(obj.Actor != ActorRef.noSender)
assert(obj.DeploymentState == DriveState.Mobile)
}
}
}
class DeploymentBehavior2Test extends ActorTest {
"Deployment" should {
"change following a deployment cycle using TryDeploymentChange" in {
val obj = DeploymentTest.SetUpAgent
val probe = new TestProbe(system)
val eventsProbe = new TestProbe(system)
obj.Zone.VehicleEvents = eventsProbe.ref
assert(obj.DeploymentState == DriveState.Mobile)
//to Deploying
obj.Actor.tell(Deployment.TryDeploymentChange(DriveState.Deploying), probe.ref)
val reply1a = probe.receiveOne(Duration.create(500, "ms"))
assert(reply1a match {
case Deployment.CanDeploy(_, DriveState.Deploying) => true
case _ => false
})
val reply1b = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply1b match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
//to Deployed
val reply2 = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply2 match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
assert(obj.DeploymentState == DriveState.Deployed)
//to Undeploying
obj.Actor.tell(Deployment.TryDeploymentChange(DriveState.Undeploying), probe.ref)
val reply3a = probe.receiveOne(Duration.create(500, "ms"))
assert(reply3a match {
case Deployment.CanUndeploy(_, DriveState.Undeploying) => true
case _ => false
})
val reply3b = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply3b match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
//to Mobile
val reply4 = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply4 match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
assert(obj.DeploymentState == DriveState.Mobile)
}
}
}
class DeploymentBehavior3Test extends ActorTest {
"Deployment" should {
"change following a deployment cycle using TryDeploy and TryUndeploy" in {
val obj = DeploymentTest.SetUpAgent
val probe = new TestProbe(system)
val eventsProbe = new TestProbe(system)
obj.Zone.VehicleEvents = eventsProbe.ref
assert(obj.DeploymentState == DriveState.Mobile)
//to Deploying
obj.Actor.tell(Deployment.TryDeploy(DriveState.Deploying), probe.ref)
val reply1a = probe.receiveOne(Duration.create(500, "ms"))
assert(reply1a match {
case Deployment.CanDeploy(_, DriveState.Deploying) => true
case _ => false
})
val reply1b = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply1b match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deploying, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
//to Deployed
val reply2 = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply2 match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Deployed, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
assert(obj.DeploymentState == DriveState.Deployed)
//to Undeploying
obj.Actor.tell(Deployment.TryUndeploy(DriveState.Undeploying), probe.ref)
val reply3a = probe.receiveOne(Duration.create(500, "ms"))
assert(reply3a match {
case Deployment.CanUndeploy(_, DriveState.Undeploying) => true
case _ => false
})
val reply3b = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply3b match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Undeploying, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
//to Mobile
val reply4 = eventsProbe.receiveOne(Duration.create(500, "ms"))
assert(reply4 match {
case VehicleServiceMessage(
"test",
VehicleAction.DeployRequest(_, PlanetSideGUID(1), DriveState.Mobile, 0, false, Vector3.Zero)
) =>
true
case _ => false
})
assert(obj.DeploymentState == DriveState.Mobile)
}
}
}
class DeploymentBehavior4Test extends ActorTest {
"Deployment" should {
"not deploy to an out of order state" in {
val obj = DeploymentTest.SetUpAgent
assert(obj.DeploymentState == DriveState.Mobile)
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deployed)
val reply1 = receiveOne(Duration.create(100, "ms"))
assert(reply1.isInstanceOf[Deployment.CanNotChangeDeployment])
assert(reply1.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
assert(reply1.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Deployed)
assert(obj.DeploymentState == DriveState.Mobile)
obj.Actor ! Deployment.TryDeploy(DriveState.Deployed)
val reply2 = receiveOne(Duration.create(100, "ms"))
assert(reply2.isInstanceOf[Deployment.CanNotChangeDeployment])
assert(reply2.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
assert(reply2.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Deployed)
assert(obj.DeploymentState == DriveState.Mobile)
}
}
}
class DeploymentBehavior5Test extends ActorTest {
"Deployment" should {
"not deploy to an undeploy state" in {
val obj = DeploymentTest.SetUpAgent
assert(obj.DeploymentState == DriveState.Mobile)
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deploying)
receiveOne(Duration.create(100, "ms")) //consume
obj.Actor ! Deployment.TryDeploymentChange(DriveState.Deployed)
receiveOne(Duration.create(100, "ms")) //consume
assert(obj.DeploymentState == DriveState.Deployed)
obj.Actor ! Deployment.TryDeploy(DriveState.Undeploying)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Deployment.CanNotChangeDeployment])
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Undeploying)
assert(obj.DeploymentState == DriveState.Deployed)
}
}
}
class DeploymentBehavior6Test extends ActorTest {
"Deployment" should {
"not undeploy to a deploy state" in {
val obj = DeploymentTest.SetUpAgent
assert(obj.DeploymentState == DriveState.Mobile)
obj.Actor ! Deployment.TryUndeploy(DriveState.Deploying)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Deployment.CanNotChangeDeployment])
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].obj == obj)
assert(reply.asInstanceOf[Deployment.CanNotChangeDeployment].to_state == DriveState.Deploying)
assert(obj.DeploymentState == DriveState.Mobile)
}
}
}
object DeploymentTest {
class DeploymentObject extends PlanetSideServerObject with Deployment {
def Faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
def Definition = null
}
private class DeploymentControl(obj: Deployment.DeploymentObject) extends Actor with DeploymentBehavior {
override def DeploymentObject = obj
def receive = deployBehavior.orElse { case _ => }
}
def SetUpAgent(implicit system: ActorSystem) = {
val obj = new DeploymentObject()
obj.GUID = PlanetSideGUID(1)
obj.Zone = Zone("test", new ZoneMap("test"), 1)
obj.Actor = system.actorOf(Props(classOf[DeploymentControl], obj), "test")
obj
}
}

View file

@ -0,0 +1,140 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorSystem, Props}
import base.ActorTest
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.{Default, GlobalDefinitions, Player}
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.UseItemMessage
import net.psforever.types._
import org.specs2.mutable.Specification
import scala.concurrent.duration.Duration
class DoorTest extends Specification {
val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
"Door" should {
"construct" in {
Door(GlobalDefinitions.door)
ok
}
"starts as closed (false)" in {
val door = Door(GlobalDefinitions.door)
door.Open mustEqual None
door.isOpen mustEqual false
}
"be opened and closed (1; manual)" in {
val door = Door(GlobalDefinitions.door)
door.isOpen mustEqual false
door.Open mustEqual None
door.Open = Some(player)
door.isOpen mustEqual true
door.Open mustEqual Some(player)
door.Open = None
door.isOpen mustEqual false
door.Open mustEqual None
}
"be opened and closed (2; toggle)" in {
val msg = UseItemMessage(
PlanetSideGUID(6585),
PlanetSideGUID(0),
PlanetSideGUID(372),
4294967295L,
false,
Vector3(5.0f, 0.0f, 0.0f),
Vector3(0.0f, 0.0f, 0.0f),
11,
25,
0,
364
)
val door = Door(GlobalDefinitions.door)
door.Open mustEqual None
door.Use(player, msg)
door.Open mustEqual Some(player)
door.Use(player, msg)
door.Open mustEqual None
}
}
}
class DoorControl1Test extends ActorTest {
"DoorControl" should {
"construct" in {
val door = Door(GlobalDefinitions.door)
door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door")
assert(door.Actor != Default.Actor)
}
}
}
class DoorControl2Test extends ActorTest {
"DoorControl" should {
"open on use" in {
val (player, door) = DoorControlTest.SetUpAgents(PlanetSideEmpire.TR)
val msg = UseItemMessage(
PlanetSideGUID(1),
PlanetSideGUID(0),
PlanetSideGUID(2),
0L,
false,
Vector3(0f, 0f, 0f),
Vector3(0f, 0f, 0f),
0,
0,
0,
0L
) //faked
assert(door.Open.isEmpty)
door.Actor ! Door.Use(player, msg)
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Door.DoorMessage])
val reply2 = reply.asInstanceOf[Door.DoorMessage]
assert(reply2.player == player)
assert(reply2.msg == msg)
assert(reply2.response == Door.OpenEvent())
assert(door.Open.isDefined)
}
}
}
class DoorControl3Test extends ActorTest {
"DoorControl" should {
"do nothing if given garbage" in {
val (_, door) = DoorControlTest.SetUpAgents(PlanetSideEmpire.TR)
assert(door.Open.isEmpty)
door.Actor ! "trash"
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Door.NoEvent])
assert(door.Open.isEmpty)
}
}
}
object DoorControlTest {
def SetUpAgents(faction: PlanetSideEmpire.Value)(implicit system: ActorSystem): (Player, Door) = {
val door = Door(GlobalDefinitions.door)
door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door")
door.Owner = new Building(
"Building",
building_guid = 0,
map_id = 0,
Zone.Nowhere,
StructureType.Building,
GlobalDefinitions.building
)
door.Owner.Faction = faction
(Player(Avatar(0, "test", faction, CharacterGender.Male, 0, CharacterVoice.Mute)), door)
}
}

View file

@ -0,0 +1,288 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.entity.{AssigningGUIDException, NoGUIDException}
import net.psforever.types.{PlanetSideGUID, StalePlanetSideGUID, ValidPlanetSideGUID, Vector3}
import org.specs2.mutable._
class EntityTest extends Specification {
//both WorldEntity and IdentifiableEntity are components of PlanetSideGameObject
private class EntityTestClass extends PlanetSideGameObject {
def Definition: ObjectDefinition = new ObjectDefinition(0) {}
}
"PlanetSideGUID" should {
"construct as valid" in {
ValidPlanetSideGUID(1).isInstanceOf[PlanetSideGUID] mustEqual true
}
"construct as stale" in {
StalePlanetSideGUID(1).isInstanceOf[PlanetSideGUID] mustEqual true
}
"apply construct (as valid)" in {
val guid = PlanetSideGUID(1)
guid.isInstanceOf[PlanetSideGUID] mustEqual true
guid.isInstanceOf[ValidPlanetSideGUID] mustEqual true
guid.isInstanceOf[StalePlanetSideGUID] mustEqual false
}
"valid and stale are equal by guid" in {
//your linter will complain; let it
ValidPlanetSideGUID(1) == StalePlanetSideGUID(1) mustEqual true
ValidPlanetSideGUID(1) == StalePlanetSideGUID(2) mustEqual false
}
"valid and stale are pattern-matchable" in {
val guid1: PlanetSideGUID = ValidPlanetSideGUID(1)
val guid2: PlanetSideGUID = StalePlanetSideGUID(1)
def getGuid(o: PlanetSideGUID): PlanetSideGUID = o //distancing the proper type
getGuid(guid1) match {
case ValidPlanetSideGUID(1) => ok
case _ => ko
}
getGuid(guid2) match {
case StalePlanetSideGUID(1) => ok
case _ => ko
}
}
}
"SimpleWorldEntity" should {
"construct" in {
new EntityTestClass()
ok
}
"initialize" in {
val obj: EntityTestClass = new EntityTestClass()
obj.Position mustEqual Vector3(0f, 0f, 0f)
obj.Orientation mustEqual Vector3(0f, 0f, 0f)
obj.Velocity.isEmpty mustEqual true
}
"mutate and access" in {
val obj: EntityTestClass = new EntityTestClass
obj.Position = Vector3(1f, 1f, 1f)
obj.Orientation = Vector3(2f, 2f, 2f)
obj.Velocity = Vector3(3f, 3f, 3f)
obj.Position mustEqual Vector3(1f, 1f, 1f)
obj.Orientation mustEqual Vector3(2f, 2f, 2f)
obj.Velocity.contains(Vector3(3f, 3f, 3f)) mustEqual true
}
"clamp Orientation" in {
val obj: EntityTestClass = new EntityTestClass
obj.Orientation = Vector3(-1f, 361f, -0f)
obj.Orientation mustEqual Vector3(359f, 1f, 0f)
}
"is moving (at all)" in {
val obj: EntityTestClass = new EntityTestClass
obj.Velocity.isEmpty mustEqual true
obj.isMoving mustEqual false
obj.Velocity = Vector3.Zero
obj.isMoving mustEqual false
obj.Velocity = Vector3(1, 0, 0)
obj.isMoving mustEqual true
obj.Velocity = None
obj.isMoving mustEqual false
}
"is moving (Vector3 comparison)" in {
val obj: EntityTestClass = new EntityTestClass
val test1 = Vector3(1, 0, 0)
val test2 = Vector3(2, 0, 0)
obj.Velocity.isEmpty mustEqual true
obj.isMoving mustEqual false
obj.isMoving(test1) mustEqual false
obj.isMoving(test2) mustEqual false
obj.Velocity = Vector3(1, 0, 0)
obj.isMoving(test1) mustEqual true
obj.isMoving(test2) mustEqual false
obj.Velocity = Vector3(3, 0, 0)
obj.isMoving(test1) mustEqual true
obj.isMoving(test2) mustEqual true
obj.Velocity = Vector3(1, 1, 0)
obj.isMoving(test1) mustEqual true
obj.isMoving(test2) mustEqual false
}
"is moving (Float comparison)" in {
val obj: EntityTestClass = new EntityTestClass
obj.Velocity.isEmpty mustEqual true
obj.isMoving mustEqual false
obj.isMoving(1) mustEqual false
obj.isMoving(2) mustEqual false
obj.isMoving(4) mustEqual false
obj.Velocity = Vector3(1, 0, 0)
obj.isMoving(1) mustEqual true
obj.isMoving(2) mustEqual false
obj.isMoving(4) mustEqual false
obj.Velocity = Vector3(3, 0, 0)
obj.isMoving(1) mustEqual true
obj.isMoving(2) mustEqual true
obj.isMoving(4) mustEqual true
obj.Velocity = Vector3(1, 1, 1)
obj.isMoving(1) mustEqual true
obj.isMoving(2) mustEqual true
obj.isMoving(4) mustEqual false
}
}
"IdentifiableEntity" should {
"construct" in {
new EntityTestClass()
ok
}
"error while not set" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID must throwA[NoGUIDException]
}
"error if set to an invalid GUID before being set to a valid GUID" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID must throwA[NoGUIDException]
try {
obj.GUID = StalePlanetSideGUID(1)
ko
} catch {
case AssigningGUIDException(_, _, _, _: StalePlanetSideGUID) => ok
case _: Throwable => ko
}
}
"work after valid mutation" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
}
"raise complaint about subsequent mutations using a valid GUID" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
try {
obj.GUID = ValidPlanetSideGUID(1)
ko
} catch {
case AssigningGUIDException(_, _, _, ValidPlanetSideGUID(1)) => ok
case _: Throwable => ko
}
}
"ignore subsequent mutations using an invalid GUID" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
try {
obj.GUID = StalePlanetSideGUID(1)
ko
} catch {
case AssigningGUIDException(_, _, _, _: StalePlanetSideGUID) => ok
case _: Throwable => ko
}
}
"invalidate does nothing by default" in {
val obj: EntityTestClass = new EntityTestClass
obj.Invalidate()
obj.GUID must throwA[NoGUIDException]
}
"invalidate changes the nature of the previous valid mutation" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[ValidPlanetSideGUID] mustEqual true
obj.Invalidate()
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[StalePlanetSideGUID] mustEqual true
}
"setting an invalid GUID after invalidating the previous valid mutation still raises complaint" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[ValidPlanetSideGUID] mustEqual true
obj.Invalidate()
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[StalePlanetSideGUID] mustEqual true
(obj.GUID = StalePlanetSideGUID(2)) must throwA[AssigningGUIDException]
obj.GUID mustEqual PlanetSideGUID(1051)
}
"setting a valid GUID after invalidating correctly sets the new valid GUID" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[ValidPlanetSideGUID] mustEqual true
obj.Invalidate()
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[StalePlanetSideGUID] mustEqual true
obj.GUID = PlanetSideGUID(2)
obj.GUID mustEqual PlanetSideGUID(2)
obj.GUID.isInstanceOf[ValidPlanetSideGUID] mustEqual true
}
"setting the same valid GUID after invalidating correctly resets the valid GUID" in {
val obj: EntityTestClass = new EntityTestClass
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[ValidPlanetSideGUID] mustEqual true
obj.Invalidate()
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[StalePlanetSideGUID] mustEqual true
obj.GUID = PlanetSideGUID(1051)
obj.GUID mustEqual PlanetSideGUID(1051)
obj.GUID.isInstanceOf[ValidPlanetSideGUID] mustEqual true
}
"report not having a GUID when not set" in {
val obj: EntityTestClass = new EntityTestClass
obj.HasGUID mustEqual false
}
"report having a GUID when a valid GUID is set" in {
val obj: EntityTestClass = new EntityTestClass
obj.HasGUID mustEqual false
obj.GUID = PlanetSideGUID(1051)
obj.HasGUID mustEqual true
}
"report not having a GUID after invalidating (staleness)" in {
val obj: EntityTestClass = new EntityTestClass
obj.HasGUID mustEqual false
obj.GUID = PlanetSideGUID(1051)
obj.HasGUID mustEqual true
obj.Invalidate()
obj.HasGUID mustEqual false
//remember that we will still return a GUID in this case
obj.GUID mustEqual PlanetSideGUID(1051)
}
"report having a GUID after setting a valid GUID, after invalidating" in {
val obj: EntityTestClass = new EntityTestClass
obj.HasGUID mustEqual false
obj.GUID = PlanetSideGUID(1051)
obj.HasGUID mustEqual true
obj.Invalidate()
obj.HasGUID mustEqual false
obj.GUID = PlanetSideGUID(2)
obj.HasGUID mustEqual true
}
}
"hachCode test" in {
ValidPlanetSideGUID(1051).hashCode mustEqual ValidPlanetSideGUID(1051).hashCode
ValidPlanetSideGUID(1051).hashCode mustEqual StalePlanetSideGUID(1051).hashCode
}
}

View file

@ -0,0 +1,148 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.{OffhandEquipmentSlot, Tool}
import net.psforever.objects.equipment.{EquipmentSize, EquipmentSlot}
import net.psforever.objects.GlobalDefinitions.{beamer, repeater, suppressor}
import org.specs2.mutable._
class EquipmentSlotTest extends Specification {
"EquipmentSlot" should {
"construct" in {
val obj = new EquipmentSlot()
obj.Size mustEqual EquipmentSize.Blocked
obj.Equipment mustEqual None
}
"construct with a default size" in {
val obj = EquipmentSlot(EquipmentSize.Pistol)
obj.Size mustEqual EquipmentSize.Pistol
}
"change size" in {
val obj = new EquipmentSlot()
obj.Size mustEqual EquipmentSize.Blocked
obj.Size = EquipmentSize.Pistol
obj.Size mustEqual EquipmentSize.Pistol
}
"hold equipment" in {
val obj = new EquipmentSlot()
val equipment = Tool(beamer)
obj.Equipment = None
beamer.Size mustEqual EquipmentSize.Pistol
obj.Size = EquipmentSize.Pistol
obj.Equipment = equipment
obj.Equipment match {
case Some(item) =>
item.Definition mustEqual beamer
case None =>
ko
}
}
"put down previously held equipment" in {
val obj = EquipmentSlot(EquipmentSize.Pistol)
obj.Equipment = Tool(beamer)
obj.Equipment match {
case Some(item) =>
item.Definition mustEqual beamer
case None =>
ko
}
obj.Equipment = None
obj.Equipment match {
case Some(_) =>
ko
case None =>
ok
}
}
"not change size when holding equipment" in {
val obj = new EquipmentSlot()
obj.Size mustEqual EquipmentSize.Blocked
obj.Size = EquipmentSize.Pistol
obj.Equipment = Tool(beamer)
obj.Equipment match {
case Some(_) => ;
case None => ko
}
obj.Size mustEqual EquipmentSize.Pistol
obj.Size = EquipmentSize.Rifle
obj.Size mustEqual EquipmentSize.Pistol
}
"not hold wrong-sized equipment" in {
val obj = new EquipmentSlot()
val equipment = Tool(suppressor)
obj.Equipment = None
beamer.Size mustEqual EquipmentSize.Pistol
obj.Size = EquipmentSize.Pistol
obj.Equipment = equipment
obj.Equipment mustEqual None
}
"not switch to holding a second item in place of a first one" in {
val obj = EquipmentSlot(EquipmentSize.Pistol)
obj.Equipment = Tool(beamer)
obj.Equipment match {
case Some(item) =>
item.Definition mustEqual beamer
case None =>
ko
}
repeater.Size mustEqual EquipmentSize.Pistol
obj.Equipment = Tool(repeater) //also a pistol
obj.Equipment match {
case Some(item) =>
item.Definition mustEqual beamer
case None =>
ko
}
}
}
"OffhandEquipmentSLot" should {
"construct" in {
val obj = new OffhandEquipmentSlot(EquipmentSize.Pistol)
obj.Size mustEqual EquipmentSize.Pistol
obj.Equipment mustEqual None
}
"hold equipment" in {
val obj = new OffhandEquipmentSlot(EquipmentSize.Pistol)
val equipment = Tool(beamer)
obj.Equipment = None
beamer.Size mustEqual EquipmentSize.Pistol
obj.Equipment = equipment
obj.Equipment match {
case Some(item) =>
item.Definition mustEqual beamer
case None =>
ko
}
}
"not change size after being constructed" in {
//see above test "EquipmentSlot should/not change size when holding equipment"
val obj = new OffhandEquipmentSlot(EquipmentSize.Pistol)
obj.Equipment mustEqual None
obj.Size mustEqual EquipmentSize.Pistol
obj.Size = EquipmentSize.Rifle
obj.Size mustEqual EquipmentSize.Pistol
}
"special Blocked size default" in {
OffhandEquipmentSlot.BlockedSlot.Size mustEqual EquipmentSize.Blocked
OffhandEquipmentSlot.BlockedSlot.Equipment mustEqual None
}
}
}

View file

@ -0,0 +1,440 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects._
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.GlobalDefinitions._
import net.psforever.objects.avatar.Certification
import net.psforever.objects.ce.DeployedItem
import net.psforever.objects.definition._
import net.psforever.types.PlanetSideGUID
import org.specs2.mutable._
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 {
"define" in {
val obj = AmmoBoxDefinition(86)
obj.Capacity = 300
obj.Tile = InventoryTile.Tile44
obj.AmmoType mustEqual Ammo.aphelion_immolation_cannon_ammo
obj.Capacity mustEqual 300
obj.Tile.Width mustEqual InventoryTile.Tile44.Width
obj.Tile.Height mustEqual InventoryTile.Tile44.Height
obj.ObjectId mustEqual 86
}
"construct" in {
val obj = AmmoBox(bullet_9mm)
obj.AmmoType mustEqual Ammo.bullet_9mm
obj.Capacity mustEqual 50
}
"construct (2)" in {
val obj = AmmoBox(bullet_9mm, 150)
obj.AmmoType mustEqual Ammo.bullet_9mm
obj.Capacity mustEqual 150
}
"vary capacity" in {
val obj = AmmoBox(bullet_9mm, 0)
obj.Capacity mustEqual 1 //can not be initialized to 0
obj.Capacity = 75
obj.Capacity mustEqual 75
}
"limit capacity" in {
val obj = AmmoBox(bullet_9mm)
obj.Capacity mustEqual 50
obj.Capacity = -1
obj.Capacity mustEqual 0
obj.Capacity = 65536
obj.Capacity mustEqual 65535
}
"split (0)" in {
val obj = AmmoBox(bullet_9mm)
obj.Capacity = 0
val list = AmmoBox.Split(obj)
list.size mustEqual 0
}
"split (1)" in {
val obj = AmmoBox(bullet_9mm)
obj.Capacity = 50
val list = AmmoBox.Split(obj)
list.size mustEqual 1
list.head.Capacity mustEqual 50
}
"split (2)" in {
val obj = AmmoBox(bullet_9mm)
obj.Capacity = 75
val list = AmmoBox.Split(obj)
list.size mustEqual 2
list.head.Capacity mustEqual 50
list(1).Capacity mustEqual 25
}
"split (4)" in {
val obj = AmmoBox(bullet_9mm)
obj.Capacity = 165
val list = AmmoBox.Split(obj)
list.size mustEqual 4
list.head.Capacity mustEqual 50
list(1).Capacity mustEqual 50
list(2).Capacity mustEqual 50
list(3).Capacity mustEqual 15
}
}
"Tool" should {
"define" in {
val obj = ToolDefinition(1076)
obj.Name = "sample_weapon"
obj.Size = EquipmentSize.Rifle
obj.AmmoTypes += GlobalDefinitions.shotgun_shell
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
obj.FireModes += new FireModeDefinition
obj.FireModes.head.AmmoTypeIndices += 0
obj.FireModes.head.AmmoTypeIndices += 1
obj.FireModes.head.AmmoSlotIndex = 0
obj.FireModes.head.Magazine = 18
obj.FireModes += new FireModeDefinition
obj.FireModes(1).AmmoTypeIndices += 0
obj.FireModes(1).AmmoTypeIndices += 1
obj.FireModes(1).AmmoSlotIndex = 1
obj.FireModes(1).Chamber = 3
obj.FireModes(1).Magazine = 18
obj.Tile = InventoryTile.Tile93
obj.ObjectId mustEqual 1076
obj.Name mustEqual "sample_weapon"
obj.AmmoTypes.head mustEqual GlobalDefinitions.shotgun_shell
obj.AmmoTypes(1) mustEqual GlobalDefinitions.shotgun_shell_AP
obj.FireModes.head.AmmoTypeIndices.head mustEqual 0
obj.FireModes.head.AmmoTypeIndices(1) mustEqual 1
obj.FireModes.head.AmmoSlotIndex mustEqual 0
obj.FireModes.head.Chamber mustEqual 1
obj.FireModes.head.Magazine mustEqual 18
obj.FireModes(1).AmmoTypeIndices.head mustEqual 0
obj.FireModes(1).AmmoTypeIndices(1) mustEqual 1
obj.FireModes(1).AmmoSlotIndex mustEqual 1
obj.FireModes(1).Chamber mustEqual 3
obj.FireModes(1).Magazine mustEqual 18
obj.Tile.Width mustEqual InventoryTile.Tile93.Width
obj.Tile.Height mustEqual InventoryTile.Tile93.Height
}
"construct" in {
val obj: Tool = Tool(fury_weapon_systema)
obj.Definition.ObjectId mustEqual fury_weapon_systema.ObjectId
}
"fire mode" in {
//explanation: fury_weapon_systema has one fire mode and that fire mode is our only option
val obj: Tool = Tool(fury_weapon_systema)
obj.Magazine = obj.MaxMagazine
obj.Magazine mustEqual obj.Definition.FireModes.head.Magazine
//fmode = 0
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 2
obj.AmmoType mustEqual Ammo.hellfire_ammo
//fmode -> 1 (0)
obj.FireModeIndex = 1
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 2
obj.AmmoType mustEqual Ammo.hellfire_ammo
}
"default fire mode (dual magazine feed)" in {
val obj = ToolDefinition(1076)
obj.AmmoTypes += GlobalDefinitions.shotgun_shell
obj.AmmoTypes += GlobalDefinitions.shotgun_shell_AP
obj.ProjectileTypes += GlobalDefinitions.shotgun_shell_projectile
obj.ProjectileTypes += GlobalDefinitions.shotgun_shell_AP_projectile
obj.FireModes += new FireModeDefinition
obj.FireModes.head.AmmoTypeIndices += 0
obj.FireModes.head.AmmoSlotIndex = 0
obj.FireModes += new FireModeDefinition
obj.FireModes(1).AmmoTypeIndices += 1
obj.FireModes(1).AmmoSlotIndex = 1
val tool0 = Tool(obj)
tool0.FireModeIndex mustEqual 0
tool0.ProjectileType mustEqual GlobalDefinitions.shotgun_shell_projectile.ProjectileType
obj.DefaultFireModeIndex = 1
val tool1 = Tool(obj)
tool1.FireModeIndex mustEqual 1
tool1.ProjectileType mustEqual GlobalDefinitions.shotgun_shell_AP_projectile.ProjectileType
}
"multiple fire modes" in {
//explanation: sample_weapon has two fire modes; each fire mode has a different ammunition type
val obj: Tool = Tool(punisher)
//fmode = 0
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 30
obj.AmmoType mustEqual Ammo.bullet_9mm
//fmode -> 1
obj.NextFireMode
obj.FireModeIndex mustEqual 1
obj.FireMode.Magazine mustEqual 1
obj.AmmoType mustEqual Ammo.rocket
//fmode -> 0
obj.NextFireMode
obj.FireModeIndex mustEqual 0
obj.FireMode.Magazine mustEqual 30
obj.AmmoType mustEqual Ammo.bullet_9mm
}
"multiple types of ammunition" in {
//explanation: obj has one fire mode and two ammunitions; adjusting the AmmoType changes between them
val obj: Tool = Tool(flechette)
//ammo = 0
obj.AmmoTypeIndex mustEqual 0
obj.AmmoType mustEqual Ammo.shotgun_shell
//ammo -> 1
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 1
obj.AmmoType mustEqual Ammo.shotgun_shell_AP
//ammo -> 2 (0)
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 0
obj.AmmoType mustEqual Ammo.shotgun_shell
}
"multiple ammo types and multiple fire modes, split (Punisher)" in {
val obj = Tool(GlobalDefinitions.punisher)
//ammo = 0, fmode = 0
obj.FireModeIndex mustEqual 0
obj.AmmoTypeIndex mustEqual 0
obj.AmmoType mustEqual Ammo.bullet_9mm
//ammo = 2, fmode = 1
obj.NextFireMode
obj.FireModeIndex mustEqual 1
obj.AmmoTypeIndex mustEqual 2
obj.AmmoType mustEqual Ammo.rocket
//ammo = 3, fmode = 1
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 3
obj.AmmoType mustEqual Ammo.frag_cartridge
//ammo = 4, fmode = 1
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 4
obj.AmmoType mustEqual Ammo.jammer_cartridge
//ammo = 0, fmode = 0
obj.NextFireMode
obj.FireModeIndex mustEqual 0
obj.AmmoTypeIndex mustEqual 0
obj.AmmoType mustEqual Ammo.bullet_9mm
//ammo = 1, fmode = 0
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 1
obj.AmmoType mustEqual Ammo.bullet_9mm_AP
//ammo = 5, fmode = 1
obj.NextFireMode
obj.NextAmmoType
obj.FireModeIndex mustEqual 1
obj.AmmoTypeIndex mustEqual 5
obj.AmmoType mustEqual Ammo.plasma_cartridge
//ammo = 2, fmode = 1
obj.NextAmmoType
obj.AmmoTypeIndex mustEqual 2
obj.AmmoType mustEqual Ammo.rocket
}
"projectile types and ammo types" in {
val suppressor_wep = Tool(suppressor)
suppressor_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
suppressor_wep.NextAmmoType
suppressor_wep.ProjectileType mustEqual bullet_9mm_AP_projectile.ProjectileType
suppressor_wep.NextAmmoType
suppressor_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
}
"projectile types and fire modes" in {
val pulsar_wep = Tool(pulsar)
pulsar_wep.ProjectileType mustEqual pulsar_projectile.ProjectileType
pulsar_wep.NextFireMode
pulsar_wep.ProjectileType mustEqual pulsar_ap_projectile.ProjectileType
pulsar_wep.NextFireMode
pulsar_wep.ProjectileType mustEqual pulsar_projectile.ProjectileType
}
"projectile types and fire modes / ammo types" in {
val punisher_wep = Tool(punisher)
punisher_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
punisher_wep.NextAmmoType
punisher_wep.ProjectileType mustEqual bullet_9mm_AP_projectile.ProjectileType
punisher_wep.NextFireMode
punisher_wep.ProjectileType mustEqual rocket_projectile.ProjectileType
punisher_wep.NextAmmoType
punisher_wep.ProjectileType mustEqual frag_cartridge_projectile.ProjectileType
punisher_wep.NextAmmoType
punisher_wep.ProjectileType mustEqual jammer_cartridge_projectile.ProjectileType
punisher_wep.NextFireMode
punisher_wep.ProjectileType mustEqual bullet_9mm_AP_projectile.ProjectileType
punisher_wep.NextAmmoType
punisher_wep.ProjectileType mustEqual bullet_9mm_projectile.ProjectileType
punisher_wep.NextFireMode
punisher_wep.ProjectileType mustEqual jammer_cartridge_projectile.ProjectileType
punisher_wep.NextAmmoType
punisher_wep.ProjectileType mustEqual plasma_cartridge_projectile.ProjectileType
punisher_wep.NextAmmoType
punisher_wep.ProjectileType mustEqual rocket_projectile.ProjectileType
}
"discharge (1)" in {
val obj = Tool(GlobalDefinitions.punisher)
obj.Magazine mustEqual 30
obj.Discharge()
obj.Magazine mustEqual 29
obj.Discharge()
obj.Discharge()
obj.Magazine mustEqual 27
}
"chamber" in {
val obj = Tool(GlobalDefinitions.flechette)
obj.Magazine mustEqual 12
obj.AmmoSlot.Chamber mustEqual 8
obj.Discharge()
obj.Magazine mustEqual 12
obj.AmmoSlot.Chamber mustEqual 7
obj.Discharge()
obj.Discharge()
obj.Magazine mustEqual 12
obj.AmmoSlot.Chamber mustEqual 5
obj.Discharge()
obj.Discharge()
obj.Discharge()
obj.Discharge()
obj.Magazine mustEqual 12
obj.AmmoSlot.Chamber mustEqual 1
obj.Discharge()
obj.Magazine mustEqual 11
obj.AmmoSlot.Chamber mustEqual 8
}
}
"Kit" should {
"define" in {
val sample = KitDefinition(Kits.medkit)
sample.ObjectId mustEqual medkit.ObjectId
sample.Tile.Width mustEqual medkit.Tile.Width
sample.Tile.Height mustEqual medkit.Tile.Height
}
"construct" in {
val obj: Kit = Kit(medkit)
obj.Definition.ObjectId mustEqual medkit.ObjectId
}
}
"ConstructionItem" should {
"construct" in {
val obj: ConstructionItem = ConstructionItem(GlobalDefinitions.ace)
obj.Definition.ObjectId mustEqual GlobalDefinitions.ace.ObjectId
}
"fire modes" in {
val obj: ConstructionItem = ConstructionItem(GlobalDefinitions.ace)
obj.AmmoType mustEqual DeployedItem.boomer
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.he_mine
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.spitfire_turret
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.motionalarmsensor
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.boomer
}
"ammo types" in {
val obj: ConstructionItem = ConstructionItem(GlobalDefinitions.ace)
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.he_mine
obj.NextAmmoType
obj.AmmoType mustEqual DeployedItem.jammer_mine
obj.NextAmmoType
obj.AmmoType mustEqual DeployedItem.he_mine
}
"when switching fire modes, ammo mode resets to the first entry" in {
val obj: ConstructionItem = ConstructionItem(GlobalDefinitions.ace)
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.he_mine
obj.NextAmmoType
obj.AmmoType mustEqual DeployedItem.jammer_mine
obj.NextFireMode //spitfire_turret
obj.NextFireMode //motionalarmsensor
obj.NextFireMode //boomer
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.he_mine
}
"qualify certifications that must be met before ammo types may be used" in {
val obj: ConstructionItem = ConstructionItem(GlobalDefinitions.ace)
obj.AmmoType mustEqual DeployedItem.boomer
obj.ModePermissions mustEqual Set(Certification.CombatEngineering)
obj.NextFireMode
obj.AmmoType mustEqual DeployedItem.he_mine
obj.ModePermissions mustEqual Set(Certification.CombatEngineering)
obj.NextAmmoType
obj.AmmoType mustEqual DeployedItem.jammer_mine
obj.ModePermissions mustEqual Set(Certification.AssaultEngineering)
}
}
"SimpleItem" should {
"define" in {
val sample = SimpleItemDefinition(SItem.remote_electronics_kit)
sample.ObjectId mustEqual remote_electronics_kit.ObjectId
}
"construct" in {
val obj: SimpleItem = SimpleItem(remote_electronics_kit)
obj.Definition.ObjectId mustEqual remote_electronics_kit.ObjectId
}
}
"BoomerTrigger" should {
"construct" in {
val obj: BoomerTrigger = new BoomerTrigger
obj.Definition.ObjectId mustEqual boomer_trigger.ObjectId
obj.Companion mustEqual None
}
"boomer trigger has a companion object referenced by GUID" in {
val obj: BoomerTrigger = new BoomerTrigger
obj.Companion mustEqual None
obj.Companion = PlanetSideGUID(1)
obj.Companion.contains(PlanetSideGUID(1)) mustEqual true
obj.Companion = None
obj.Companion mustEqual None
}
}
}

View file

@ -0,0 +1,210 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.definition.{ExoSuitDefinition, SpecialExoSuitDefinition}
import net.psforever.objects.equipment._
import net.psforever.objects.inventory.InventoryTile
import net.psforever.types.{ExoSuitType, PlanetSideEmpire}
import org.specs2.mutable._
class ExoSuitTest extends Specification {
"ExoSuitDefinition" should {
"construct" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.MaxArmor mustEqual 0
obj.InventoryScale mustEqual InventoryTile.Tile11
obj.InventoryOffset mustEqual 0
obj.SuitType mustEqual ExoSuitType.Standard
obj.Holsters.length mustEqual 5
obj.Holsters.foreach(slot => { if (slot != EquipmentSize.Blocked) { ko } })
ok
}
"produce the type of exo-suit that was provided as a clarified type" in {
ExoSuitDefinition(ExoSuitType.Standard).SuitType mustEqual ExoSuitType.Standard
ExoSuitDefinition(ExoSuitType.Agile).SuitType mustEqual ExoSuitType.Agile
}
"change the maximum armor value" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.MaxArmor mustEqual 0
obj.MaxArmor = 1
obj.MaxArmor mustEqual 1
}
"not change the maximum armor to an invalid value" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.MaxArmor mustEqual 0
obj.MaxArmor = -1
obj.MaxArmor mustEqual 0
obj.MaxArmor = 65536
obj.MaxArmor mustEqual 65535
}
"change the size of the inventory" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.InventoryScale mustEqual InventoryTile.Tile11
obj.InventoryScale = InventoryTile.Tile42
obj.InventoryScale mustEqual InventoryTile.Tile42
}
"change the start index of the inventory" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.InventoryOffset mustEqual 0
obj.InventoryOffset = 1
obj.InventoryOffset mustEqual 1
}
"not change the start index of the inventory to an invalid value" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.InventoryOffset mustEqual 0
obj.InventoryOffset = -1
obj.InventoryOffset mustEqual 0
obj.InventoryOffset = 65536
obj.InventoryOffset mustEqual 65535
}
"change specific holsters to specific values" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.Holster(0) mustEqual EquipmentSize.Blocked
obj.Holster(0, EquipmentSize.Pistol)
obj.Holster(0) mustEqual EquipmentSize.Pistol
obj.Holster(4) mustEqual EquipmentSize.Blocked
obj.Holster(4, EquipmentSize.Rifle)
obj.Holster(4) mustEqual EquipmentSize.Rifle
(0 to 4).foreach {
case 0 => obj.Holsters(0) mustEqual EquipmentSize.Pistol
case 4 => obj.Holsters(4) mustEqual EquipmentSize.Rifle
case x => obj.Holsters(x) mustEqual EquipmentSize.Blocked
}
ok
}
"can not change any slot that does not exist" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
obj.Holster(9) mustEqual EquipmentSize.Blocked
obj.Holster(9, EquipmentSize.Pistol)
obj.Holster(9) mustEqual EquipmentSize.Blocked
}
"produce a copy of the definition" in {
val obj = ExoSuitDefinition(ExoSuitType.Standard)
val obj2 = obj.Use
obj eq obj2
}
}
"SpecialExoSuitDefinition" should {
"construct" in {
val obj = SpecialExoSuitDefinition(ExoSuitType.Standard)
obj.MaxArmor mustEqual 0
obj.InventoryScale mustEqual InventoryTile.Tile11
obj.InventoryOffset mustEqual 0
obj.SuitType mustEqual ExoSuitType.Standard
obj.Holsters.length mustEqual 5
obj.Holsters.foreach(slot => { if (slot != EquipmentSize.Blocked) { ko } })
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
}
"configure UsingSpecial to various values" in {
val obj = SpecialExoSuitDefinition(ExoSuitType.Standard)
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Anchored
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Overdrive
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Overdrive
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Shielded
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Shielded
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
}
"produce a separate copy of the definition" in {
val obj = SpecialExoSuitDefinition(ExoSuitType.Standard)
val obj2 = obj.Use
obj ne obj2
}
}
"ExoSuitDefinition.Select" should {
"produce common, shared instances of exo suits" in {
ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Standard,
PlanetSideEmpire.VS
)
ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Agile,
PlanetSideEmpire.VS
)
ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Reinforced,
PlanetSideEmpire.VS
)
ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Infiltration,
PlanetSideEmpire.VS
)
}
"produce common, shared instances of exo suits across factions" in {
ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Standard,
PlanetSideEmpire.TR
)
ExoSuitDefinition.Select(ExoSuitType.Standard, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Standard,
PlanetSideEmpire.NC
)
ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Agile,
PlanetSideEmpire.TR
)
ExoSuitDefinition.Select(ExoSuitType.Agile, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Agile,
PlanetSideEmpire.NC
)
ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Reinforced,
PlanetSideEmpire.TR
)
ExoSuitDefinition.Select(ExoSuitType.Reinforced, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Reinforced,
PlanetSideEmpire.NC
)
ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Infiltration,
PlanetSideEmpire.TR
)
ExoSuitDefinition.Select(ExoSuitType.Infiltration, PlanetSideEmpire.VS) eq ExoSuitDefinition.Select(
ExoSuitType.Infiltration,
PlanetSideEmpire.NC
)
}
"can select max for TR" in {
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.TR)
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
obj.MaxCapacitor mustEqual 300
}
"can select max for VS" in {
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.VS)
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
obj.MaxCapacitor mustEqual 50
}
"can select max for NC" in {
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.NC)
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
obj.MaxCapacitor mustEqual 400
}
"produces unique instances of the mechanized assault exo suit" in {
val obj = ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.VS)
obj ne ExoSuitDefinition.Select(ExoSuitType.MAX, PlanetSideEmpire.VS)
obj.isInstanceOf[SpecialExoSuitDefinition] mustEqual true
}
}
}

View file

@ -0,0 +1,287 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.Props
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.{Default, GlobalDefinitions, Player, Tool}
import net.psforever.objects.definition.ToolDefinition
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.turret._
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.{InventoryStateMessage, RepairMessage}
import net.psforever.types._
import org.specs2.mutable.Specification
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.collection.mutable
import scala.concurrent.duration._
class FacilityTurretTest extends Specification {
"FacilityTurretTest" should {
"define" in {
val obj = new FacilityTurretDefinition(480)
obj.Weapons mustEqual mutable.HashMap.empty[TurretUpgrade.Value, ToolDefinition]
obj.ReserveAmmunition mustEqual false
obj.FactionLocked mustEqual true
obj.MaxHealth mustEqual 0
obj.MountPoints mustEqual mutable.HashMap.empty[Int, Int]
}
"construct" in {
val obj = FacilityTurret(GlobalDefinitions.manned_turret)
obj.Weapons.size mustEqual 1
obj.Weapons(1).Equipment match {
case Some(tool: Tool) =>
tool.Definition mustEqual GlobalDefinitions.phalanx_sgl_hevgatcan
case _ =>
ko
}
obj.Seats.size mustEqual 1
obj.Seats(0).ControlledWeapon.contains(1) mustEqual true
obj.MountPoints.size mustEqual 1
obj.MountPoints(1) mustEqual 0
obj.Health mustEqual 3600
obj.Upgrade mustEqual TurretUpgrade.None
obj.Health = 360
obj.Health mustEqual 360
}
"upgrade to a different weapon" in {
val obj = FacilityTurret(GlobalDefinitions.manned_turret)
obj.Upgrade = TurretUpgrade.None
obj.Weapons(1).Equipment match {
case Some(tool: Tool) =>
tool.Definition mustEqual GlobalDefinitions.phalanx_sgl_hevgatcan
tool.FireModeIndex mustEqual 0
tool.NextFireMode
tool.FireModeIndex mustEqual 0 //one fire mode
case _ =>
ko
}
//upgrade
obj.Upgrade = TurretUpgrade.AVCombo
obj.Weapons(1).Equipment match {
case Some(tool: Tool) =>
tool.Definition mustEqual GlobalDefinitions.phalanx_avcombo
tool.FireModeIndex mustEqual 0
tool.ProjectileType mustEqual GlobalDefinitions.phalanx_projectile.ProjectileType
tool.NextFireMode
tool.FireModeIndex mustEqual 1
tool.ProjectileType mustEqual GlobalDefinitions.phalanx_av_projectile.ProjectileType
case _ =>
ko
}
//revert
obj.Upgrade = TurretUpgrade.None
obj.Weapons(1).Equipment match {
case Some(tool: Tool) =>
tool.Definition mustEqual GlobalDefinitions.phalanx_sgl_hevgatcan
case _ =>
ko
}
}
}
}
class FacilityTurretControl1Test extends ActorTest {
"FacilityTurretControl" should {
"construct" in {
val obj = FacilityTurret(GlobalDefinitions.manned_turret)
obj.Actor = system.actorOf(Props(classOf[FacilityTurretControl], obj), "turret-control")
assert(obj.Actor != Default.Actor)
}
}
}
class FacilityTurretControl2Test extends ActorTest {
val player = Player(Avatar(0, "", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj = FacilityTurret(GlobalDefinitions.manned_turret)
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[FacilityTurretControl], obj), "turret-control")
val bldg = Building("Building", guid = 0, map_id = 0, Zone.Nowhere, StructureType.Building)
bldg.Amenities = obj
bldg.Faction = PlanetSideEmpire.TR
"FacilityTurretControl" should {
"seat on faction affiliation when FactionLock is true" in {
assert(player.Faction == PlanetSideEmpire.TR)
assert(obj.Faction == PlanetSideEmpire.TR)
assert(obj.Definition.FactionLocked)
obj.Actor ! Mountable.TryMount(player, 0)
val reply = receiveOne(300 milliseconds)
reply match {
case msg: Mountable.MountMessages =>
assert(msg.response.isInstanceOf[Mountable.CanMount])
case _ =>
assert(false)
}
}
}
}
class FacilityTurretControl3Test extends ActorTest {
val player = Player(Avatar(0, "", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj = FacilityTurret(GlobalDefinitions.manned_turret)
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[FacilityTurretControl], obj), "turret-control")
val bldg = Building("Building", guid = 0, map_id = 0, Zone.Nowhere, StructureType.Building)
bldg.Amenities = obj
"FacilityTurretControl" should {
"block seating on mismatched faction affiliation when FactionLock is true" in {
assert(player.Faction == PlanetSideEmpire.TR)
assert(obj.Faction == PlanetSideEmpire.NEUTRAL)
assert(obj.Definition.FactionLocked)
obj.Actor ! Mountable.TryMount(player, 0)
val reply = receiveOne(300 milliseconds)
reply match {
case msg: Mountable.MountMessages =>
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
case _ =>
assert(false)
}
}
}
}
class FacilityTurretControl4Test extends ActorTest {
val player = Player(Avatar(0, "", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val objDef = new FacilityTurretDefinition(480)
objDef.FactionLocked = false
val obj = FacilityTurret(objDef)
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[FacilityTurretControl], obj), "turret-control")
val bldg = Building("Building", guid = 0, map_id = 0, Zone.Nowhere, StructureType.Building)
bldg.Amenities = obj
"FacilityTurretControl" should {
"seating even with mismatched faction affiliation when FactionLock is false" in {
assert(player.Faction == PlanetSideEmpire.TR)
assert(obj.Faction == PlanetSideEmpire.NEUTRAL)
assert(!obj.Definition.FactionLocked)
obj.Actor ! Mountable.TryMount(player, 0)
val reply = receiveOne(300 milliseconds)
reply match {
case msg: Mountable.MountMessages =>
assert(msg.response.isInstanceOf[Mountable.CanMount])
case _ =>
assert(false)
}
}
}
}
class FacilityTurretControlRestorationTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val vehicleProbe = TestProbe()
val buildingProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
zone.VehicleEvents = vehicleProbe.ref
building.Actor = buildingProbe.ref
val turret = new FacilityTurret(GlobalDefinitions.manned_turret) //2, 5, 6
turret.Actor = system.actorOf(Props(classOf[FacilityTurretControl], turret), "turret-control")
turret.Zone = zone
turret.Position = Vector3(1, 0, 0)
val turretWeapon = turret.Weapons.values.head.Equipment.get.asInstanceOf[Tool]
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
player1.Position = Vector3(2, 2, 2)
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
guid.register(building, 1)
guid.register(turret, 2)
guid.register(player1, 3)
guid.register(turretWeapon, 5)
guid.register(turretWeapon.AmmoSlot.Box, 6)
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = turret
val tool = Tool(GlobalDefinitions.nano_dispenser) //7 & 8
guid.register(tool, 7)
guid.register(tool.AmmoSlot.Box, 8)
"RepairableTurretWeapon" should {
"handle repairs and restoration" in {
turret.Health = turret.Definition.RepairRestoresAt - 1 //initial state manip
turret.Destroyed = true //initial state manip
assert(turret.Health < turret.Definition.RepairRestoresAt)
assert(turret.Destroyed)
turret.Actor ! CommonMessages.Use(player1, Some(tool))
val msg12345 = avatarProbe.receiveN(5, 500 milliseconds)
val msg4 = vehicleProbe.receiveOne(500 milliseconds)
assert(
msg12345.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction
.SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(8), _, PlanetSideGUID(7), _))
) =>
true
case _ => false
}
)
assert(
msg12345(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg12345(2) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 50, 0)) => true
case _ => false
}
)
assert(
msg12345(3) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 51, 0)) => true
case _ => false
}
)
assert(
msg12345(4) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
) =>
true
case _ => false
}
)
assert(
msg4 match {
case VehicleServiceMessage("test", VehicleAction.EquipmentInSlot(_, PlanetSideGUID(2), 1, t))
if t eq turretWeapon =>
true
case _ => false
}
)
assert(turret.Health > turret.Definition.RepairRestoresAt)
assert(!turret.Destroyed)
}
}
}

View file

@ -0,0 +1,141 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, ActorSystem, Props}
import base.ActorTest
import net.psforever.objects.{GlobalDefinitions, Vehicle}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable.Specification
import scala.concurrent.duration.Duration
class FactionAffinityTest extends Specification {
"FactionAffinity" should {
"construct (basic)" in {
val obj = new FactionAffinity { def Faction = PlanetSideEmpire.TR }
obj.Faction mustEqual PlanetSideEmpire.TR
}
"construct (part of)" in {
val obj = new Door(GlobalDefinitions.door)
obj.Faction mustEqual PlanetSideEmpire.NEUTRAL
}
"can not change affinity directly (basic)" in {
val obj = new FactionAffinity { def Faction = PlanetSideEmpire.TR }
(obj.Faction = PlanetSideEmpire.NC) mustEqual PlanetSideEmpire.TR
}
"can not change affinity directly (part of)" in {
val obj = new Door(GlobalDefinitions.door)
(obj.Faction = PlanetSideEmpire.TR) mustEqual PlanetSideEmpire.NEUTRAL
}
"inherits affinity from owner 1" in {
val obj = new Door(GlobalDefinitions.door)
obj.Owner.Faction mustEqual PlanetSideEmpire.NEUTRAL
(obj.Faction = PlanetSideEmpire.TR) mustEqual PlanetSideEmpire.NEUTRAL
}
"inherits affinity from owner 2" in {
val obj = new Door(GlobalDefinitions.door)
val bldg = new Building(
"Building",
building_guid = 0,
map_id = 1,
Zone.Nowhere,
StructureType.Building,
GlobalDefinitions.building
)
obj.Owner = bldg
obj.Faction mustEqual PlanetSideEmpire.NEUTRAL
bldg.Faction = PlanetSideEmpire.TR
obj.Faction mustEqual PlanetSideEmpire.TR
bldg.Faction = PlanetSideEmpire.NC
obj.Faction mustEqual PlanetSideEmpire.NC
}
}
}
class FactionAffinity1Test extends ActorTest {
"FactionAffinity" should {
"assert affinity on confirm request" in {
val obj = FactionAffinityTest.SetUpAgent
obj.Faction = PlanetSideEmpire.VS //object is a type that can be changed directly
assert(obj.Faction == PlanetSideEmpire.VS)
obj.Actor ! FactionAffinity.ConfirmFactionAffinity()
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == obj)
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.VS)
}
}
}
class FactionAffinity2Test extends ActorTest {
"FactionAffinity" should {
"assert affinity on assert request" in {
val obj = FactionAffinityTest.SetUpAgent
obj.Faction = PlanetSideEmpire.VS //object is a type that can be changed directly
assert(obj.Faction == PlanetSideEmpire.VS)
obj.Actor ! FactionAffinity.AssertFactionAffinity(obj, PlanetSideEmpire.NEUTRAL)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == obj)
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.VS)
}
}
}
class FactionAffinity3Test extends ActorTest {
"FactionAffinity" should {
"convert and assert affinity on convert request" in {
val obj = FactionAffinityTest.SetUpAgent
obj.Faction = PlanetSideEmpire.VS //object is a type that can be changed directly
assert(obj.Faction == PlanetSideEmpire.VS)
obj.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.TR)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[FactionAffinity.AssertFactionAffinity])
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].obj == obj)
assert(reply.asInstanceOf[FactionAffinity.AssertFactionAffinity].faction == PlanetSideEmpire.TR)
assert(obj.Faction == PlanetSideEmpire.TR)
}
}
}
object FactionAffinityTest {
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
private class AffinityControl(obj: FactionAffinity)
extends Actor
with FactionAffinityBehavior.Check
with FactionAffinityBehavior.Convert {
override def FactionObject = obj
def receive = checkBehavior.orElse(convertBehavior).orElse { case _ => }
}
def SetUpAgent(implicit system: ActorSystem) = {
val obj = new Vehicle(GlobalDefinitions.quadstealth)
obj.Actor = system.actorOf(Props(classOf[FactionAffinityTest.AffinityControl], obj), "test")
obj
}
def FreeFactionObject: FactionAffinity =
new FactionAffinity() {
private var faction: PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
def Faction: PlanetSideEmpire.Value = faction
override def Faction_=(fac: PlanetSideEmpire.Value): PlanetSideEmpire.Value = {
faction = fac
faction
}
}
}

View file

@ -0,0 +1,132 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.definition.ToolDefinition
import net.psforever.objects.{GlobalDefinitions, Tool}
import net.psforever.objects.equipment.{
EquipmentSize,
FireModeDefinition,
InfiniteFireModeDefinition,
PelletFireModeDefinition
}
import org.specs2.mutable._
class FireModeTest extends Specification {
"FireModeDefinition" should {
"construct" in {
val obj = new FireModeDefinition
obj.AmmoTypeIndices mustEqual Nil
obj.AmmoSlotIndex mustEqual 0
obj.Magazine mustEqual 1
obj.RoundsPerShot mustEqual 1
obj.Chamber mustEqual 1
}
"test configurations" in {
val tdef = ToolDefinition(1076) //fake object id
tdef.Size = EquipmentSize.Rifle
tdef.AmmoTypes += GlobalDefinitions.bullet_9mm
tdef.AmmoTypes += GlobalDefinitions.shotgun_shell
tdef.FireModes += new FireModeDefinition
tdef.FireModes.head.AmmoTypeIndices += 0
tdef.FireModes.head.AmmoSlotIndex = 0
tdef.FireModes.head.Magazine = 18
tdef.FireModes.head.RoundsPerShot = 18
tdef.FireModes.head.Chamber = 2
tdef.FireModes += new FireModeDefinition
tdef.FireModes(1).AmmoTypeIndices += 1
tdef.FireModes(1).AmmoTypeIndices += 2
tdef.FireModes(1).AmmoSlotIndex = 1
tdef.FireModes(1).Magazine = 9
tdef.FireModes(1).RoundsPerShot = 2
tdef.FireModes(1).Chamber = 8
tdef.AmmoTypes.toList mustEqual List(GlobalDefinitions.bullet_9mm, GlobalDefinitions.shotgun_shell)
tdef.FireModes.size mustEqual 2
tdef.FireModes.head.AmmoTypeIndices.toList mustEqual List(0)
tdef.FireModes.head.AmmoSlotIndex mustEqual 0
tdef.FireModes.head.Magazine mustEqual 18
tdef.FireModes.head.RoundsPerShot mustEqual 18
tdef.FireModes.head.Chamber mustEqual 2
tdef.FireModes(1).AmmoTypeIndices.toList mustEqual List(1, 2)
tdef.FireModes(1).AmmoSlotIndex mustEqual 1
tdef.FireModes(1).Magazine mustEqual 9
tdef.FireModes(1).RoundsPerShot mustEqual 2
tdef.FireModes(1).Chamber mustEqual 8
}
"discharge" in {
val obj = Tool(GlobalDefinitions.beamer) //see EquipmentTest
obj.FireMode.isInstanceOf[FireModeDefinition] mustEqual true
obj.Magazine mustEqual 16
obj.FireMode.RoundsPerShot mustEqual 1
obj.FireMode.Chamber mustEqual 1
obj.Magazine mustEqual 16
obj.Discharge()
obj.Magazine mustEqual 15
obj.Discharge()
obj.Discharge()
obj.Magazine mustEqual 13
}
}
"PelletFireModeDefinition" should {
"construct" in {
val obj = new PelletFireModeDefinition
obj.AmmoTypeIndices mustEqual Nil
obj.AmmoSlotIndex mustEqual 0
obj.Magazine mustEqual 1
obj.RoundsPerShot mustEqual 1
obj.Chamber mustEqual 1
}
"discharge" in {
val obj = Tool(GlobalDefinitions.flechette) //see EquipmentTest
obj.FireMode.isInstanceOf[PelletFireModeDefinition] mustEqual true
obj.Magazine mustEqual 12
obj.FireMode.RoundsPerShot mustEqual 1
obj.FireMode.Chamber mustEqual 8
obj.Magazine mustEqual 12
obj.Discharge() //1
obj.Magazine mustEqual 12
obj.Discharge() //2
obj.Discharge() //3
obj.Magazine mustEqual 12
obj.Discharge() //4
obj.Discharge() //5
obj.Discharge() //6
obj.Discharge() //7
obj.Magazine mustEqual 12
obj.Discharge() //8
obj.Magazine mustEqual 11
}
}
"InfiniteFireModeDefinition" should {
"construct" in {
val obj = new InfiniteFireModeDefinition
obj.AmmoTypeIndices mustEqual Nil
obj.AmmoSlotIndex mustEqual 0
obj.Magazine mustEqual 1
obj.RoundsPerShot mustEqual 1
obj.Chamber mustEqual 1
}
"discharge" in {
val obj = Tool(GlobalDefinitions.magcutter) //see EquipmentTest
obj.FireMode.isInstanceOf[InfiniteFireModeDefinition] mustEqual true
obj.Magazine mustEqual 1
obj.FireMode.RoundsPerShot mustEqual 1
obj.FireMode.Chamber mustEqual 1
obj.Magazine mustEqual 1
obj.Discharge()
obj.Magazine mustEqual 1
obj.Discharge()
obj.Discharge()
obj.Magazine mustEqual 1
}
}
}

View file

@ -0,0 +1,852 @@
// Copyright (c) 2020 PSForever
package objects
import akka.actor.{ActorRef, Props}
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.ballistics._
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.{InventoryStateMessage, RepairMessage, TriggerEffectMessage}
import net.psforever.types._
import org.specs2.mutable.Specification
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import scala.concurrent.duration._
class GeneratorTest extends Specification {
"Generator" should {
"construct" in {
Generator(GlobalDefinitions.generator)
ok
}
"start in 'Normal' condition" in {
val obj = Generator(GlobalDefinitions.generator)
obj.Condition mustEqual PlanetSideGeneratorState.Normal
}
}
}
class GeneratorControlConstructTest extends ActorTest {
"GeneratorControl" should {
"construct" in {
val gen = Generator(GlobalDefinitions.generator)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "gen-control")
assert(gen.Actor != ActorRef.noSender)
}
}
}
class GeneratorControlDamageTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn()
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(
projectile,
weapon.Definition,
weapon.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"handle damage" in {
assert(gen.Health == gen.Definition.MaxHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveN(2, 500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 15)) =>
true
case _ => false
}
)
assert(gen.Health < gen.Definition.MaxHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
}
}
}
class GeneratorControlCriticalTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn()
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(
projectile,
weapon.Definition,
weapon.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
val halfHealth = gen.Definition.MaxHealth / 2
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"handle damage through the generator's critical state" in {
gen.Health = halfHealth + 1 //no matter what, the next shot pushes it to critical status
assert(gen.Health > halfHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveN(2, 500 milliseconds)
val msg_building = buildingProbe.receiveOne(500 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 15)) =>
true
case _ => false
}
)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(gen.Health < halfHealth)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Critical)
}
}
}
class GeneratorControlDestroyedTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn()
player1.Actor = TestProbe().ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(
projectile,
weapon.Definition,
weapon.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"handle damage until destroyed" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar1 = avatarProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
assert(
msg_avatar1 match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) =>
true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
avatarProbe.expectNoMessage(9 seconds)
buildingProbe.expectNoMessage(50 milliseconds) //no prior messages
val msg_avatar2 = avatarProbe.receiveN(3, 1000 milliseconds) //see DamageableEntity test file
val msg_building = buildingProbe.receiveOne(200 milliseconds)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(
msg_avatar2.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar2(1) match {
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
case _ => false
}
)
assert(
msg_avatar2(2) match {
case AvatarServiceMessage(
"test",
AvatarAction.SendResponse(_, TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None))
) =>
true
case _ => false
}
)
assert(gen.Health == 0)
assert(gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Destroyed)
}
}
}
class GeneratorControlKillsTest extends ActorTest {
/*
to perform this test, players need to be added to the SOI organization of the test base in proximity of the generator
under normal player scenario, this is an automatic process
extending from the act of players being in a zone
and players being within the SOI radius from the center of a facility on a periodic check
the test base being used has no established SOI region or automatic SOI check refresh,
but its SOI information can be loaded with the players manually
the players need something to catch the die message
*/
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn()
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Female, 1, CharacterVoice.Mute)) //guid=4
player2.Position = Vector3(15, 0, 0) //>14m from generator; lives
player2.Spawn()
val player2Probe = TestProbe()
player2.Actor = player2Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1, player2)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
guid.register(player2, 4)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(
projectile,
weapon.Definition,
weapon.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"kill players when the generator is destroyed" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar1 = avatarProbe.receiveN(2, 500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
player2Probe.expectNoMessage(200 milliseconds)
assert(
msg_avatar1.head match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) =>
true
case _ => false
}
)
assert(
msg_avatar1(1) match {
case AvatarServiceMessage("TestCharacter2", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) =>
true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
val msg_building = buildingProbe.receiveOne(10500 milliseconds)
val msg_avatar2 = avatarProbe.receiveN(3, 200 milliseconds)
val msg_player1 = player1Probe.receiveOne(100 milliseconds)
player2Probe.expectNoMessage(200 milliseconds)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(
msg_avatar2.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar2(1) match {
case AvatarServiceMessage("test", AvatarAction.Destroy(PlanetSideGUID(2), _, _, Vector3(1, 0, 0))) => true
case _ => false
}
)
assert(
msg_avatar2(2) match {
case AvatarServiceMessage(
"test",
AvatarAction.SendResponse(_, TriggerEffectMessage(PlanetSideGUID(2), "explosion_generator", None, None))
) =>
true
case _ => false
}
)
assert(
msg_player1 match {
case _ @Player.Die() => true
case _ => false
}
)
assert(gen.Health == 0)
assert(gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Destroyed)
}
}
}
class GeneratorControlNotDestroyTwice extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
val gen = Generator(GlobalDefinitions.generator) //guid=2
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val buildingProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
building.Actor = buildingProbe.ref
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(
projectile,
weapon.Definition,
weapon.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"not send a status update if destroyed and partially repaired, but destroyed again" in {
//damaged, not yet restored, but will not be destroyed again within one shot
val originalHealth = gen.Health = gen.Definition.DamageDestroysAt + 1
gen.Condition = PlanetSideGeneratorState.Destroyed //initial state manip
gen.Destroyed = true
assert(gen.Destroyed)
assert(originalHealth < gen.Definition.DefaultHealth)
assert(originalHealth < gen.Definition.RepairRestoresAt)
assert(originalHealth > gen.Definition.DamageDestroysAt)
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
activityProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(1000 milliseconds)
assert(gen.Health < originalHealth)
assert(gen.Destroyed)
assert(originalHealth < gen.Definition.DefaultHealth)
assert(originalHealth < gen.Definition.RepairRestoresAt)
assert(gen.Health <= gen.Definition.DamageDestroysAt)
//damaged, not yet restored, and would have been destroyed with next shot
gen.Health = 1
assert(gen.Health == 1)
assert(gen.Destroyed)
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
activityProbe.receiveOne(500 milliseconds) //activity alert occurs because this was not a kill shot
buildingProbe.expectNoMessage(1000 milliseconds)
assert(gen.Health == 0)
assert(gen.Destroyed)
}
}
}
class GeneratorControlNotDamageIfExplodingTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn()
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(
projectile,
weapon.Definition,
weapon.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"not damage if the generator is going to explode" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(
msg_avatar match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) =>
true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
//going to explode state
//once
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
//twice
gen.Actor ! Vitality.Damage(applyDamageTo)
avatarProbe.expectNoMessage(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
}
}
}
class GeneratorControlNotRepairIfExplodingTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn()
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
val weapon = Tool(GlobalDefinitions.phoenix) //decimator
val projectile = weapon.Projectile
val resolved = ResolvedProjectile(
ProjectileResolution.Splash,
Projectile(
projectile,
weapon.Definition,
weapon.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
SourceEntry(gen),
gen.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
val tool = Tool(GlobalDefinitions.nano_dispenser) //4 & 5
guid.register(tool, 4)
guid.register(tool.AmmoSlot.Box, 5)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"not repair if the generator is going to explode" in {
gen.Health = 1 //no matter what, the next shot destroys the generator
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal) //skipped critical state because didn't transition ~50%
gen.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar1 = avatarProbe.receiveOne(500 milliseconds)
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(
msg_avatar1 match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 16)) =>
true
case _ => false
}
)
assert(gen.Health == 1)
assert(!gen.Destroyed)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
//going to explode state
//once
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair?
avatarProbe.expectNoMessage(1000 milliseconds) //no messages
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
//twice
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair?
avatarProbe.expectNoMessage(1000 milliseconds) //no messages
buildingProbe.expectNoMessage(200 milliseconds)
player1Probe.expectNoMessage(200 milliseconds)
assert(gen.Health == 1)
}
}
}
class GeneratorControlRepairPastRestorePoint extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(5))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val gen = Generator(GlobalDefinitions.generator) //guid=2
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Position = Vector3(14, 0, 0) //<14m from generator; dies
player1.Spawn()
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
building.PlayersInSOI = List(player1)
val buildingProbe = TestProbe()
building.Actor = buildingProbe.ref
val tool = Tool(GlobalDefinitions.nano_dispenser) //4 & 5
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
guid.register(tool, 4)
guid.register(tool.AmmoSlot.Box, 5)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"GeneratorControl" should {
"send a status update if destroyed and repairing past the restoration point" in {
val originalHealth = gen.Health = gen.Definition.RepairRestoresAt - 1 //damage
gen.Condition = PlanetSideGeneratorState.Destroyed //initial state manip
gen.Destroyed = true
assert(originalHealth < gen.Definition.DefaultHealth)
assert(originalHealth < gen.Definition.RepairRestoresAt)
assert(gen.Destroyed)
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair
val msg_avatar = avatarProbe.receiveN(4, 500 milliseconds) //expected
val msg_building = buildingProbe.receiveOne(200 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction
.SendResponse(_, InventoryStateMessage(ValidPlanetSideGUID(5), _, ValidPlanetSideGUID(4), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
case AvatarServiceMessage("TestCharacter1", AvatarAction.GenericObjectAction(_, PlanetSideGUID(1), 17)) =>
true
case _ => false
}
)
assert(
msg_avatar(3) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, RepairMessage(ValidPlanetSideGUID(2), _))
) =>
true
case _ => false
}
)
assert(
msg_building match {
case Building.AmenityStateChange(o) => o eq gen
case _ => false
}
)
assert(gen.Condition == PlanetSideGeneratorState.Normal)
assert(gen.Health > gen.Definition.RepairRestoresAt)
assert(!gen.Destroyed)
}
}
}

View file

@ -0,0 +1,103 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{ActorSystem, Props}
import base.ActorTest
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.{Default, GlobalDefinitions, Player}
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.locks.{IFFLock, IFFLockControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.zones.Zone
import net.psforever.types._
import org.specs2.mutable.Specification
class IFFLockTest extends Specification {
"IFFLock" should {
"construct" in {
IFFLock(GlobalDefinitions.lock_external)
ok
}
//TODO internal hacking logic will be re-written later
"keep track of its orientation as a North-corrected vector" in {
val ulp = math.ulp(1)
val lock = IFFLock(GlobalDefinitions.lock_external)
lock.Orientation = Vector3(0, 0, 0) //face North
lock.Outwards.x < ulp mustEqual true
lock.Outwards.y mustEqual 1
lock.Orientation = Vector3(0, 0, 90) //face East
lock.Outwards.x mustEqual 1
lock.Outwards.y < ulp mustEqual true
lock.Orientation = Vector3(0, 0, 180) //face South
lock.Outwards.x < ulp mustEqual true
lock.Outwards.y mustEqual -1
lock.Orientation = Vector3(0, 0, 270) //face West
lock.Outwards.x mustEqual -1
lock.Outwards.y < ulp mustEqual true
}
}
}
class IFFLockControl1Test extends ActorTest {
"IFFLockControl" should {
"construct" in {
val lock = IFFLock(GlobalDefinitions.lock_external)
lock.Actor = system.actorOf(Props(classOf[IFFLockControl], lock), "lock-control")
assert(lock.Actor != Default.Actor)
}
}
}
class IFFLockControl2Test extends ActorTest {
"IFFLockControl" should {
"can hack" in {
val (player, lock) = IFFLockControlTest.SetUpAgents(PlanetSideEmpire.TR)
player.GUID = PlanetSideGUID(1)
assert(lock.HackedBy.isEmpty)
lock.Actor ! CommonMessages.Hack(player, lock)
Thread.sleep(500L) //blocking
assert(lock.HackedBy.nonEmpty) //TODO rewrite later
}
}
}
class IFFLockControl3Test extends ActorTest {
"IFFLockControl" should {
"can clear hack" in {
val (player, lock) = IFFLockControlTest.SetUpAgents(PlanetSideEmpire.TR)
player.GUID = PlanetSideGUID(1)
assert(lock.HackedBy.isEmpty)
lock.Actor ! CommonMessages.Hack(player, lock)
Thread.sleep(500L) //blocking
assert(lock.HackedBy.nonEmpty) //TODO rewrite later
lock.Actor ! CommonMessages.ClearHack()
Thread.sleep(500L) //blocking
assert(lock.HackedBy.isEmpty) //TODO rewrite
}
}
}
object IFFLockControlTest {
def SetUpAgents(faction: PlanetSideEmpire.Value)(implicit system: ActorSystem): (Player, IFFLock) = {
val lock = IFFLock(GlobalDefinitions.lock_external)
lock.Actor = system.actorOf(Props(classOf[IFFLockControl], lock), "lock-control")
lock.Owner = new Building(
"Building",
building_guid = 0,
map_id = 0,
Zone.Nowhere,
StructureType.Building,
GlobalDefinitions.building
)
lock.Owner.Faction = faction
(Player(Avatar(0, "test", faction, CharacterGender.Male, 0, CharacterVoice.Mute)), lock)
}
}

View file

@ -0,0 +1,656 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.{AmmoBox, SimpleItem, Tool}
import net.psforever.objects.definition.SimpleItemDefinition
import net.psforever.objects.inventory.{GridInventory, InventoryDisarrayException, InventoryItem, InventoryTile}
import net.psforever.objects.GlobalDefinitions.{bullet_9mm, suppressor}
import net.psforever.types.PlanetSideGUID
import org.specs2.mutable._
import scala.collection.mutable.ListBuffer
import scala.util.{Success, Failure}
class InventoryTest extends Specification {
val bullet9mmBox1 = AmmoBox(bullet_9mm)
bullet9mmBox1.GUID = PlanetSideGUID(1)
val bullet9mmBox2 = AmmoBox(bullet_9mm)
bullet9mmBox2.GUID = PlanetSideGUID(2)
"InventoryDisarrayException" should {
"construct" in {
InventoryDisarrayException("slot out of bounds")
ok
}
"construct (with Throwable)" in {
InventoryDisarrayException("slot out of bounds", new Throwable())
ok
}
}
"GridInventory" should {
"construct" in {
val obj: GridInventory = GridInventory()
obj.TotalCapacity mustEqual 1
obj.Capacity mustEqual 1
}
"resize" in {
val obj: GridInventory = GridInventory(9, 6)
obj.TotalCapacity mustEqual 54
obj.Capacity mustEqual 54
obj.Size mustEqual 0
}
"check for collision with inventory border" in {
val obj: GridInventory = GridInventory(3, 3)
//safe
obj.CheckCollisionsAsList(0, 3, 3) mustEqual Success(Nil)
//right
obj.CheckCollisionsAsList(-1, 3, 3) match {
case Failure(fail) =>
fail.isInstanceOf[IndexOutOfBoundsException] mustEqual true
case _ => ko
}
//left
obj.CheckCollisionsAsList(1, 3, 3) match {
case Failure(fail) =>
fail.isInstanceOf[IndexOutOfBoundsException] mustEqual true
case _ => ko
}
//bottom
obj.CheckCollisionsAsList(3, 3, 3) match {
case Failure(fail) =>
fail.isInstanceOf[IndexOutOfBoundsException] mustEqual true
case _ => ko
}
}
"check for item collision (right insert)" in {
val obj: GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.Width
val h = bullet9mmBox2.Tile.Height
val list0 = obj.CheckCollisionsAsList(0, w, h)
obj.CheckCollisionsAsList(0, w, h) match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(1, w, h)
list1 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(2, w, h)
list2 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(3, w, h)
list3 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(1, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(2, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(3, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (left insert)" in {
val obj: GridInventory = GridInventory(9, 6)
obj += 3 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.Width
val h = bullet9mmBox2.Tile.Height
val list0 = obj.CheckCollisionsAsList(3, w, h)
list0 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(2, w, h)
list1 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(1, w, h)
list2 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(0, w, h)
list3 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
obj.CheckCollisionsAsGrid(3, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(2, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(1, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (below insert)" in {
val obj: GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.Width
val h = bullet9mmBox2.Tile.Height
val list0 = obj.CheckCollisionsAsList(0, w, h)
list0 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(9, w, h)
list1 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(18, w, h)
list2 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(27, w, h)
list3 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(9, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(18, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(27, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (above insert)" in {
val obj: GridInventory = GridInventory(9, 6)
obj += 27 -> bullet9mmBox1
obj.Capacity mustEqual 45
val w = bullet9mmBox2.Tile.Width
val h = bullet9mmBox2.Tile.Height
val list0 = obj.CheckCollisionsAsList(27, w, h)
list0 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(18, w, h)
list1 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(9, w, h)
list2 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(0, w, h)
list3 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
obj.CheckCollisionsAsGrid(27, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(18, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(9, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list3
obj.Clear()
ok
}
"check for item collision (diagonal insert)" in {
/*
Number indicates upper-left corner of attempted 3x3 insertion by list#
0 - - - - - 2 - - - - -
- 1 - - - 3 - - - - - -
- - - - - - - - - - - -
- - - X X X - - - - - -
- - - X X X - - - - - -
- 5 - X X 7 - - - - - -
4 - - - - - 6 - - - - -
- - - - - - - - - - - -
- - - - - - - - - - - -
*/
val obj: GridInventory = GridInventory(12, 9)
obj += 39 -> bullet9mmBox1
obj.Capacity mustEqual 99 //108 - 9
val w = bullet9mmBox2.Tile.Width
val h = bullet9mmBox2.Tile.Height
val list0 = obj.CheckCollisionsAsList(0, w, h)
list0 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
val list1 = obj.CheckCollisionsAsList(13, w, h)
list1 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list2 = obj.CheckCollisionsAsList(6, w, h)
list2 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
val list3 = obj.CheckCollisionsAsList(17, w, h)
list3 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list4 = obj.CheckCollisionsAsList(72, w, h)
list4 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
val list5 = obj.CheckCollisionsAsList(61, w, h)
list5 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
val list6 = obj.CheckCollisionsAsList(78, w, h)
list6 match {
case Success(list) => list.isEmpty mustEqual true
case Failure(_) => ko
}
val list7 = obj.CheckCollisionsAsList(65, w, h)
list7 match {
case Success(list) => list.length mustEqual 1
case Failure(_) => ko
}
obj.CheckCollisionsAsGrid(0, w, h) mustEqual list0
obj.CheckCollisionsAsGrid(13, w, h) mustEqual list1
obj.CheckCollisionsAsGrid(6, w, h) mustEqual list2
obj.CheckCollisionsAsGrid(17, w, h) mustEqual list3
obj.CheckCollisionsAsGrid(72, w, h) mustEqual list4
obj.CheckCollisionsAsGrid(61, w, h) mustEqual list5
obj.CheckCollisionsAsGrid(78, w, h) mustEqual list6
obj.CheckCollisionsAsGrid(65, w, h) mustEqual list7
obj.Clear()
ok
}
"insert item" in {
val obj: GridInventory = GridInventory(9, 6)
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(Nil)
obj += 2 -> bullet9mmBox1
obj.TotalCapacity mustEqual 54
obj.Capacity mustEqual 45
obj.Size mustEqual 1
obj.hasItem(PlanetSideGUID(1)).contains(bullet9mmBox1) mustEqual true
obj.Clear()
obj.Size mustEqual 0
}
"not insert into an invalid slot (n < 0)" in {
val obj: GridInventory = GridInventory(9, 6)
obj.Capacity mustEqual 54
obj.Size mustEqual 0
obj.Insert(-1, bullet9mmBox1) must throwA[IndexOutOfBoundsException]
obj.Capacity mustEqual 54
obj.Size mustEqual 0
}
"not insert into an invalid slot (n > capacity)" in {
val obj: GridInventory = GridInventory(9, 6)
obj.Capacity mustEqual 54
obj.Size mustEqual 0
obj.Insert(55, bullet9mmBox1) must throwA[IndexOutOfBoundsException]
obj.Capacity mustEqual 54
obj.Size mustEqual 0
}
"block insertion if item collision" in {
val obj: GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.Capacity mustEqual 45
obj.hasItem(PlanetSideGUID(1)).contains(bullet9mmBox1) mustEqual true
obj += 2 -> bullet9mmBox2
obj.hasItem(PlanetSideGUID(2)).isEmpty mustEqual true
}
"insert items quickly (risk overwriting entries)" in {
val obj: GridInventory = GridInventory(6, 6)
(obj += 0 -> bullet9mmBox1) mustEqual true
val collision1 = obj.CheckCollisions(0, 1, 1)
obj.CheckCollisions(1, 1, 1) mustEqual collision1
obj.CheckCollisions(2, 1, 1) mustEqual collision1
obj.CheckCollisions(6, 1, 1) mustEqual collision1
obj.CheckCollisions(7, 1, 1) mustEqual collision1
obj.CheckCollisions(8, 1, 1) mustEqual collision1
obj.CheckCollisions(12, 1, 1) mustEqual collision1
obj.CheckCollisions(13, 1, 1) mustEqual collision1
obj.CheckCollisions(14, 1, 1) mustEqual collision1
(obj += 7 -> bullet9mmBox2) mustEqual false //can not insert overlapping object
obj.CheckCollisions(0, 1, 1) mustEqual collision1
obj.CheckCollisions(1, 1, 1) mustEqual collision1
obj.CheckCollisions(2, 1, 1) mustEqual collision1
obj.CheckCollisions(6, 1, 1) mustEqual collision1
obj.CheckCollisions(7, 1, 1) mustEqual collision1
obj.CheckCollisions(8, 1, 1) mustEqual collision1
obj.CheckCollisions(12, 1, 1) mustEqual collision1
obj.CheckCollisions(13, 1, 1) mustEqual collision1
obj.CheckCollisions(14, 1, 1) mustEqual collision1
obj.InsertQuickly(7, bullet9mmBox2) mustEqual true //overwrite
val collision2 = obj.CheckCollisions(7, 1, 1)
obj.CheckCollisions(0, 1, 1) mustEqual collision1
obj.CheckCollisions(1, 1, 1) mustEqual collision1
obj.CheckCollisions(2, 1, 1) mustEqual collision1
obj.CheckCollisions(6, 1, 1) mustEqual collision1
obj.CheckCollisions(7, 1, 1) mustEqual collision2
obj.CheckCollisions(8, 1, 1) mustEqual collision2
obj.CheckCollisions(12, 1, 1) mustEqual collision1
obj.CheckCollisions(13, 1, 1) mustEqual collision2
obj.CheckCollisions(14, 1, 1) mustEqual collision2
}
"clear all items" in {
val obj: GridInventory = GridInventory(9, 6)
obj += 2 -> bullet9mmBox1
obj.Size mustEqual 1
obj.hasItem(PlanetSideGUID(1)).contains(bullet9mmBox1) mustEqual true
obj.Clear()
obj.Size mustEqual 0
obj.hasItem(PlanetSideGUID(1)).isEmpty mustEqual true
}
"remove item" in {
val obj: GridInventory = GridInventory(9, 6)
obj += 0 -> bullet9mmBox1
obj.hasItem(PlanetSideGUID(1)).contains(bullet9mmBox1) mustEqual true
obj -= PlanetSideGUID(1)
obj.hasItem(PlanetSideGUID(1)).isEmpty mustEqual true
obj.Clear()
ok
}
"fail to remove from an invalid slot (n < 0)" in {
val obj: GridInventory = GridInventory(9, 6)
(obj -= -1) mustEqual false
}
"fail to remove from an invalid slot (n > capacity)" in {
val obj: GridInventory = GridInventory(9, 6)
(obj -= 55) mustEqual false
}
"unblock insertion on item removal" in {
val obj: GridInventory = GridInventory(9, 6)
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(Nil)
obj += 23 -> bullet9mmBox1
obj.hasItem(PlanetSideGUID(1)).contains(bullet9mmBox1) mustEqual true
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(1 :: Nil)
obj -= PlanetSideGUID(1)
obj.hasItem(PlanetSideGUID(1)).isEmpty mustEqual true
obj.CheckCollisions(23, bullet9mmBox1) mustEqual Success(Nil)
obj.Clear()
ok
}
"attempt to fit an item" in {
val sampleDef22 = new SimpleItemDefinition(149)
sampleDef22.Tile = InventoryTile.Tile22
val sampleDef33 = new SimpleItemDefinition(149)
sampleDef33.Tile = InventoryTile.Tile33
val sampleDef63 = new SimpleItemDefinition(149)
sampleDef63.Tile = InventoryTile.Tile63
val obj: GridInventory = GridInventory(9, 9)
obj += 0 -> SimpleItem(sampleDef22)
obj += 20 -> SimpleItem(sampleDef63)
obj += 56 -> SimpleItem(sampleDef33)
obj.Fit(InventoryTile.Tile33) match {
case Some(x) =>
x mustEqual 50
case None =>
ko
}
ok
}
"attempt to fit all the items" in {
val sampleDef1 = new SimpleItemDefinition(149)
sampleDef1.Tile = InventoryTile.Tile22
val sampleDef2 = new SimpleItemDefinition(149)
sampleDef2.Tile = InventoryTile.Tile33
val sampleDef3 = new SimpleItemDefinition(149)
sampleDef3.Tile = InventoryTile.Tile42
val sampleDef4 = new SimpleItemDefinition(149)
sampleDef4.Tile = InventoryTile.Tile63
val list: ListBuffer[InventoryItem] = ListBuffer()
list += new InventoryItem(SimpleItem(sampleDef2), -1)
list += new InventoryItem(SimpleItem(sampleDef3), -1)
list += new InventoryItem(SimpleItem(sampleDef1), -1)
list += new InventoryItem(SimpleItem(sampleDef4), -1)
list += new InventoryItem(SimpleItem(sampleDef1), -1)
list += new InventoryItem(SimpleItem(sampleDef4), -1)
list += new InventoryItem(SimpleItem(sampleDef2), -1)
list += new InventoryItem(SimpleItem(sampleDef3), -1)
val obj: GridInventory = GridInventory(9, 9)
val (elements, out) = GridInventory.recoverInventory(list.toList, obj)
elements.length mustEqual 6
out.length mustEqual 2
elements.foreach(item => {
obj.Insert(item.start, item.obj) mustEqual true
})
out.head.Definition.Tile mustEqual InventoryTile.Tile22 //did not fit
out(1).Definition.Tile mustEqual InventoryTile.Tile22 //did not fit
ok
}
"confirm integrity of inventory as a grid" in {
val obj: GridInventory = GridInventory(6, 6)
(obj += 0 -> bullet9mmBox1) mustEqual true
(obj += 21 -> bullet9mmBox2) mustEqual true
//artificially pollute the inventory grid-space
obj.SetCells(10, 1, 1, 3)
obj.SetCells(19, 2, 2, 4)
obj.ElementsOnGridMatchList() mustEqual 5 //number of misses repaired
}
"confirm integrity of inventory as a list (no overlap)" in {
val obj: GridInventory = GridInventory(9, 9)
val gun = Tool(suppressor)
obj.InsertQuickly(0, gun)
obj.InsertQuickly(33, bullet9mmBox1)
//nothing should overlap
val lists = obj.ElementsInListCollideInGrid()
lists.size mustEqual 0
}
"confirm integrity of inventory as a list (normal overlap)" in {
val obj: GridInventory = GridInventory(9, 9)
val gun = Tool(suppressor)
val bullet9mmBox3 = AmmoBox(bullet_9mm)
obj.InsertQuickly(0, gun)
obj.InsertQuickly(18, bullet9mmBox1)
obj.InsertQuickly(38, bullet9mmBox2)
obj.InsertQuickly(33, bullet9mmBox3)
//gun and box1 should overlap
//box1 and box2 should overlap
//box3 should not overlap with anything
val lists = obj.ElementsInListCollideInGrid()
lists.size mustEqual 2
lists.foreach { list =>
val out = list.map { _.obj }
if (out.size == 2 && out.contains(gun) && out.contains(bullet9mmBox1)) {
ok
} else if (out.size == 2 && out.contains(bullet9mmBox1) && out.contains(bullet9mmBox2)) {
ok
} else {
ko
}
}
ok
}
"confirm integrity of inventory as a list (triple overlap)" in {
val obj: GridInventory = GridInventory(9, 9)
val gun = Tool(suppressor)
val bullet9mmBox3 = AmmoBox(bullet_9mm)
val bullet9mmBox4 = AmmoBox(bullet_9mm)
obj.InsertQuickly(0, gun)
obj.InsertQuickly(18, bullet9mmBox1)
obj.InsertQuickly(36, bullet9mmBox2)
obj.InsertQuickly(38, bullet9mmBox3)
obj.InsertQuickly(33, bullet9mmBox4)
//gun and box1 should overlap
//box1, box2, and box3 should overlap
//box4 should not overlap with anything
val lists = obj.ElementsInListCollideInGrid()
lists.size mustEqual 2
lists.foreach { list =>
val out = list.map { _.obj }
if (out.size == 2 && out.contains(gun) && out.contains(bullet9mmBox1)) {
ok
} else if (
out.size == 3 && out.contains(bullet9mmBox1) && out.contains(bullet9mmBox2) && out.contains(bullet9mmBox3)
) {
ok
} else {
ko
}
}
ok
}
}
"InventoryEquiupmentSlot" should {
"insert, collide, insert" in {
val obj: GridInventory = GridInventory(7, 7)
obj.Slot(16).Equipment = bullet9mmBox1
//confirm all squares
obj.Slot(8).Equipment.nonEmpty mustEqual false
obj.Slot(9).Equipment.nonEmpty mustEqual false
obj.Slot(10).Equipment.nonEmpty mustEqual false
obj.Slot(11).Equipment.nonEmpty mustEqual false
obj.Slot(12).Equipment.nonEmpty mustEqual false
//
obj.Slot(15).Equipment.nonEmpty mustEqual false
obj.Slot(16).Equipment.nonEmpty mustEqual true
obj.Slot(17).Equipment.nonEmpty mustEqual true
obj.Slot(18).Equipment.nonEmpty mustEqual true
obj.Slot(19).Equipment.nonEmpty mustEqual false
//
obj.Slot(22).Equipment.nonEmpty mustEqual false
obj.Slot(23).Equipment.nonEmpty mustEqual true
obj.Slot(24).Equipment.nonEmpty mustEqual true
obj.Slot(25).Equipment.nonEmpty mustEqual true
obj.Slot(26).Equipment.nonEmpty mustEqual false
//
obj.Slot(29).Equipment.nonEmpty mustEqual false
obj.Slot(30).Equipment.nonEmpty mustEqual true
obj.Slot(31).Equipment.nonEmpty mustEqual true
obj.Slot(32).Equipment.nonEmpty mustEqual true
obj.Slot(33).Equipment.nonEmpty mustEqual false
//
obj.Slot(36).Equipment.nonEmpty mustEqual false
obj.Slot(37).Equipment.nonEmpty mustEqual false
obj.Slot(38).Equipment.nonEmpty mustEqual false
obj.Slot(39).Equipment.nonEmpty mustEqual false
obj.Slot(40).Equipment.nonEmpty mustEqual false
//
//remove
obj.Slot(16).Equipment = None
obj.Slot(8).Equipment.nonEmpty mustEqual false
obj.Slot(9).Equipment.nonEmpty mustEqual false
obj.Slot(10).Equipment.nonEmpty mustEqual false
obj.Slot(11).Equipment.nonEmpty mustEqual false
obj.Slot(12).Equipment.nonEmpty mustEqual false
//
obj.Slot(15).Equipment.nonEmpty mustEqual false
obj.Slot(16).Equipment.nonEmpty mustEqual false
obj.Slot(17).Equipment.nonEmpty mustEqual false
obj.Slot(18).Equipment.nonEmpty mustEqual false
obj.Slot(19).Equipment.nonEmpty mustEqual false
//
obj.Slot(22).Equipment.nonEmpty mustEqual false
obj.Slot(23).Equipment.nonEmpty mustEqual false
obj.Slot(24).Equipment.nonEmpty mustEqual false
obj.Slot(25).Equipment.nonEmpty mustEqual false
obj.Slot(26).Equipment.nonEmpty mustEqual false
//
obj.Slot(29).Equipment.nonEmpty mustEqual false
obj.Slot(30).Equipment.nonEmpty mustEqual false
obj.Slot(31).Equipment.nonEmpty mustEqual false
obj.Slot(32).Equipment.nonEmpty mustEqual false
obj.Slot(33).Equipment.nonEmpty mustEqual false
//
obj.Slot(36).Equipment.nonEmpty mustEqual false
obj.Slot(37).Equipment.nonEmpty mustEqual false
obj.Slot(38).Equipment.nonEmpty mustEqual false
obj.Slot(39).Equipment.nonEmpty mustEqual false
obj.Slot(40).Equipment.nonEmpty mustEqual false
//insert again
obj.Slot(16).Equipment = bullet9mmBox2
obj.Slot(8).Equipment.nonEmpty mustEqual false
obj.Slot(9).Equipment.nonEmpty mustEqual false
obj.Slot(10).Equipment.nonEmpty mustEqual false
obj.Slot(11).Equipment.nonEmpty mustEqual false
obj.Slot(12).Equipment.nonEmpty mustEqual false
//
obj.Slot(15).Equipment.nonEmpty mustEqual false
obj.Slot(16).Equipment.nonEmpty mustEqual true
obj.Slot(17).Equipment.nonEmpty mustEqual true
obj.Slot(18).Equipment.nonEmpty mustEqual true
obj.Slot(19).Equipment.nonEmpty mustEqual false
//
obj.Slot(22).Equipment.nonEmpty mustEqual false
obj.Slot(23).Equipment.nonEmpty mustEqual true
obj.Slot(24).Equipment.nonEmpty mustEqual true
obj.Slot(25).Equipment.nonEmpty mustEqual true
obj.Slot(26).Equipment.nonEmpty mustEqual false
//
obj.Slot(29).Equipment.nonEmpty mustEqual false
obj.Slot(30).Equipment.nonEmpty mustEqual true
obj.Slot(31).Equipment.nonEmpty mustEqual true
obj.Slot(32).Equipment.nonEmpty mustEqual true
obj.Slot(33).Equipment.nonEmpty mustEqual false
//
obj.Slot(36).Equipment.nonEmpty mustEqual false
obj.Slot(37).Equipment.nonEmpty mustEqual false
obj.Slot(38).Equipment.nonEmpty mustEqual false
obj.Slot(39).Equipment.nonEmpty mustEqual false
obj.Slot(40).Equipment.nonEmpty mustEqual false
//
//remove
obj.Slot(16).Equipment = None
obj.Slot(8).Equipment.nonEmpty mustEqual false
obj.Slot(9).Equipment.nonEmpty mustEqual false
obj.Slot(10).Equipment.nonEmpty mustEqual false
obj.Slot(11).Equipment.nonEmpty mustEqual false
obj.Slot(12).Equipment.nonEmpty mustEqual false
//
obj.Slot(15).Equipment.nonEmpty mustEqual false
obj.Slot(16).Equipment.nonEmpty mustEqual false
obj.Slot(17).Equipment.nonEmpty mustEqual false
obj.Slot(18).Equipment.nonEmpty mustEqual false
obj.Slot(19).Equipment.nonEmpty mustEqual false
//
obj.Slot(22).Equipment.nonEmpty mustEqual false
obj.Slot(23).Equipment.nonEmpty mustEqual false
obj.Slot(24).Equipment.nonEmpty mustEqual false
obj.Slot(25).Equipment.nonEmpty mustEqual false
obj.Slot(26).Equipment.nonEmpty mustEqual false
//
obj.Slot(29).Equipment.nonEmpty mustEqual false
obj.Slot(30).Equipment.nonEmpty mustEqual false
obj.Slot(31).Equipment.nonEmpty mustEqual false
obj.Slot(32).Equipment.nonEmpty mustEqual false
obj.Slot(33).Equipment.nonEmpty mustEqual false
//
obj.Slot(36).Equipment.nonEmpty mustEqual false
obj.Slot(37).Equipment.nonEmpty mustEqual false
obj.Slot(38).Equipment.nonEmpty mustEqual false
obj.Slot(39).Equipment.nonEmpty mustEqual false
obj.Slot(40).Equipment.nonEmpty mustEqual false
}
}
}

View file

@ -0,0 +1,152 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects._
import net.psforever.objects.loadouts._
import net.psforever.types.{CharacterGender, CharacterVoice, ExoSuitType, PlanetSideEmpire}
import net.psforever.objects.GlobalDefinitions._
import net.psforever.objects.avatar.Avatar
import org.specs2.mutable._
class LoadoutTest extends Specification {
val avatar = Avatar(0, "TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 41, CharacterVoice.Voice1)
def CreatePlayer(): Player = {
new Player(avatar) {
Slot(0).Equipment = Tool(beamer)
Slot(2).Equipment = Tool(suppressor)
Slot(4).Equipment = Tool(forceblade)
Slot(6).Equipment = ConstructionItem(ace)
Slot(9).Equipment = AmmoBox(bullet_9mm)
Slot(12).Equipment = AmmoBox(bullet_9mm)
Slot(33).Equipment = Kit(medkit)
Slot(39).Equipment = SimpleItem(remote_electronics_kit)
}
}
"test sample player" in {
val player = CreatePlayer()
player.Holsters()(0).Equipment.get.Definition mustEqual beamer
player.Holsters()(2).Equipment.get.Definition mustEqual suppressor
player.Holsters()(4).Equipment.get.Definition mustEqual forceblade
player.Slot(6).Equipment.get.Definition mustEqual ace
player.Slot(9).Equipment.get.Definition mustEqual bullet_9mm
player.Slot(12).Equipment.get.Definition mustEqual bullet_9mm
player.Slot(33).Equipment.get.Definition mustEqual medkit
player.Slot(39).Equipment.get.Definition mustEqual remote_electronics_kit
}
"create a loadout that contains a player's inventory" in {
val player = CreatePlayer()
val obj = Loadout.Create(player, "test").asInstanceOf[InfantryLoadout]
obj.label mustEqual "test"
obj.exosuit mustEqual ExoSuitType.Standard
obj.subtype mustEqual 0
obj.visible_slots.length mustEqual 3
val holsters = obj.visible_slots.sortBy(_.index)
holsters.head.index mustEqual 0
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual beamer
holsters(1).index mustEqual 2
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual suppressor
holsters(2).index mustEqual 4
holsters(2).item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual forceblade
obj.inventory.length mustEqual 5
val inventory = obj.inventory.sortBy(_.index)
inventory.head.index mustEqual 6
inventory.head.item.asInstanceOf[Loadout.ShorthandConstructionItem].definition mustEqual ace
inventory(1).index mustEqual 9
inventory(1).item.asInstanceOf[Loadout.ShorthandAmmoBox].definition mustEqual bullet_9mm
inventory(2).index mustEqual 12
inventory(2).item.asInstanceOf[Loadout.ShorthandAmmoBox].definition mustEqual bullet_9mm
inventory(3).index mustEqual 33
inventory(3).item.asInstanceOf[Loadout.ShorthandKit].definition mustEqual medkit
inventory(4).index mustEqual 39
inventory(4).item.asInstanceOf[Loadout.ShorthandSimpleItem].definition mustEqual remote_electronics_kit
}
"create a loadout that contains a vehicle's inventory" in {
val vehicle = Vehicle(mediumtransport)
vehicle.Inventory += 30 -> AmmoBox(bullet_9mm)
vehicle.Inventory += 33 -> AmmoBox(bullet_9mm_AP)
val obj = Loadout.Create(vehicle, "test").asInstanceOf[VehicleLoadout]
obj.label mustEqual "test"
obj.vehicle_definition mustEqual mediumtransport
obj.visible_slots.length mustEqual 2
val holsters = obj.visible_slots.sortBy(_.index)
holsters.head.index mustEqual 5
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual mediumtransport_weapon_systemA
holsters(1).index mustEqual 6
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual mediumtransport_weapon_systemB
obj.inventory.length mustEqual 2
val inventory = obj.inventory.sortBy(_.index)
inventory.head.index mustEqual 30
inventory.head.item.asInstanceOf[Loadout.ShorthandAmmoBox].definition mustEqual bullet_9mm
inventory(1).index mustEqual 33
inventory(1).item.asInstanceOf[Loadout.ShorthandAmmoBox].definition mustEqual bullet_9mm_AP
}
"distinguish MAX subtype information" in {
val player = CreatePlayer()
val slot = player.Slot(0)
slot.Equipment = None //only an unequipped slot can have its Equipment Size changed (Rifle -> Max)
player.ExoSuit = ExoSuitType.MAX
val ldout1 = Loadout.Create(player, "weaponless").asInstanceOf[InfantryLoadout]
slot.Equipment = None
slot.Equipment = Tool(trhev_dualcycler)
val ldout2 = Loadout.Create(player, "cycler").asInstanceOf[InfantryLoadout]
slot.Equipment = None
slot.Equipment = Tool(trhev_pounder)
val ldout3 = Loadout.Create(player, "pounder").asInstanceOf[InfantryLoadout]
slot.Equipment = None
slot.Equipment = Tool(trhev_burster)
val ldout4 = Loadout.Create(player, "burster").asInstanceOf[InfantryLoadout]
ldout1.subtype mustEqual 0
ldout2.subtype mustEqual 1
ldout3.subtype mustEqual 2
ldout4.subtype mustEqual InfantryLoadout.DetermineSubtype(player) //example
}
"players have additional uniform subtype" in {
val player = CreatePlayer()
val slot = player.Slot(0)
slot.Equipment = None //only an unequipped slot can have its Equipment Size changed (Rifle -> Max)
player.ExoSuit = ExoSuitType.Standard
val ldout0 = Loadout.Create(player, "standard").asInstanceOf[InfantryLoadout]
player.ExoSuit = ExoSuitType.Agile
val ldout1 = Loadout.Create(player, "agile").asInstanceOf[InfantryLoadout]
player.ExoSuit = ExoSuitType.Reinforced
val ldout2 = Loadout.Create(player, "rein").asInstanceOf[InfantryLoadout]
player.ExoSuit = ExoSuitType.Infiltration
val ldout7 = Loadout.Create(player, "inf").asInstanceOf[InfantryLoadout]
player.ExoSuit = ExoSuitType.MAX
val ldout3 = Loadout.Create(player, "weaponless").asInstanceOf[InfantryLoadout]
slot.Equipment = None
slot.Equipment = Tool(trhev_dualcycler)
val ldout4 = Loadout.Create(player, "cycler").asInstanceOf[InfantryLoadout]
slot.Equipment = None
slot.Equipment = Tool(trhev_pounder)
val ldout5 = Loadout.Create(player, "pounder").asInstanceOf[InfantryLoadout]
slot.Equipment = None
slot.Equipment = Tool(trhev_burster)
val ldout6 = Loadout.Create(player, "burster").asInstanceOf[InfantryLoadout]
InfantryLoadout.DetermineSubtypeB(ldout0.exosuit, ldout0.subtype) mustEqual 0
InfantryLoadout.DetermineSubtypeB(ldout1.exosuit, ldout1.subtype) mustEqual 1
InfantryLoadout.DetermineSubtypeB(ldout2.exosuit, ldout2.subtype) mustEqual 2
InfantryLoadout.DetermineSubtypeB(ldout3.exosuit, ldout3.subtype) mustEqual 3
InfantryLoadout.DetermineSubtypeB(ldout4.exosuit, ldout4.subtype) mustEqual 4
InfantryLoadout.DetermineSubtypeB(ldout5.exosuit, ldout5.subtype) mustEqual 5
InfantryLoadout.DetermineSubtypeB(ldout6.exosuit, ldout6.subtype) mustEqual 6
InfantryLoadout.DetermineSubtypeB(ldout7.exosuit, ldout7.subtype) mustEqual 7
}
}

View file

@ -0,0 +1,37 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.Props
import base.ActorTest
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.mblocker.{Locker, LockerControl}
import net.psforever.types.PlanetSideEmpire
import org.specs2.mutable._
class LockerTest extends Specification {
"LockerDefinition" should {
"define" in {
GlobalDefinitions.mb_locker.ObjectId mustEqual 524
GlobalDefinitions.mb_locker.Name mustEqual "mb_locker"
}
}
"Locker" should {
"construct" in {
new Locker()
ok
}
}
}
class LockerControlTest extends ActorTest {
"LockerControl" should {
"construct" in {
val locker = new Locker()
locker.Actor = system.actorOf(Props(classOf[LockerControl], locker), "test")
locker.Actor ! FactionAffinity.ConfirmFactionAffinity()
expectMsg(FactionAffinity.AssertFactionAffinity(locker, PlanetSideEmpire.NEUTRAL))
}
}
}

View file

@ -0,0 +1,98 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, ActorRef, Props}
import base.ActorTest
import net.psforever.objects.Player
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.definition.{ObjectDefinition, SeatDefinition}
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.vehicles.Seat
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, PlanetSideGUID}
import scala.concurrent.duration.Duration
class MountableControl1Test extends ActorTest {
"MountableControl" should {
"construct" in {
val obj = new MountableTest.MountableTestObject
obj.Actor = system.actorOf(Props(classOf[MountableTest.MountableTestControl], obj), "mech")
assert(obj.Actor != ActorRef.noSender)
}
}
}
class MountableControl2Test extends ActorTest {
"MountableControl" should {
"let a player mount" in {
val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj = new MountableTest.MountableTestObject
obj.Actor = system.actorOf(Props(classOf[MountableTest.MountableTestControl], obj), "mountable")
val msg = Mountable.TryMount(player, 0)
obj.Actor ! msg
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player)
assert(reply2.response.isInstanceOf[Mountable.CanMount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanMount]
assert(reply3.obj == obj)
assert(reply3.seat_num == 0)
}
}
}
class MountableControl3Test extends ActorTest {
"MountableControl" should {
"block a player from mounting" in {
val player1 = Player(Avatar(0, "test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val player2 = Player(Avatar(1, "test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj = new MountableTest.MountableTestObject
obj.Actor = system.actorOf(Props(classOf[MountableTest.MountableTestControl], obj), "mountable")
obj.Actor ! Mountable.TryMount(player1, 0)
receiveOne(Duration.create(100, "ms")) //consume reply
obj.Actor ! Mountable.TryMount(player2, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player2)
assert(reply2.response.isInstanceOf[Mountable.CanNotMount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanNotMount]
assert(reply3.obj == obj)
assert(reply3.seat_num == 0)
}
}
}
object MountableTest {
class MountableTestObject extends PlanetSideServerObject with Mountable {
private val seats: Map[Int, Seat] = Map(0 -> new Seat(new SeatDefinition()))
def Seats: Map[Int, Seat] = seats
def Seat(seatNum: Int): Option[Seat] = seats.get(seatNum)
def MountPoints: Map[Int, Int] = Map(1 -> 0)
def GetSeatFromMountPoint(mount: Int): Option[Int] = MountPoints.get(mount)
def PassengerInSeat(user: Player): Option[Int] = {
if (seats(0).Occupant.contains(user)) {
Some(0)
} else {
None
}
}
GUID = PlanetSideGUID(1)
//eh whatever
def Faction = PlanetSideEmpire.TR
def Definition: ObjectDefinition = null
}
class MountableTestControl(obj: PlanetSideServerObject with Mountable)
extends Actor
with MountableBehavior.Mount
with MountableBehavior.Dismount {
override def MountableObject = obj
def receive: Receive = mountBehavior.orElse(dismountBehavior)
}
}

View file

@ -0,0 +1,725 @@
// Copyright (c) 2020 PSForever
package objects
/*
import akka.actor.Props
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects.avatar.{Avatar, PlayerControl}
import net.psforever.objects.ballistics._
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.vital.Vitality
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.objects._
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.packet.game._
import net.psforever.types._
import net.psforever.services.Service
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import scala.concurrent.duration._
class PlayerControlHealTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(15))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1
player1.Zone = zone
player1.Spawn()
player1.Position = Vector3(2, 0, 0)
guid.register(player1.avatar.locker, 5)
player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1), "player1-control")
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=2
player2.Zone = zone
player2.Spawn()
guid.register(player2.avatar.locker, 6)
player2.Actor = system.actorOf(Props(classOf[PlayerControl], player2), "player2-control")
val tool = Tool(GlobalDefinitions.medicalapplicator) //guid=3 & 4
guid.register(player1, 1)
guid.register(player2, 2)
guid.register(tool, 3)
guid.register(tool.AmmoSlot.Box, 4)
"PlayerControl" should {
"handle being healed by another player" in {
val originalHealth = player2.Health = 0 //initial state manip
val originalMagazine = tool.Magazine
assert(originalHealth < player2.MaxHealth)
player2.Actor ! CommonMessages.Use(player1, Some(tool))
val msg_avatar = avatarProbe.receiveN(4, 500 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 55, 1)
) =>
true
case _ => false
}
)
assert(
msg_avatar(3) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, RepairMessage(PlanetSideGUID(2), _))
) =>
true
case _ => false
}
)
val raisedHealth = player2.Health
assert(raisedHealth > originalHealth)
assert(tool.Magazine < originalMagazine)
player1.Position = Vector3(10, 0, 0) //moved more than 5m away
player2.Actor ! CommonMessages.Use(player1, Some(tool))
avatarProbe.expectNoMessage(500 milliseconds)
assert(raisedHealth == player2.Health)
}
}
}
class PlayerControlHealSelfTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(15))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1
player1.Zone = zone
player1.Spawn()
player1.Position = Vector3(2, 0, 0)
guid.register(player1.avatar.locker, 5)
player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1), "player1-control")
val tool = Tool(GlobalDefinitions.medicalapplicator) //guid=3 & 4
guid.register(player1, 1)
guid.register(tool, 3)
guid.register(tool.AmmoSlot.Box, 4)
"PlayerControl" should {
"handle healing own self" in {
val originalHealth = player1.Health = 1 //initial state manip
val originalMagazine = tool.Magazine
assert(originalHealth < player1.MaxHealth)
player1.Actor ! CommonMessages.Use(player1, Some(tool))
val msg_avatar1 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar1.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar1(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
val raisedHealth = player1.Health
assert(raisedHealth > originalHealth)
assert(tool.Magazine < originalMagazine)
player1.Position = Vector3(10, 0, 0) //trying to move away from oneself doesn't work
player1.Actor ! CommonMessages.Use(player1, Some(tool))
val msg_avatar2 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar2.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar2(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
assert(player1.Health > raisedHealth)
}
}
}
class PlayerControlRepairTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(15))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1
player1.Zone = zone
player1.Spawn()
player1.Position = Vector3(2, 0, 0)
guid.register(player1.avatar.locker, 5)
player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1), "player1-control")
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=2
player2.Zone = zone
player2.Spawn()
guid.register(player2.avatar.locker, 6)
player2.Actor = system.actorOf(Props(classOf[PlayerControl], player2), "player2-control")
val tool = Tool(GlobalDefinitions.bank) //guid=3 & 4
guid.register(player1, 1)
guid.register(player2, 2)
guid.register(tool, 3)
guid.register(tool.AmmoSlot.Box, 4)
"PlayerControl" should {
"handle being repaired by another player" in {
val originalArmor = player2.Armor = 0 //initial state manip
val originalMagazine = tool.Magazine
assert(originalArmor < player2.MaxArmor)
player2.Actor ! CommonMessages.Use(player1, Some(tool))
val msg_avatar = avatarProbe.receiveN(5, 1000 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 4, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 56, 1)
) =>
true
case _ => false
}
)
assert(
msg_avatar(3) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, RepairMessage(PlanetSideGUID(2), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar(4) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 56, 1)
) =>
true
case _ => false
}
)
assert(player2.Armor > originalArmor)
assert(tool.Magazine < originalMagazine)
val fixedArmor = player2.Armor
player1.Position = Vector3(10, 0, 0) //moved more than 5m away
player2.Actor ! CommonMessages.Use(player1, Some(tool))
avatarProbe.expectNoMessage(500 milliseconds)
assert(fixedArmor == player2.Armor)
}
}
}
class PlayerControlRepairSelfTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(15))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1
player1.Zone = zone
player1.Spawn()
player1.Position = Vector3(2, 0, 0)
guid.register(player1.avatar.locker, 5)
player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1), "player1-control")
val tool = Tool(GlobalDefinitions.bank) //guid=3 & 4
guid.register(player1, 1)
guid.register(tool, 3)
guid.register(tool.AmmoSlot.Box, 4)
"PlayerControl" should {
"handle repairing own self" in {
val originalArmor = player1.Armor = 0 //initial state manip
val originalMagazine = tool.Magazine
assert(originalArmor < player1.MaxArmor)
player1.Actor ! CommonMessages.Use(player1, Some(tool))
val msg_avatar1 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar1.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar1(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 4, _)) => true
case _ => false
}
)
val fixedArmor = player1.Armor
assert(fixedArmor > originalArmor)
assert(tool.Magazine < originalMagazine)
player1.Position = Vector3(10, 0, 0) //trying to move away from oneself doesn't work
player1.Actor ! CommonMessages.Use(player1, Some(tool))
val msg_avatar2 = avatarProbe.receiveN(2, 500 milliseconds)
assert(
msg_avatar2.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(_, InventoryStateMessage(PlanetSideGUID(4), _, PlanetSideGUID(3), _))
) =>
true
case _ => false
}
)
assert(
msg_avatar2(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 4, _)) => true
case _ => false
}
)
assert(player1.Armor > fixedArmor)
}
}
}
class PlayerControlDamageTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(15))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1
player1.Zone = zone
player1.Spawn()
player1.Position = Vector3(2, 0, 0)
guid.register(player1.avatar.locker, 5)
player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1), "player1-control")
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=2
player2.Zone = zone
player2.Spawn()
guid.register(player2.avatar.locker, 6)
player2.Actor = system.actorOf(Props(classOf[PlayerControl], player2), "player2-control")
val tool = Tool(GlobalDefinitions.suppressor) //guid 3 & 4
val projectile = tool.Projectile
val playerSource = SourceEntry(player2)
val resolved = ResolvedProjectile(
ProjectileResolution.Hit,
Projectile(
projectile,
tool.Definition,
tool.FireMode,
PlayerSource(player1),
0,
Vector3(2, 0, 0),
Vector3(-1, 0, 0)
),
playerSource,
player1.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
guid.register(player1, 1)
guid.register(player2, 2)
guid.register(tool, 3)
guid.register(tool.AmmoSlot.Box, 4)
expectNoMessage(200 milliseconds)
"PlayerControl" should {
"handle damage" in {
assert(player2.Health == player2.Definition.DefaultHealth)
assert(player2.Armor == player2.MaxArmor)
player2.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveN(4, 500 milliseconds)
val msg_activity = activityProbe.receiveOne(200 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 4, _)) => true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(2) match {
case AvatarServiceMessage("TestCharacter2", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 2, _)) =>
true
case _ => false
}
)
assert(
msg_activity match {
case activity: Zone.HotSpot.Activity =>
activity.attacker == PlayerSource(player1) &&
activity.defender == playerSource &&
activity.location == Vector3(1, 0, 0)
case _ => false
}
)
assert(
msg_avatar(3) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.SendResponse(Service.defaultPlayerGUID, DamageWithPositionMessage(10, Vector3(2, 0, 0)))
) =>
true
case _ => false
}
)
assert(player2.Health < player2.Definition.DefaultHealth)
assert(player2.Armor < player2.MaxArmor)
}
}
}
class PlayerControlDeathStandingTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(15))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1
player1.Zone = zone
player1.Spawn()
player1.Position = Vector3(2, 0, 0)
guid.register(player1.avatar.locker, 5)
player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1), "player1-control")
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=2
player2.Zone = zone
player2.Spawn()
guid.register(player2.avatar.locker, 6)
player2.Actor = system.actorOf(Props(classOf[PlayerControl], player2), "player2-control")
val tool = Tool(GlobalDefinitions.suppressor) //guid 3 & 4
val projectile = tool.Projectile
val player1Source = SourceEntry(player1)
val resolved = ResolvedProjectile(
ProjectileResolution.Hit,
Projectile(projectile, tool.Definition, tool.FireMode, player1Source, 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(player2),
player2.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
guid.register(player1, 1)
guid.register(player2, 2)
guid.register(tool, 3)
guid.register(tool.AmmoSlot.Box, 4)
expectNoMessage(200 milliseconds)
"PlayerControl" should {
"handle death" in {
player2.Health = player2.Definition.DamageDestroysAt + 1 //initial state manip
player2.ExoSuit = ExoSuitType.MAX
player2.Armor = 1 //initial state manip
player2.Capacitor = 1 //initial state manip
assert(player2.Health > player2.Definition.DamageDestroysAt)
assert(player2.Armor == 1)
assert(player2.Capacitor == 1)
assert(player2.isAlive)
player2.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveN(8, 500 milliseconds)
activityProbe.expectNoMessage(200 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 4, _)) => true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage("TestCharacter2", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 2, _)) =>
true
case _ => false
}
)
assert(
msg_avatar(2) match {
case AvatarServiceMessage("TestCharacter2", AvatarAction.Killed(PlanetSideGUID(2), None)) => true
case _ => false
}
)
assert(
msg_avatar(3) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(4) match {
case AvatarServiceMessage("TestCharacter2", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 7, _)) =>
true
case _ => false
}
)
assert(
msg_avatar(5) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.SendResponse(_, DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(2), _, Vector3.Zero))
) =>
true
case _ => false
}
)
assert(
msg_avatar(6) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.SendResponse(
_,
AvatarDeadStateMessage(DeadState.Dead, 300000, 300000, Vector3.Zero, PlanetSideEmpire.NC, true)
)
) =>
true
case _ => false
}
)
assert(
msg_avatar(7) match {
case AvatarServiceMessage("test", AvatarAction.DestroyDisplay(killer, victim, _, _))
if killer.Name.equals(player1.Name) && victim.Name.equals(player2.Name) =>
true
case _ => false
}
)
assert(player2.Health <= player2.Definition.DamageDestroysAt)
assert(player2.Armor == 0)
assert(!player2.isAlive)
}
}
}
class PlayerControlDeathSeatedTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(15))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val activityProbe = TestProbe()
zone.Activity = activityProbe.ref
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=1
player1.Zone = zone
player1.Spawn()
player1.Position = Vector3(2, 0, 0)
guid.register(player1.avatar.locker, 6)
player1.Actor = system.actorOf(Props(classOf[PlayerControl], player1), "player1-control")
val player2 =
Player(Avatar(0, "TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=2
player2.Zone = zone
player2.Spawn()
guid.register(player2.avatar.locker, 7)
player2.Actor = system.actorOf(Props(classOf[PlayerControl], player2), "player2-control")
val vehicle = Vehicle(GlobalDefinitions.quadstealth) //guid=5
vehicle.Faction = player2.Faction
val tool = Tool(GlobalDefinitions.suppressor) //guid 3 & 4
val projectile = tool.Projectile
val player1Source = SourceEntry(player1)
val resolved = ResolvedProjectile(
ProjectileResolution.Hit,
Projectile(projectile, tool.Definition, tool.FireMode, player1Source, 0, Vector3(2, 0, 0), Vector3(-1, 0, 0)),
SourceEntry(player2),
player2.DamageModel,
Vector3(1, 0, 0)
)
val applyDamageTo = resolved.damage_model.Calculate(resolved)
guid.register(player1, 1)
guid.register(player2, 2)
guid.register(tool, 3)
guid.register(tool.AmmoSlot.Box, 4)
guid.register(vehicle, 5)
expectNoMessage(200 milliseconds)
"PlayerControl" should {
"handle death when seated (in something)" in {
player2.Health = player2.Definition.DamageDestroysAt + 1 //initial state manip
player2.VehicleSeated = vehicle.GUID //initial state manip, anything
vehicle.Seats(0).Occupant = player2
player2.Armor = 0 //initial state manip
assert(player2.Health > player2.Definition.DamageDestroysAt)
assert(player2.isAlive)
player2.Actor ! Vitality.Damage(applyDamageTo)
val msg_avatar = avatarProbe.receiveN(9, 500 milliseconds)
activityProbe.expectNoMessage(200 milliseconds)
assert(
msg_avatar.head match {
case AvatarServiceMessage("TestCharacter2", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 2, _)) =>
true
case _ => false
}
)
assert(
msg_avatar(1) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.Killed(PlanetSideGUID(2), Some(PlanetSideGUID(5)))
) =>
true
case _ => false
}
)
assert(
msg_avatar(2) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.SendResponse(_, ObjectDetachMessage(PlanetSideGUID(5), PlanetSideGUID(2), _, _, _, _))
) =>
true
case _ => false
}
)
assert(
msg_avatar(3) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 29, 1)
) =>
true
case _ => false
}
)
assert(
msg_avatar(4) match {
case AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(2), PlanetSideGUID(2), _)) => true
case _ => false
}
)
assert(
msg_avatar(5) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg_avatar(6) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.SendResponse(_, DestroyMessage(PlanetSideGUID(2), PlanetSideGUID(2), _, Vector3.Zero))
) =>
true
case _ => false
}
)
assert(
msg_avatar(7) match {
case AvatarServiceMessage(
"TestCharacter2",
AvatarAction.SendResponse(
_,
AvatarDeadStateMessage(DeadState.Dead, 300000, 300000, Vector3.Zero, PlanetSideEmpire.NC, true)
)
) =>
true
case _ => false
}
)
assert(
msg_avatar(8) match {
case AvatarServiceMessage("test", AvatarAction.DestroyDisplay(killer, victim, _, _))
if killer.Name.equals(player1.Name) && victim.Name.equals(player2.Name) =>
true
case _ => false
}
)
assert(player2.Health <= player2.Definition.DamageDestroysAt)
assert(!player2.isAlive)
}
}
}
object PlayerControlTest {}
*/

View file

@ -0,0 +1,425 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.GlobalDefinitions._
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.definition.{SimpleItemDefinition, SpecialExoSuitDefinition}
import net.psforever.objects.equipment.EquipmentSize
import net.psforever.types.{PlanetSideGUID, _}
import org.specs2.mutable._
import scala.util.Success
class PlayerTest extends Specification {
def TestPlayer(
name: String,
faction: PlanetSideEmpire.Value,
sex: CharacterGender.Value,
head: Int,
voice: CharacterVoice.Value
): Player = {
new Player(Avatar(0, name, faction, sex, head, voice))
}
"Player" should {
"construct" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.isAlive mustEqual false
obj.FacingYawUpper mustEqual 0
obj.Jumping mustEqual false
obj.Crouching mustEqual false
obj.Cloaked mustEqual false
obj.FacingYawUpper = 1.3f
obj.Jumping = true
obj.Crouching = true
obj.Cloaked = true
obj.FacingYawUpper mustEqual 1.3f
obj.Jumping mustEqual true
obj.Crouching mustEqual true
obj.Cloaked mustEqual true
}
"(re)spawn" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.isAlive mustEqual false
obj.Health mustEqual 0
obj.Armor mustEqual 0
obj.MaxHealth mustEqual 100
obj.MaxArmor mustEqual 50
obj.Spawn()
obj.isAlive mustEqual true
obj.Health mustEqual 100
obj.Armor mustEqual 50
}
"will not (re)spawn if not dead" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Spawn()
obj.Health mustEqual 100
obj.Armor mustEqual 50
obj.isAlive mustEqual true
obj.Health = 10
obj.Armor = 10
obj.Health mustEqual 10
obj.Armor mustEqual 10
obj.Spawn()
obj.Health mustEqual 10
obj.Armor mustEqual 10
}
"can die" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Spawn()
obj.Armor = 35 //50 -> 35
obj.isAlive mustEqual true
obj.Health mustEqual obj.MaxHealth
obj.Armor mustEqual 35
obj.Die
obj.isAlive mustEqual false
obj.Health mustEqual 0
obj.Armor mustEqual 35
}
"can not become a backpack if alive" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Spawn()
obj.isAlive mustEqual true
obj.isBackpack mustEqual false
obj.Release
obj.isAlive mustEqual true
obj.isBackpack mustEqual false
}
"can become a backpack" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.isAlive mustEqual false
obj.isBackpack mustEqual false
obj.Release
obj.isAlive mustEqual false
obj.isBackpack mustEqual true
}
"set new maximum values (health, stamina)" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.MaxHealth mustEqual 100
obj.MaxHealth = 123
obj.MaxHealth mustEqual 123
obj.MaxHealth = None
//MaxStamina has no equivalent
obj.MaxHealth mustEqual 100
}
// "set new values (health, armor, stamina) but only when alive" in {
// val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
// obj.Health = 23
// obj.Armor = 34
// obj.Stamina = 45
// obj.Health mustEqual 0
// obj.Armor mustEqual 0
// obj.Stamina mustEqual 0
//
// obj.Spawn()
// obj.Health mustEqual obj.MaxHealth
// obj.Armor mustEqual obj.MaxArmor
// obj.Stamina mustEqual obj.MaxStamina
// obj.Health = 23
// obj.Armor = 34
// obj.Stamina = 45
// obj.Health mustEqual 23
// obj.Armor mustEqual 34
// obj.Stamina mustEqual 45
// }
"has visible slots" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.VisibleSlots mustEqual Set(0, 2, 4) //Standard
obj.ExoSuit = ExoSuitType.Agile
obj.VisibleSlots mustEqual Set(0, 1, 2, 4)
obj.ExoSuit = ExoSuitType.Reinforced
obj.VisibleSlots mustEqual Set(0, 1, 2, 3, 4)
obj.ExoSuit = ExoSuitType.Infiltration
obj.VisibleSlots mustEqual Set(0, 4)
obj.ExoSuit = ExoSuitType.MAX
obj.VisibleSlots mustEqual Set(0)
}
"init (Standard Exo-Suit)" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.ExoSuit mustEqual ExoSuitType.Standard
obj.Slot(0).Size mustEqual EquipmentSize.Pistol
obj.Slot(1).Size mustEqual EquipmentSize.Blocked
obj.Slot(2).Size mustEqual EquipmentSize.Rifle
obj.Slot(3).Size mustEqual EquipmentSize.Blocked
obj.Slot(4).Size mustEqual EquipmentSize.Melee
obj.Inventory.Width mustEqual 9
obj.Inventory.Height mustEqual 6
obj.Inventory.Offset mustEqual 6
}
"draw equipped holsters only" in {
val wep = SimpleItem(SimpleItemDefinition(149))
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Slot(1).Size = EquipmentSize.Pistol
obj.Slot(1).Equipment = wep
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.DrawnSlot = 0
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
}
"remember the last drawn holster" in {
val wep1 = SimpleItem(SimpleItemDefinition(149))
val wep2 = SimpleItem(SimpleItemDefinition(149))
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Slot(0).Size = EquipmentSize.Pistol
obj.Slot(0).Equipment = wep1
obj.Slot(1).Size = EquipmentSize.Pistol
obj.Slot(1).Equipment = wep2
obj.DrawnSlot mustEqual Player.HandsDownSlot //default value
obj.LastDrawnSlot mustEqual Player.HandsDownSlot //default value
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
obj.LastDrawnSlot mustEqual 1
obj.DrawnSlot = 0
obj.DrawnSlot mustEqual 0
obj.LastDrawnSlot mustEqual 0
obj.DrawnSlot = Player.HandsDownSlot
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.LastDrawnSlot mustEqual 0
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
obj.LastDrawnSlot mustEqual 1
obj.DrawnSlot = 0
obj.DrawnSlot mustEqual 0
obj.LastDrawnSlot mustEqual 0
obj.DrawnSlot = 1
obj.DrawnSlot mustEqual 1
obj.LastDrawnSlot mustEqual 1
obj.DrawnSlot = Player.HandsDownSlot
obj.DrawnSlot mustEqual Player.HandsDownSlot
obj.LastDrawnSlot mustEqual 1
}
"hold something in their free hand" in {
val wep = SimpleItem(SimpleItemDefinition(149))
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
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 = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Slot(-1).Equipment = wep
obj.Slot(-1).Equipment.isEmpty mustEqual true
}
"search for the smallest available slot in which to store equipment" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Inventory.Resize(3, 3) //fits one item
obj.Fit(Tool(GlobalDefinitions.beamer)).contains(0) mustEqual true
obj.Fit(Tool(GlobalDefinitions.suppressor)).contains(2) mustEqual true
val ammo = AmmoBox(GlobalDefinitions.bullet_9mm)
val ammo2 = AmmoBox(GlobalDefinitions.bullet_9mm)
val ammo3 = AmmoBox(GlobalDefinitions.bullet_9mm)
obj.Fit(ammo).contains(6) mustEqual true
obj.Slot(6).Equipment = ammo
obj.Fit(ammo2).contains(Player.FreeHandSlot) mustEqual true
obj.Slot(Player.FreeHandSlot).Equipment = ammo2
obj.Fit(ammo3).isEmpty mustEqual true
}
"can use their free hand to hold things" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val ammo = AmmoBox(GlobalDefinitions.bullet_9mm)
obj.FreeHand.Equipment.isEmpty mustEqual true
obj.FreeHand.Equipment = ammo
obj.FreeHand.Equipment.contains(ammo) mustEqual true
}
"can access the player's locker-space" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Slot(5).Equipment.get.isInstanceOf[LockerEquipment] mustEqual true
}
"can find equipment" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Slot(0).Equipment = {
val item = Tool(beamer)
item.GUID = PlanetSideGUID(1)
item
}
obj.Slot(4).Equipment = {
val item = Tool(forceblade)
item.GUID = PlanetSideGUID(2)
item
}
obj.Slot(6).Equipment = {
val item = ConstructionItem(ace)
item.GUID = PlanetSideGUID(3)
item
}
obj.avatar.locker.Slot(6).Equipment = {
val item = Kit(medkit)
item.GUID = PlanetSideGUID(4)
item
}
obj.FreeHand.Equipment = {
val item = SimpleItem(remote_electronics_kit)
item.GUID = PlanetSideGUID(5)
item
}
obj.Find(PlanetSideGUID(1)).contains(0) mustEqual true //holsters
obj.Find(PlanetSideGUID(2)).contains(4) mustEqual true //holsters, melee
obj.Find(PlanetSideGUID(3)).contains(6) mustEqual true //inventory
obj.Find(PlanetSideGUID(4)).isEmpty mustEqual true //can not find in locker-space
obj.Find(PlanetSideGUID(5)).contains(Player.FreeHandSlot) mustEqual true //free hand
obj.Find(PlanetSideGUID(6)).isEmpty mustEqual true //not here
}
"does equipment collision checking (are we already holding something there?)" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val item1 = Tool(beamer)
val item2 = Kit(medkit)
val item3 = AmmoBox(GlobalDefinitions.bullet_9mm)
obj.Slot(0).Equipment = item1
obj.Slot(6).Equipment = item2
obj.FreeHand.Equipment = item3
obj.Collisions(0, 1, 1) match {
case Success(List(item)) =>
item.obj mustEqual item1
item.start mustEqual 0
case _ =>
ko
} //holsters
obj.Collisions(1, 1, 1) match {
case Success(List()) => ;
case _ =>
ko
} //holsters, nothing
obj.Collisions(6, 1, 1) match {
case Success(List(item)) =>
item.obj mustEqual item2
item.start mustEqual 6
case _ =>
ko
} //inventory
obj.Collisions(Player.FreeHandSlot, 1, 1) match {
case Success(List(item)) =>
item.obj mustEqual item3
item.start mustEqual Player.FreeHandSlot
case _ =>
ko
} //free hand
}
"seat in a vehicle" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.VehicleSeated.isEmpty mustEqual true
obj.VehicleSeated = PlanetSideGUID(65)
obj.VehicleSeated.contains(PlanetSideGUID(65)) mustEqual true
obj.VehicleSeated = None
obj.VehicleSeated.isEmpty mustEqual true
}
"own in a vehicle" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.avatar.vehicle.isEmpty mustEqual true
obj.avatar.vehicle = Some(PlanetSideGUID(65))
obj.avatar.vehicle.contains(PlanetSideGUID(65)) mustEqual true
obj.avatar.vehicle = None
obj.avatar.vehicle.isEmpty mustEqual true
}
"remember what zone he is in" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.Continent mustEqual "home2"
obj.Continent = "ugd01"
obj.Continent mustEqual "ugd01"
}
"special is typically normal and can not be changed from normal" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Shielded
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
}
"a TR MAX can change its special to Overdrive or Anchored" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.ExoSuit = ExoSuitType.MAX
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Anchored
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Overdrive
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Overdrive
//note
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Overdrive
}
"an NC MAX can change its special to Shielded" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.ExoSuit = ExoSuitType.MAX
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Shielded
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Shielded
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
}
"one faction can not use the other's specials" in {
val objtr = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
objtr.ExoSuit = ExoSuitType.MAX
objtr.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
objtr.UsingSpecial = SpecialExoSuitDefinition.Mode.Shielded
objtr.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
val objnc = TestPlayer("Chord", PlanetSideEmpire.NC, CharacterGender.Male, 0, CharacterVoice.Voice5)
objnc.ExoSuit = ExoSuitType.MAX
objnc.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
objnc.UsingSpecial = SpecialExoSuitDefinition.Mode.Overdrive
objnc.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
objnc.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
objnc.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
}
"changing exo-suit type resets the special to Normal (and changing back does not revert it again)" in {
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
obj.ExoSuit = ExoSuitType.MAX
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
obj.UsingSpecial = SpecialExoSuitDefinition.Mode.Anchored
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Anchored
val test = obj.UsingSpecial
obj.ExoSuit = ExoSuitType.Standard
obj.UsingSpecial mustEqual SpecialExoSuitDefinition.Mode.Normal
obj.ExoSuit = ExoSuitType.MAX
obj.UsingSpecial != test mustEqual true
}
}
}

View file

@ -0,0 +1,368 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.ballistics._
import net.psforever.objects.definition.ProjectileDefinition
import net.psforever.objects.serverobject.mblocker.Locker
import net.psforever.objects.vital.DamageType
import net.psforever.types.{PlanetSideGUID, _}
import org.specs2.mutable.Specification
class ProjectileTest extends Specification {
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val fury = Vehicle(GlobalDefinitions.fury)
"LocalProjectile" should {
"construct" in {
val obj = new LocalProjectile() //since they're just placeholders, they only need to construct
obj.Definition.ObjectId mustEqual 0
obj.Definition.Name mustEqual "projectile"
}
"local projectile range" in {
Projectile.baseUID < Projectile.rangeUID mustEqual true
}
}
"ProjectileDefinition" should {
"define (default)" in {
val obj = new ProjectileDefinition(31) //9mmbullet_projectile
obj.ProjectileType mustEqual Projectiles.bullet_9mm_projectile
obj.ObjectId mustEqual 31
obj.Damage0 mustEqual 0
obj.Damage1 mustEqual 0
obj.Damage2 mustEqual 0
obj.Damage3 mustEqual 0
obj.Damage4 mustEqual 0
obj.Acceleration mustEqual 0
obj.AccelerationUntil mustEqual 0f
obj.ProjectileDamageType mustEqual DamageType.None
obj.ProjectileDamageTypeSecondary mustEqual DamageType.None
obj.DegradeDelay mustEqual 1f
obj.DegradeMultiplier mustEqual 1f
obj.InitialVelocity mustEqual 1
obj.Lifespan mustEqual 1f
obj.DamageAtEdge mustEqual 1f
obj.DamageRadius mustEqual 1f
obj.UseDamage1Subtract mustEqual false
}
"define (custom)" in {
val obj = new ProjectileDefinition(31) //9mmbullet_projectile
obj.Damage0 = 2
obj.Damage1 = 4
obj.Damage2 = 8
obj.Damage3 = 16
obj.Damage4 = 32
obj.Acceleration = 5
obj.AccelerationUntil = 5.5f
obj.ProjectileDamageType = DamageType.Splash
obj.ProjectileDamageTypeSecondary = DamageType.Radiation
obj.DegradeDelay = 11.1f
obj.DegradeMultiplier = 22.2f
obj.InitialVelocity = 50
obj.Lifespan = 11.2f
obj.DamageAtEdge = 3f
obj.DamageRadius = 3f
obj.UseDamage1Subtract = true
obj.Damage0 mustEqual 2
obj.Damage1 mustEqual 4
obj.Damage2 mustEqual 8
obj.Damage3 mustEqual 16
obj.Damage4 mustEqual 32
obj.Acceleration mustEqual 5
obj.AccelerationUntil mustEqual 5.5f
obj.ProjectileDamageType mustEqual DamageType.Splash
obj.ProjectileDamageTypeSecondary mustEqual DamageType.Radiation
obj.DegradeDelay mustEqual 11.1f
obj.DegradeMultiplier mustEqual 22.2f
obj.InitialVelocity mustEqual 50
obj.Lifespan mustEqual 11.2f
obj.DamageAtEdge mustEqual 3f
obj.DamageRadius mustEqual 3f
obj.UseDamage1Subtract mustEqual true
}
"define (failure)" in {
Projectiles(31) mustEqual Projectiles.bullet_9mm_projectile
try {
ProjectileDefinition(Projectiles.bullet_9mm_projectile) //passes
} catch {
case _: NoSuchElementException =>
ko
}
Projectiles(2) must throwA[NoSuchElementException]
new ProjectileDefinition(2) must throwA[NoSuchElementException]
}
"cascade damage values" in {
val obj = new ProjectileDefinition(31) //9mmbullet_projectile
obj.Damage4 = 32
obj.Damage3 = 16
obj.Damage2 = 8
obj.Damage1 = 4
obj.Damage0 = 2
//initial
obj.Damage4 mustEqual 32
obj.Damage3 mustEqual 16
obj.Damage2 mustEqual 8
obj.Damage1 mustEqual 4
obj.Damage0 mustEqual 2
//negate Damage4
obj.Damage4 = None
obj.Damage4 mustEqual 16
obj.Damage3 mustEqual 16
obj.Damage2 mustEqual 8
obj.Damage1 mustEqual 4
obj.Damage0 mustEqual 2
//negate Damage3
obj.Damage3 = None
obj.Damage4 mustEqual 8
obj.Damage3 mustEqual 8
obj.Damage2 mustEqual 8
obj.Damage1 mustEqual 4
obj.Damage0 mustEqual 2
//negate Damage2
obj.Damage2 = None
obj.Damage4 mustEqual 4
obj.Damage3 mustEqual 4
obj.Damage2 mustEqual 4
obj.Damage1 mustEqual 4
obj.Damage0 mustEqual 2
//negate Damage1
obj.Damage1 = None
obj.Damage4 mustEqual 2
obj.Damage3 mustEqual 2
obj.Damage2 mustEqual 2
obj.Damage1 mustEqual 2
obj.Damage0 mustEqual 2
//negate Damage0
obj.Damage0 = None
obj.Damage4 mustEqual 0
obj.Damage3 mustEqual 0
obj.Damage2 mustEqual 0
obj.Damage1 mustEqual 0
obj.Damage0 mustEqual 0
//set Damage3, set Damage0
obj.Damage3 = 13
obj.Damage0 = 7
obj.Damage4 mustEqual 13
obj.Damage3 mustEqual 13
obj.Damage2 mustEqual 7
obj.Damage1 mustEqual 7
obj.Damage0 mustEqual 7
}
}
"SourceEntry" should {
"construct for players" in {
SourceEntry(player) match {
case o: PlayerSource =>
o.Name mustEqual "TestCharacter"
o.Faction mustEqual PlanetSideEmpire.TR
o.Seated mustEqual false
o.ExoSuit mustEqual ExoSuitType.Standard
o.Health mustEqual 0
o.Armor mustEqual 0
o.Definition mustEqual GlobalDefinitions.avatar
o.Position mustEqual Vector3.Zero
o.Orientation mustEqual Vector3.Zero
o.Velocity mustEqual None
case _ =>
ko
}
}
"construct for vehicles" in {
SourceEntry(fury) match {
case o: VehicleSource =>
o.Name mustEqual "Fury"
o.Faction mustEqual PlanetSideEmpire.NEUTRAL
o.Definition mustEqual GlobalDefinitions.fury
o.Health mustEqual 650
o.Shields mustEqual 0
o.Position mustEqual Vector3.Zero
o.Orientation mustEqual Vector3.Zero
o.Velocity mustEqual None
case _ =>
ko
}
}
"construct for generic object" in {
val obj = Locker()
SourceEntry(obj) match {
case o: ObjectSource =>
o.obj mustEqual obj
o.Name mustEqual "Mb Locker"
o.Faction mustEqual PlanetSideEmpire.NEUTRAL
o.Definition mustEqual GlobalDefinitions.mb_locker
o.Position mustEqual Vector3.Zero
o.Orientation mustEqual Vector3.Zero
o.Velocity mustEqual None
case _ =>
ko
}
}
"contain timely information" in {
val obj =
Player(Avatar(0, "TestCharacter-alt", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
obj.VehicleSeated = Some(PlanetSideGUID(1))
obj.Position = Vector3(1.2f, 3.4f, 5.6f)
obj.Orientation = Vector3(2.1f, 4.3f, 6.5f)
obj.Velocity = Some(Vector3(1.1f, 2.2f, 3.3f))
val sobj = SourceEntry(obj)
obj.VehicleSeated = None
obj.Position = Vector3.Zero
obj.Orientation = Vector3.Zero
obj.Velocity = None
obj.ExoSuit = ExoSuitType.Agile
sobj match {
case o: PlayerSource =>
o.Name mustEqual "TestCharacter-alt"
o.Faction mustEqual PlanetSideEmpire.TR
o.Seated mustEqual true
o.ExoSuit mustEqual ExoSuitType.Standard
o.Definition mustEqual GlobalDefinitions.avatar
o.Position mustEqual Vector3(1.2f, 3.4f, 5.6f)
o.Orientation mustEqual Vector3(2.1f, 4.3f, 6.5f)
o.Velocity mustEqual Some(Vector3(1.1f, 2.2f, 3.3f))
case _ =>
ko
}
}
}
"Projectile" should {
val beamer_def = GlobalDefinitions.beamer
val beamer_wep = Tool(beamer_def)
val firemode = beamer_wep.FireMode
val projectile = beamer_wep.Projectile
"construct" in {
val obj = Projectile(
beamer_wep.Projectile,
beamer_wep.Definition,
beamer_wep.FireMode,
PlayerSource(player),
beamer_def.ObjectId,
Vector3(1.2f, 3.4f, 5.6f),
Vector3(0.2f, 0.4f, 0.6f)
)
obj.profile mustEqual projectile
obj.tool_def mustEqual beamer_def
obj.fire_mode mustEqual firemode
obj.owner match {
case _: PlayerSource =>
ok
case _ =>
ko
}
obj.attribute_to mustEqual obj.tool_def.ObjectId
obj.shot_origin mustEqual Vector3(1.2f, 3.4f, 5.6f)
obj.shot_angle mustEqual Vector3(0.2f, 0.4f, 0.6f)
obj.fire_time <= System.nanoTime mustEqual true
obj.isResolved mustEqual false
}
"construct (different attribute)" in {
val obj1 = Projectile(
beamer_wep.Projectile,
beamer_wep.Definition,
beamer_wep.FireMode,
player,
Vector3(1.2f, 3.4f, 5.6f),
Vector3(0.2f, 0.4f, 0.6f)
)
obj1.attribute_to mustEqual obj1.tool_def.ObjectId
val obj2 = Projectile(
beamer_wep.Projectile,
beamer_wep.Definition,
beamer_wep.FireMode,
PlayerSource(player),
65,
Vector3(1.2f, 3.4f, 5.6f),
Vector3(0.2f, 0.4f, 0.6f)
)
obj2.attribute_to == obj2.tool_def.ObjectId mustEqual false
obj2.attribute_to mustEqual 65
}
"resolve" in {
val obj = Projectile(
projectile,
beamer_def,
firemode,
PlayerSource(player),
beamer_def.ObjectId,
Vector3.Zero,
Vector3.Zero
)
obj.isResolved mustEqual false
obj.isMiss mustEqual false
obj.Resolve()
obj.isResolved mustEqual true
obj.isMiss mustEqual false
}
"missed" in {
val obj = Projectile(
projectile,
beamer_def,
firemode,
PlayerSource(player),
beamer_def.ObjectId,
Vector3.Zero,
Vector3.Zero
)
obj.isResolved mustEqual false
obj.isMiss mustEqual false
obj.Miss()
obj.isResolved mustEqual true
obj.isMiss mustEqual true
}
}
"ResolvedProjectile" should {
val beamer_wep = Tool(GlobalDefinitions.beamer)
val p_source = PlayerSource(player)
val player2 = Player(Avatar(0, "TestTarget", PlanetSideEmpire.NC, CharacterGender.Female, 1, CharacterVoice.Mute))
val p2_source = PlayerSource(player2)
val projectile = Projectile(
beamer_wep.Projectile,
GlobalDefinitions.beamer,
beamer_wep.FireMode,
p_source,
GlobalDefinitions.beamer.ObjectId,
Vector3.Zero,
Vector3.Zero
)
val fury_dm = fury.DamageModel
"construct" in {
val obj = ResolvedProjectile(
ProjectileResolution.Hit,
projectile,
PlayerSource(player2),
fury_dm,
Vector3(1.2f, 3.4f, 5.6f)
)
obj.resolution mustEqual ProjectileResolution.Hit
obj.projectile mustEqual projectile
obj.target mustEqual p2_source
obj.damage_model mustEqual fury.DamageModel
obj.hit_pos mustEqual Vector3(1.2f, 3.4f, 5.6f)
}
}
}

View file

@ -0,0 +1,444 @@
// Copyright (c) 2020 PSForever
package objects
import akka.actor.Props
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl}
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretControl}
import net.psforever.objects.vehicles.VehicleControl
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.{InventoryStateMessage, RepairMessage}
import net.psforever.types._
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.concurrent.duration._
/*
the generator is used to test basic entity repair
essentially, treat it more as a generic entity whose object type is repairable
see GeneratorTest in relation to what the generator does above and beyond that during repair
*/
class RepairableEntityRepairTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
val gen = Generator(GlobalDefinitions.generator) //guid=2
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val buildingProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
building.Actor = buildingProbe.ref
val tool = Tool(GlobalDefinitions.nano_dispenser) //4 & 5
guid.register(tool, 4)
guid.register(tool.AmmoSlot.Box, 5)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"RepairableEntity" should {
"handle repairs" in {
assert(gen.Health == gen.Definition.DefaultHealth) //ideal
val originalHealth = gen.Health -= 50
assert(gen.Health < gen.Definition.DefaultHealth) //damage
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair
val msg123 = avatarProbe.receiveN(3, 500 milliseconds)
assert(
msg123.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction
.SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(5), _, PlanetSideGUID(4), _))
) =>
true
case _ => false
}
)
assert(
msg123(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg123(2) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
) =>
true
case _ => false
}
)
assert(originalHealth < gen.Health) //generator repaired a bit
}
}
}
class RepairableEntityNotRepairTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
val gen = Generator(GlobalDefinitions.generator) //guid=2
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
guid.register(building, 1)
guid.register(gen, 2)
guid.register(player1, 3)
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = gen
gen.Position = Vector3(1, 0, 0)
gen.Actor = system.actorOf(Props(classOf[GeneratorControl], gen), "generator-control")
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val buildingProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
building.Actor = buildingProbe.ref
val tool = Tool(GlobalDefinitions.nano_dispenser) //4 & 5
guid.register(tool, 4)
guid.register(tool.AmmoSlot.Box, 5)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"RepairableEntity" should {
"not repair if health is already full" in {
assert(gen.Health == gen.Definition.DefaultHealth) //ideal
gen.Actor ! CommonMessages.Use(player1, Some(tool)) //repair?
avatarProbe.expectNoMessage(1000 milliseconds) //no messages
}
}
}
class RepairableAmenityTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
val term = Terminal(GlobalDefinitions.order_terminal) //guid=2
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
guid.register(building, 1)
guid.register(term, 2)
guid.register(player1, 3)
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = term
term.Position = Vector3(1, 0, 0)
term.Actor = system.actorOf(Props(classOf[TerminalControl], term), "terminal-control")
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val buildingProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
building.Actor = buildingProbe.ref
val tool = Tool(GlobalDefinitions.nano_dispenser) //4 & 5
guid.register(tool, 4)
guid.register(tool.AmmoSlot.Box, 5)
expectNoMessage(200 milliseconds)
//we're not testing that the math is correct
"RepairableAmenity" should {
"send initialization messages upon restoration" in {
//the decimator does enough damage to one-shot this terminal from any initial health
val originalHealth = term.Health = term.Definition.RepairRestoresAt - 1 //initial state manip
term.Destroyed = true
assert(originalHealth < term.Definition.RepairRestoresAt)
assert(term.Destroyed)
term.Actor ! CommonMessages.Use(player1, Some(tool))
val msg12345 = avatarProbe.receiveN(5, 500 milliseconds)
assert(
msg12345.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction
.SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(5), _, PlanetSideGUID(4), _))
) =>
true
case _ => false
}
)
assert(
msg12345(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
assert(
msg12345(2) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 50, 0)) => true
case _ => false
}
)
assert(
msg12345(3) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 51, 0)) => true
case _ => false
}
)
assert(
msg12345(4) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
) =>
true
case _ => false
}
)
assert(term.Health > term.Definition.RepairRestoresAt)
assert(!term.Destroyed)
}
}
}
class RepairableTurretWeapon extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = Building("test-building", 1, 1, zone, StructureType.Facility) //guid=1
val activityProbe = TestProbe()
val avatarProbe = TestProbe()
val vehicleProbe = TestProbe()
val buildingProbe = TestProbe()
zone.Activity = activityProbe.ref
zone.AvatarEvents = avatarProbe.ref
zone.VehicleEvents = vehicleProbe.ref
building.Actor = buildingProbe.ref
val turret = new FacilityTurret(GlobalDefinitions.manned_turret) //2, 5, 6
turret.Actor = system.actorOf(Props(classOf[FacilityTurretControl], turret), "turret-control")
turret.Zone = zone
turret.Position = Vector3(1, 0, 0)
val turretWeapon = turret.Weapons.values.head.Equipment.get.asInstanceOf[Tool]
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=3
player1.Spawn()
player1.Position = Vector3(2, 2, 2)
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
guid.register(building, 1)
guid.register(turret, 2)
guid.register(player1, 3)
guid.register(turretWeapon, 5)
guid.register(turretWeapon.AmmoSlot.Box, 6)
building.Position = Vector3(1, 0, 0)
building.Zone = zone
building.Amenities = turret
val tool = Tool(GlobalDefinitions.nano_dispenser) //7 & 8
guid.register(tool, 7)
guid.register(tool.AmmoSlot.Box, 8)
"RepairableTurretWeapon" should {
"handle repairs and restoration" in {
turret.Health = turret.Definition.RepairRestoresAt - 1 //initial state manip
turret.Destroyed = true //initial state manip
assert(turret.Health < turret.Definition.RepairRestoresAt)
assert(turret.Destroyed)
turret.Actor ! CommonMessages.Use(player1, Some(tool))
val msg12345 = avatarProbe.receiveN(5, 500 milliseconds)
val msg4 = vehicleProbe.receiveOne(500 milliseconds)
assert(
msg12345.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction
.SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(8), _, PlanetSideGUID(7), _))
) =>
true
case _ => false
}
)
assert(
msg12345(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(2), 0, _)) => true
case _ => false
}
)
//msg12345(2) and msg12345(3) are related to RepairableAmenity
assert(
msg12345(4) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(2), _))
) =>
true
case _ => false
}
)
assert(
msg4 match {
case VehicleServiceMessage("test", VehicleAction.EquipmentInSlot(_, PlanetSideGUID(2), 1, t))
if t eq turretWeapon =>
true
case _ => false
}
)
assert(turret.Health > turret.Definition.RepairRestoresAt)
assert(!turret.Destroyed)
}
}
}
class RepairableVehicleRepair extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val atv = Vehicle(GlobalDefinitions.quadassault) //guid=1, 2, 3
atv.Actor = system.actorOf(Props(classOf[VehicleControl], atv), "vehicle-control")
atv.Position = Vector3(1, 0, 0)
val atvWeapon = atv.Weapons(1).Equipment.get.asInstanceOf[Tool]
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=4
player1.Spawn()
player1.Position = Vector3(2, 2, 2)
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
guid.register(atv, 1)
guid.register(atvWeapon, 2)
guid.register(atvWeapon.AmmoSlot.Box, 3)
guid.register(player1, 4)
atv.Zone = zone
val tool = Tool(GlobalDefinitions.nano_dispenser) //5 & 6
guid.register(tool, 5)
guid.register(tool.AmmoSlot.Box, 6)
"RepairableVehicle" should {
"handle repairs" in {
val originalHealth = atv.Health = atv.Definition.DamageDestroysAt + 1 //initial state manip
assert(atv.Health == originalHealth)
atv.Actor ! CommonMessages.Use(player1, Some(tool))
val msg123 = avatarProbe.receiveN(3, 500 milliseconds)
assert(
msg123.head match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction
.SendResponse(PlanetSideGUID(0), InventoryStateMessage(PlanetSideGUID(6), _, PlanetSideGUID(5), _))
) =>
true
case _ => false
}
)
assert(
msg123(1) match {
case AvatarServiceMessage("test", AvatarAction.PlanetsideAttributeToAll(PlanetSideGUID(1), 0, _)) => true
case _ => false
}
)
assert(
msg123(2) match {
case AvatarServiceMessage(
"TestCharacter1",
AvatarAction.SendResponse(PlanetSideGUID(0), RepairMessage(PlanetSideGUID(1), _))
) =>
true
case _ => false
}
)
assert(atv.Health > originalHealth)
}
}
}
class RepairableVehicleRestoration extends ActorTest {
/*
no messages are dispatched, in this case, because most vehicles are flagged to not be repairable if destroyed
*/
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val zone = new Zone("test", new ZoneMap("test"), 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val avatarProbe = TestProbe()
zone.AvatarEvents = avatarProbe.ref
val atv = Vehicle(GlobalDefinitions.quadassault) //guid=1, 2, 3
atv.Actor = system.actorOf(Props(classOf[VehicleControl], atv), "vehicle-control")
atv.Position = Vector3(1, 0, 0)
val atvWeapon = atv.Weapons(1).Equipment.get.asInstanceOf[Tool]
val player1 =
Player(Avatar(0, "TestCharacter1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)) //guid=4
player1.Spawn()
player1.Position = Vector3(2, 2, 2)
val player1Probe = TestProbe()
player1.Actor = player1Probe.ref
guid.register(atv, 1)
guid.register(atvWeapon, 2)
guid.register(atvWeapon.AmmoSlot.Box, 3)
guid.register(player1, 4)
atv.Zone = zone
val tool = Tool(GlobalDefinitions.nano_dispenser) //5 & 6
guid.register(tool, 5)
guid.register(tool.AmmoSlot.Box, 6)
"RepairableVehicle" should {
"will not restore a destroyed vehicle to working order" in {
atv.Health = atv.Definition.DamageDestroysAt - 1 //initial state manip
atv.Destroyed = true //initial state manip
assert(atv.Health <= atv.Definition.DamageDestroysAt)
assert(atv.Destroyed)
atv.Actor ! CommonMessages.Use(player1, Some(tool))
avatarProbe.expectNoMessage(500 milliseconds)
assert(atv.Health == 0) //set to zero explicitly
assert(atv.Destroyed)
}
}
}
object RepairableTest {}

View file

@ -0,0 +1,395 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, Props}
import akka.routing.RandomPool
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
import net.psforever.objects.guid.{NumberPoolHub, TaskResolver}
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.{GlobalDefinitions, Ntu, Player, Vehicle}
import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.transfer.TransferBehavior
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.packet.game.UseItemMessage
import net.psforever.types._
import org.specs2.mutable.Specification
import net.psforever.services.ServiceManager
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import akka.actor.typed.scaladsl.adapter._
import net.psforever.objects.avatar.Avatar
import scala.concurrent.duration._
class ResourceSiloTest extends Specification {
"Resource Silo" should {
"define" in {
val obj = new ResourceSiloDefinition
obj.ObjectId mustEqual 731
}
"construct" in {
val obj = ResourceSilo()
obj.Definition mustEqual GlobalDefinitions.resource_silo
obj.MaxNtuCapacitor mustEqual 1000
obj.NtuCapacitor mustEqual 0
obj.LowNtuWarningOn mustEqual true
obj.CapacitorDisplay mustEqual 0
//
obj.NtuCapacitor = 50
obj.LowNtuWarningOn = false
obj.NtuCapacitor mustEqual 50
obj.LowNtuWarningOn mustEqual false
obj.CapacitorDisplay mustEqual 1
}
"charge level can not exceed limits(0 to maximum)" in {
val obj = ResourceSilo()
obj.NtuCapacitor mustEqual 0
obj.NtuCapacitor = -5
obj.NtuCapacitor mustEqual 0
obj.NtuCapacitor = obj.MaxNtuCapacitor + 100
obj.NtuCapacitor mustEqual 1000
obj.NtuCapacitor mustEqual obj.MaxNtuCapacitor
}
"using the silo generates a charge event" in {
val msg = UseItemMessage(
PlanetSideGUID(1),
PlanetSideGUID(0),
PlanetSideGUID(2),
0L,
false,
Vector3(0f, 0f, 0f),
Vector3(0f, 0f, 0f),
0,
0,
0,
0L
) //faked
ResourceSilo().Use(ResourceSiloTest.player, msg) mustEqual ResourceSilo.ChargeEvent()
}
}
}
class ResourceSiloControlStartupTest extends ActorTest {
val serviceManager = ServiceManager.boot(system)
serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]()), "taskResolver")
val obj = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
val probe = TestProbe()
serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe), "avatar")
"Resource silo" should {
"startup properly" in {
expectNoMessage(500 milliseconds)
system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
expectNoMessage(1 seconds)
}
}
}
class ResourceSiloControlUseTest extends ActorTest {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val map = new ZoneMap("test")
val zone = new Zone("test", map, 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
zone.actor = system.spawnAnonymous(ZoneActor(zone))
val building = new Building(
"Building",
building_guid = 0,
map_id = 0,
zone,
StructureType.Building,
GlobalDefinitions.building
) //guid=1
val obj = ResourceSilo() //guid=2
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
obj.Owner = building
obj.Actor ! "startup"
val player = Player(
new Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)
) //guid=3
val vehicle = Vehicle(GlobalDefinitions.ant) //guid=4
val probe = new TestProbe(system)
guid.register(building, 1)
guid.register(obj, 2)
guid.register(player, 3)
guid.register(vehicle, 4)
expectNoMessage(200 milliseconds)
zone.Transport ! Zone.Vehicle.Spawn(vehicle)
vehicle.Seats(0).Occupant = player
player.VehicleSeated = vehicle.GUID
expectNoMessage(200 milliseconds)
system.stop(vehicle.Actor)
vehicle.Actor = probe.ref
"Resource silo" should {
"respond when being used" in {
expectNoMessage(1 seconds)
obj.Actor ! CommonMessages.Use(ResourceSiloTest.player)
val reply = probe.receiveOne(2000 milliseconds)
assert(reply match {
case TransferBehavior.Discharging(Ntu.Nanites) => true
case _ => false
})
}
}
}
class ResourceSiloControlNtuWarningTest extends ActorTest {
val obj = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
obj.Actor ! "startup"
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
obj.Owner =
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
obj.Owner.GUID = PlanetSideGUID(6)
val zoneEvents = TestProbe("zone-events")
"Resource silo" should {
"announce high ntu" in {
zone.AvatarEvents = zoneEvents.ref
assert(obj.LowNtuWarningOn)
obj.Actor ! ResourceSilo.LowNtuWarning(false)
val reply = zoneEvents.receiveOne(500 milliseconds)
assert(!obj.LowNtuWarningOn)
assert(reply.isInstanceOf[AvatarServiceMessage])
assert(reply.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
assert(reply.asInstanceOf[AvatarServiceMessage].actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
assert(
reply
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.player_guid == PlanetSideGUID(6)
)
assert(
reply
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.attribute_type == 47
)
assert(
reply
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.attribute_value == 0
)
}
}
}
class ResourceSiloControlUpdate1Test extends ActorTest {
val obj = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
obj.Actor ! "startup"
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
val bldg =
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
bldg.GUID = PlanetSideGUID(6)
obj.Owner = bldg
val zoneEvents = TestProbe("zone-events")
val buildingEvents = TestProbe("building-events")
"Resource silo" should {
"update the charge level and capacitor display (report high ntu, power restored)" in {
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
assert(obj.NtuCapacitor == 0)
assert(obj.CapacitorDisplay == 0)
assert(obj.LowNtuWarningOn)
obj.Actor ! ResourceSilo.UpdateChargeLevel(305)
val reply1 = zoneEvents.receiveOne(500 milliseconds)
val reply2 = buildingEvents.receiveOne(500 milliseconds)
assert(obj.NtuCapacitor == 305)
assert(obj.CapacitorDisplay == 4)
assert(reply1 match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(1), 45, 4)) => true
case _ => false
})
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
val reply3 = zoneEvents.receiveOne(500 milliseconds)
assert(!obj.LowNtuWarningOn)
assert(reply3 match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 47, 0)) => true
case _ => false
})
val reply4 = zoneEvents.receiveOne(500 milliseconds)
assert(reply4 match {
case AvatarServiceMessage("nowhere", AvatarAction.PlanetsideAttribute(PlanetSideGUID(6), 48, 0)) => true
case _ => false
})
}
}
}
class ResourceSiloControlUpdate2Test extends ActorTest {
val obj = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
obj.Actor ! "startup"
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
val bldg =
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
bldg.GUID = PlanetSideGUID(6)
obj.Owner = bldg
val zoneEvents = TestProbe("zone-events")
val buildingEvents = TestProbe("building-events")
"Resource silo" should {
"update the charge level and capacitor display (report good ntu)" in {
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
obj.NtuCapacitor = 100
obj.LowNtuWarningOn = true
assert(obj.NtuCapacitor == 100)
assert(obj.CapacitorDisplay == 1)
assert(obj.LowNtuWarningOn)
obj.Actor ! ResourceSilo.UpdateChargeLevel(105)
val reply1 = zoneEvents.receiveOne(1000 milliseconds)
val reply2 = buildingEvents.receiveOne(1000 milliseconds)
assert(obj.NtuCapacitor == 205)
assert(obj.CapacitorDisplay == 3)
assert(reply1.isInstanceOf[AvatarServiceMessage])
assert(reply1.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
assert(reply1.asInstanceOf[AvatarServiceMessage].actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
assert(
reply1
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.player_guid == PlanetSideGUID(1)
)
assert(
reply1
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.attribute_type == 45
)
assert(
reply1
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.attribute_value == 3
)
assert(reply2.isInstanceOf[BuildingActor.MapUpdate])
val reply3 = zoneEvents.receiveOne(500 milliseconds)
assert(!obj.LowNtuWarningOn)
assert(reply3.isInstanceOf[AvatarServiceMessage])
assert(reply3.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
assert(reply3.asInstanceOf[AvatarServiceMessage].actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
assert(
reply3
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.player_guid == PlanetSideGUID(6)
)
assert(
reply3
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.attribute_type == 47
)
assert(
reply3
.asInstanceOf[AvatarServiceMessage]
.actionMessage
.asInstanceOf[AvatarAction.PlanetsideAttribute]
.attribute_value == 0
)
}
}
}
class ResourceSiloControlNoUpdateTest extends ActorTest {
val obj = ResourceSilo()
obj.GUID = PlanetSideGUID(1)
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
obj.Actor ! "startup"
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
val bldg =
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
bldg.GUID = PlanetSideGUID(6)
obj.Owner = bldg
val zoneEvents = TestProbe("zone-events")
val buildingEvents = TestProbe("building-events")
"Resource silo" should {
"update, but not sufficiently to change the capacitor display" in {
zone.AvatarEvents = zoneEvents.ref
bldg.Actor = buildingEvents.ref
obj.NtuCapacitor = 250
obj.LowNtuWarningOn = false
assert(obj.NtuCapacitor == 250)
assert(obj.CapacitorDisplay == 3)
assert(!obj.LowNtuWarningOn)
obj.Actor ! ResourceSilo.UpdateChargeLevel(50)
expectNoMessage(500 milliseconds)
zoneEvents.expectNoMessage(500 milliseconds)
buildingEvents.expectNoMessage(500 milliseconds)
assert(
obj.NtuCapacitor == 299 || obj.NtuCapacitor == 300
) // Just in case the capacitor level drops while waiting for the message check 299 & 300
assert(obj.CapacitorDisplay == 3)
assert(!obj.LowNtuWarningOn)
}
}
}
object ResourceSiloTest {
val player = Player(
new Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)
)
class ProbedAvatarService(probe: TestProbe) extends Actor {
override def receive: Receive = {
case msg =>
probe.ref ! msg
}
}
class ProbedBuildingControl(probe: TestProbe) extends Actor {
override def receive: Receive = {
case msg =>
probe.ref ! msg
}
}
class ProbedResourceSiloControl(silo: ResourceSilo, probe: TestProbe) extends ResourceSiloControl(silo) {
override def receive: Receive = {
case msg =>
super.receive.apply(msg)
probe.ref ! msg
}
}
}

View file

@ -0,0 +1,371 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, ActorContext, Props}
import base.ActorTest
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.serverobject.ServerObjectBuilder
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType, WarpGate}
import net.psforever.objects.serverobject.terminals.ProximityTerminal
import net.psforever.objects.zones.Zone
import net.psforever.types.{PlanetSideGUID, Vector3}
import scala.concurrent.duration.Duration
class BuildingBuilderTest extends ActorTest {
"Building object" should {
"build" in {
val structure: (String, Int, Int, Zone, ActorContext) => Building = Building.Structure(StructureType.Building)
val actor = system.actorOf(
Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, "Building", 10, 10, Zone.Nowhere),
"building"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Building])
assert(reply.asInstanceOf[Building].MapId == 10)
assert(reply.asInstanceOf[Building].Zone == Zone.Nowhere)
}
}
}
class WarpGateBuilderTest extends ActorTest {
"WarpGate object" should {
"build" in {
val structure: (String, Int, Int, Zone, ActorContext) => Building = WarpGate.Structure
val actor = system.actorOf(
Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, "wgate", 10, 10, Zone.Nowhere),
"wgate"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Building])
assert(reply.asInstanceOf[Building].MapId == 10)
assert(reply.asInstanceOf[Building].Zone == Zone.Nowhere)
}
}
}
class DoorObjectBuilderTest1 extends ActorTest {
import net.psforever.objects.serverobject.doors.Door
"Door object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Door.Constructor), hub),
"door"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Door])
assert(reply.asInstanceOf[Door].HasGUID)
assert(reply.asInstanceOf[Door].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class DoorObjectBuilderTest2 extends ActorTest {
import net.psforever.objects.serverobject.doors.Door
"Door object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, Door.Constructor(Vector3(1, 2, 3))),
hub
),
"door"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Door])
assert(reply.asInstanceOf[Door].Position == Vector3(1, 2, 3))
assert(reply.asInstanceOf[Door].HasGUID)
assert(reply.asInstanceOf[Door].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class IFFLockObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.locks.IFFLock
"IFFLock object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, IFFLock.Constructor(Vector3(0f, 0f, 0f), Vector3(0f, 0f, 0f))),
hub
),
"lock"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[IFFLock])
assert(reply.asInstanceOf[IFFLock].HasGUID)
assert(reply.asInstanceOf[IFFLock].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class ImplantTerminalMechObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
"Implant terminal mech object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, ImplantTerminalMech.Constructor(Vector3.Zero)),
hub
),
"mech"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[ImplantTerminalMech])
assert(reply.asInstanceOf[ImplantTerminalMech].HasGUID)
assert(reply.asInstanceOf[ImplantTerminalMech].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class TerminalObjectBuilderTest extends ActorTest {
import net.psforever.objects.GlobalDefinitions.order_terminal
import net.psforever.objects.serverobject.terminals.Terminal
"Terminal object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, Terminal.Constructor(Vector3(1.1f, 2.2f, 3.3f), order_terminal)),
hub
),
"term"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Terminal])
assert(reply.asInstanceOf[Terminal].HasGUID)
assert(reply.asInstanceOf[Terminal].GUID == PlanetSideGUID(1))
assert(reply.asInstanceOf[Terminal].Position == Vector3(1.1f, 2.2f, 3.3f))
assert(reply == hub(1).get)
}
}
}
class ProximityTerminalObjectBuilderTest extends ActorTest {
import net.psforever.objects.GlobalDefinitions.medical_terminal
import net.psforever.objects.serverobject.terminals.Terminal
"Terminal object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, ProximityTerminal.Constructor(medical_terminal)),
hub
),
"term"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Terminal])
assert(reply.asInstanceOf[Terminal].HasGUID)
assert(reply.asInstanceOf[Terminal].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class VehicleSpawnPadObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
"Vehicle spawn pad object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(
1,
VehicleSpawnPad
.Constructor(Vector3(1.1f, 2.2f, 3.3f), GlobalDefinitions.mb_pad_creation, Vector3(4.4f, 5.5f, 6.6f))
),
hub
),
"pad"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[VehicleSpawnPad])
assert(reply.asInstanceOf[VehicleSpawnPad].HasGUID)
assert(reply.asInstanceOf[VehicleSpawnPad].GUID == PlanetSideGUID(1))
assert(reply.asInstanceOf[VehicleSpawnPad].Position == Vector3(1.1f, 2.2f, 3.3f))
assert(reply.asInstanceOf[VehicleSpawnPad].Orientation == Vector3(4.4f, 5.5f, 6.6f))
assert(reply == hub(1).get)
}
}
}
class LocalProjectileBuilderTest extends ActorTest {
import net.psforever.objects.LocalProjectile
"Local projectile object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, LocalProjectile.Constructor),
hub
),
"locker"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[LocalProjectile])
assert(reply.asInstanceOf[LocalProjectile].HasGUID)
assert(reply.asInstanceOf[LocalProjectile].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class LockerObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.mblocker.Locker
"Locker object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Locker.Constructor), hub),
"locker"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Locker])
assert(reply.asInstanceOf[Locker].HasGUID)
assert(reply.asInstanceOf[Locker].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class ResourceSiloObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
"Resource silo object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, ResourceSilo.Constructor(Vector3(0f, 0f, 0f))),
hub
),
"resource-silo"
)
actor ! "startup"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[ResourceSilo])
assert(reply.asInstanceOf[ResourceSilo].HasGUID)
assert(reply.asInstanceOf[ResourceSilo].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
class SpawnTubeObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.tube.SpawnTube
"Spawn tube object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, SpawnTube.Constructor(Vector3(3980.4062f, 4267.3047f, 257.5625f), Vector3(0, 0, 90))),
hub
),
"spawn-tube"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[SpawnTube])
assert(reply.asInstanceOf[SpawnTube].HasGUID)
assert(reply.asInstanceOf[SpawnTube].GUID == PlanetSideGUID(1))
assert(reply.asInstanceOf[SpawnTube].Position == Vector3(3980.4062f, 4267.3047f, 257.5625f))
assert(reply.asInstanceOf[SpawnTube].Orientation == Vector3(0, 0, 90))
assert(reply == hub(1).get)
}
}
}
class FacilityTurretObjectBuilderTest extends ActorTest {
import net.psforever.objects.GlobalDefinitions.manned_turret
import net.psforever.objects.serverobject.turret.FacilityTurret
"FacilityTurretObjectBuilder" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(
Props(
classOf[ServerObjectBuilderTest.BuilderTestActor],
ServerObjectBuilder(1, FacilityTurret.Constructor(manned_turret)),
hub
),
"manned-turret"
)
actor ! "!"
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[FacilityTurret])
assert(reply.asInstanceOf[FacilityTurret].HasGUID)
assert(reply.asInstanceOf[FacilityTurret].GUID == PlanetSideGUID(1))
assert(reply == hub(1).get)
}
}
}
object ServerObjectBuilderTest {
import net.psforever.objects.guid.source.LimitedNumberSource
def NumberPoolHub: NumberPoolHub = {
val obj = new NumberPoolHub(new LimitedNumberSource(2))
obj
}
class BuilderTestActor(builder: ServerObjectBuilder[_], hub: NumberPoolHub) extends Actor {
def receive: Receive = {
case _ =>
sender() ! builder.Build(context, hub)
}
}
class BuildingTestActor(
structure_con: (String, Int, Int, Zone, ActorContext) => Building,
name: String,
building_guid: Int,
map_id: Int,
zone: Zone
) extends Actor {
def receive: Receive = {
case _ =>
sender() ! FoundationBuilder(structure_con).Build(name, building_guid, map_id, zone)(context)
}
}
}

View file

@ -0,0 +1,35 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.Props
import base.ActorTest
import net.psforever.objects.{Default, GlobalDefinitions}
import net.psforever.objects.serverobject.tube.{SpawnTube, SpawnTubeControl, SpawnTubeDefinition}
import org.specs2.mutable.Specification
class SpawnTubeTest extends Specification {
"SpawnTubeDefinition" should {
"define" in {
val obj = new SpawnTubeDefinition(49)
obj.ObjectId mustEqual 49
}
}
"SpawnTube" should {
"construct" in {
val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
obj.Actor mustEqual Default.Actor
obj.Definition mustEqual GlobalDefinitions.ams_respawn_tube
}
}
}
class SpawnTubeControlTest extends ActorTest {
"SpawnTubeControl" should {
"construct" in {
val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
obj.Actor = system.actorOf(Props(classOf[SpawnTubeControl], obj), "spawn-tube")
assert(obj.Actor != Default.Actor)
}
}
}

View file

@ -0,0 +1,238 @@
// Copyright (c) 2017 PSForever
package objects
import akka.actor.{Actor, Props}
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vehicles._
import net.psforever.packet.game.ItemTransactionMessage
import net.psforever.types._
import org.specs2.mutable._
import scala.concurrent.duration.Duration
class UtilityTest extends Specification {
"Utility" should {
"create an order_terminala object" in {
val obj = Utility(UtilityType.order_terminala, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.order_terminala
obj().isInstanceOf[Terminal] mustEqual true
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 613
obj().asInstanceOf[Terminal].Actor mustEqual Default.Actor
}
"create an order_terminalb object" in {
val obj = Utility(UtilityType.order_terminalb, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.order_terminalb
obj().isInstanceOf[Terminal] mustEqual true
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 614
obj().asInstanceOf[Terminal].Actor mustEqual Default.Actor
}
"create a matrix_terminalc object" in {
val obj = Utility(UtilityType.matrix_terminalc, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.matrix_terminalc
obj().isInstanceOf[Terminal] mustEqual true
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 519
obj().asInstanceOf[Terminal].Actor mustEqual Default.Actor
}
"create an ams_respawn_tube object" in {
val obj = Utility(UtilityType.ams_respawn_tube, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.ams_respawn_tube
obj().isInstanceOf[SpawnTube] mustEqual true
obj().asInstanceOf[SpawnTube].Definition.ObjectId mustEqual 49
obj().asInstanceOf[SpawnTube].Actor mustEqual Default.Actor
}
"create a teleportpad_terminal object" in {
val obj = Utility(UtilityType.teleportpad_terminal, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.teleportpad_terminal
obj().isInstanceOf[Terminal] mustEqual true
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 853
obj().asInstanceOf[Terminal].Actor mustEqual Default.Actor
}
"produce a telepad object through the teleportpad_terminal" in {
val veh = Vehicle(GlobalDefinitions.quadstealth)
veh.Faction = PlanetSideEmpire.TR
val obj = Utility(UtilityType.teleportpad_terminal, UtilityTest.vehicle)
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
veh.GUID = PlanetSideGUID(101)
obj().Owner = veh //hack
obj().GUID = PlanetSideGUID(1)
player.GUID = PlanetSideGUID(2)
val msg = obj()
.asInstanceOf[Terminal]
.Request(
player,
ItemTransactionMessage(PlanetSideGUID(853), TransactionType.Buy, 0, "router_telepad", 0, PlanetSideGUID(0))
)
msg.isInstanceOf[Terminal.BuyEquipment] mustEqual true
msg.asInstanceOf[Terminal.BuyEquipment].item.isInstanceOf[Telepad] mustEqual true
}
"create an internal_router_telepad_deployable object" in {
val obj = Utility(UtilityType.internal_router_telepad_deployable, UtilityTest.vehicle)
obj.UtilType mustEqual UtilityType.internal_router_telepad_deployable
obj().isInstanceOf[Utility.InternalTelepad] mustEqual true
obj().asInstanceOf[Utility.InternalTelepad].Definition.ObjectId mustEqual 744
obj().asInstanceOf[Utility.InternalTelepad].Actor mustEqual Default.Actor
}
"internal_router_telepad_deployable can keep track of an object's GUID (presumedly, it's a Telepad)" in {
val obj = Utility(UtilityType.internal_router_telepad_deployable, UtilityTest.vehicle)
val inpad = obj().asInstanceOf[Utility.InternalTelepad]
inpad.Telepad.isEmpty mustEqual true
inpad.Telepad = PlanetSideGUID(5)
inpad.Telepad.contains(PlanetSideGUID(5)) mustEqual true
inpad.Telepad = PlanetSideGUID(6)
inpad.Telepad.contains(PlanetSideGUID(6)) mustEqual true
inpad.Telepad = None
inpad.Telepad.isEmpty mustEqual true
}
"be located with their owner (terminal)" in {
val veh = Vehicle(GlobalDefinitions.quadstealth)
val obj = Utility(UtilityType.order_terminala, veh)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
veh.Position = Vector3(1, 2, 3)
veh.Orientation = Vector3(4, 5, 6)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
}
"be located with their owner (spawn tube)" in {
val veh = Vehicle(GlobalDefinitions.quadstealth)
val obj = Utility(UtilityType.ams_respawn_tube, veh)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
veh.Position = Vector3(1, 2, 3)
veh.Orientation = Vector3(4, 5, 6)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
}
"be located with their owner (internal telepad)" in {
val veh = Vehicle(GlobalDefinitions.quadstealth)
val obj = Utility(UtilityType.internal_router_telepad_deployable, veh)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
veh.Position = Vector3(1, 2, 3)
veh.Orientation = Vector3(4, 5, 6)
veh.GUID = PlanetSideGUID(101)
obj().Position mustEqual veh.Position
obj().Orientation mustEqual veh.Orientation
obj().asInstanceOf[Utility.InternalTelepad].Router.contains(veh.GUID) mustEqual true
}
}
}
class UtilityTerminalATest extends ActorTest {
"Utility" should {
"wire an order_terminala Actor" in {
val obj = Utility(UtilityType.order_terminala, UtilityTest.vehicle)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == Default.Actor)
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(500, "ms")) //consume and discard
assert(obj().Actor != Default.Actor)
}
}
}
class UtilityTerminalBTest extends ActorTest {
"Utility" should {
"wire an order_terminalb Actor" in {
val obj = Utility(UtilityType.order_terminalb, UtilityTest.vehicle)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == Default.Actor)
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(500, "ms")) //consume and discard
assert(obj().Actor != Default.Actor)
}
}
}
class UtilityTerminalCTest extends ActorTest {
"Utility" should {
"wire a matrix_terminalc Actor" in {
val obj = Utility(UtilityType.matrix_terminalc, UtilityTest.vehicle)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == Default.Actor)
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(500, "ms")) //consume and discard
assert(obj().Actor != Default.Actor)
}
}
}
class UtilityRespawnTubeTest extends ActorTest {
"Utility" should {
"wire an ams_respawn_tube Actor" in {
val obj = Utility(UtilityType.ams_respawn_tube, UtilityTest.vehicle)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == Default.Actor)
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(500, "ms")) //consume and discard
assert(obj().Actor != Default.Actor)
}
}
}
class UtilityTelepadTerminalTest extends ActorTest {
"Utility" should {
"wire a teleportpad_terminal Actor" in {
val obj = Utility(UtilityType.teleportpad_terminal, UtilityTest.vehicle)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == Default.Actor)
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(500, "ms")) //consume and discard
assert(obj().Actor != Default.Actor)
}
}
}
class UtilityInternalTelepadTest extends ActorTest {
"Utility" should {
"wire a teleportpad_terminal Actor" in {
val veh = Vehicle(GlobalDefinitions.quadstealth)
veh.GUID = PlanetSideGUID(101)
val obj = Utility(UtilityType.internal_router_telepad_deployable, veh)
obj().GUID = PlanetSideGUID(1)
assert(obj().Actor == Default.Actor)
assert(obj().asInstanceOf[Utility.InternalTelepad].Router.contains(veh.GUID))
system.actorOf(Props(classOf[UtilityTest.SetupControl], obj), "test") ! ""
receiveOne(Duration.create(500, "ms")) //consume and discard
assert(obj().Actor != Default.Actor)
assert(obj().asInstanceOf[Utility.InternalTelepad].Router.contains(veh.GUID))
}
}
}
object UtilityTest {
val vehicle = Vehicle(GlobalDefinitions.quadstealth)
class SetupControl(obj: Utility) extends Actor {
def receive: Receive = {
case _ =>
obj.Setup(context)
sender() ! ""
}
}
}

View file

@ -0,0 +1,22 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.{Default, GlobalDefinitions}
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import org.specs2.mutable.Specification
class VehicleSpawnPadTest extends Specification {
"VehicleSpawnPadDefinition" should {
"define" in {
GlobalDefinitions.mb_pad_creation.ObjectId mustEqual 525
}
}
"VehicleSpawnPad" should {
"construct" in {
val obj = VehicleSpawnPad(GlobalDefinitions.mb_pad_creation)
obj.Actor mustEqual Default.Actor
obj.Definition mustEqual GlobalDefinitions.mb_pad_creation
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,96 @@
// Copyright (c) 2017 PSForever
package objects
import net.psforever.objects.ballistics._
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.vital._
import net.psforever.types._
import org.specs2.mutable.Specification
class VitalityTest extends Specification {
"Vitality" should {
val wep = GlobalDefinitions.galaxy_gunship_cannon
val wep_fmode = Tool(wep).FireMode
val proj = wep.ProjectileTypes.head
val vehicle = Vehicle(GlobalDefinitions.fury)
val vSource = VehicleSource(vehicle)
"accept a variety of events" in {
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val pSource = PlayerSource(player)
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(player),
player.DamageModel,
Vector3(50, 50, 0)
)
player.History(resprojectile) //ResolvedProjectile, straight-up
player.History(DamageFromProjectile(resprojectile))
player.History(HealFromKit(pSource, 10, GlobalDefinitions.medkit))
player.History(HealFromTerm(pSource, 10, 0, GlobalDefinitions.order_terminal))
player.History(HealFromImplant(pSource, 10, ImplantType.AdvancedRegen))
player.History(HealFromExoSuitChange(pSource, ExoSuitType.Standard))
player.History(RepairFromTerm(vSource, 10, GlobalDefinitions.order_terminal))
player.History(VehicleShieldCharge(vSource, 10))
player.History(PlayerSuicide(pSource))
ok
}
"return and clear the former list of vital activities" in {
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val pSource = PlayerSource(player)
player.History(HealFromKit(pSource, 10, GlobalDefinitions.medkit))
player.History(HealFromTerm(pSource, 10, 0, GlobalDefinitions.order_terminal))
player.History(HealFromImplant(pSource, 10, ImplantType.AdvancedRegen))
player.History(HealFromExoSuitChange(pSource, ExoSuitType.Standard))
player.History(RepairFromTerm(vSource, 10, GlobalDefinitions.order_terminal))
player.History(VehicleShieldCharge(vSource, 10))
player.History(PlayerSuicide(pSource))
player.History.size mustEqual 7
val list = player.ClearHistory()
player.History.size mustEqual 0
list.head.isInstanceOf[PlayerSuicide] mustEqual true
list(1).isInstanceOf[VehicleShieldCharge] mustEqual true
list(2).isInstanceOf[RepairFromTerm] mustEqual true
list(3).isInstanceOf[HealFromExoSuitChange] mustEqual true
list(4).isInstanceOf[HealFromImplant] mustEqual true
list(5).isInstanceOf[HealFromTerm] mustEqual true
list(6).isInstanceOf[HealFromKit] mustEqual true
}
"get exactly one entry that was caused by projectile damage" in {
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val pSource = PlayerSource(player)
val projectile = Projectile(proj, wep, wep_fmode, player, Vector3(2, 2, 0), Vector3.Zero)
val resprojectile = ResolvedProjectile(
ProjectileResolution.Splash,
projectile,
SourceEntry(player),
player.DamageModel,
Vector3(50, 50, 0)
)
player.History(DamageFromProjectile(resprojectile))
player.History(HealFromKit(pSource, 10, GlobalDefinitions.medkit))
player.History(HealFromTerm(pSource, 10, 0, GlobalDefinitions.order_terminal))
player.History(HealFromImplant(pSource, 10, ImplantType.AdvancedRegen))
player.History(HealFromExoSuitChange(pSource, ExoSuitType.Standard))
player.History(RepairFromTerm(vSource, 10, GlobalDefinitions.order_terminal))
player.History(VehicleShieldCharge(vSource, 10))
player.History(PlayerSuicide(pSource))
player.LastShot match {
case Some(resolved_projectile) =>
resolved_projectile.projectile mustEqual projectile
case None =>
ko
}
}
}
}

View file

@ -0,0 +1,656 @@
// Copyright (c) 2017 PSForever
package objects
import java.util.concurrent.atomic.AtomicInteger
import akka.actor.ActorContext
import base.ActorTest
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects._
import net.psforever.types._
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.objects.Vehicle
import org.specs2.mutable.Specification
import akka.actor.typed.scaladsl.adapter._
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar
import scala.concurrent.duration._
class ZoneTest extends Specification {
def test(a: String, b: Int, c: Int, d: Zone, e: ActorContext): Building = {
Building.NoBuilding
}
"ZoneMap" should {
"construct" in {
new ZoneMap("map13")
ok
}
"references bases by a positive building id (defaults to 0)" in {
val map = new ZoneMap("map13")
map.localBuildings mustEqual Map.empty
map.addLocalBuilding("Building", buildingGuid = 10, mapId = 0, FoundationBuilder(test))
map.localBuildings.keySet.contains(("Building", 10, 0)) mustEqual true
map.addLocalBuilding("Building", buildingGuid = -1, mapId = 0, FoundationBuilder(test))
map.localBuildings.keySet.contains(("Building", 10, 0)) mustEqual true
map.localBuildings.keySet.contains(("Building", -1, 0)) mustEqual false
}
"associates objects to bases (doesn't check numbers)" in {
val map = new ZoneMap("map13")
map.objectToBuilding mustEqual Map.empty
map.linkObjectToBuilding(1, 2)
map.objectToBuilding mustEqual Map(1 -> 2)
map.linkObjectToBuilding(3, 4)
map.objectToBuilding mustEqual Map(1 -> 2, 3 -> 4)
}
"associates doors to door locks (doesn't check numbers)" in {
val map = new ZoneMap("map13")
map.doorToLock mustEqual Map.empty
map.linkDoorToLock(1, 2)
map.doorToLock mustEqual Map(1 -> 2)
map.linkDoorToLock(3, 4)
map.doorToLock mustEqual Map(1 -> 2, 3 -> 4)
}
"associates terminals to spawn pads (doesn't check numbers)" in {
val map = new ZoneMap("map13")
map.terminalToSpawnPad mustEqual Map.empty
map.linkTerminalToSpawnPad(1, 2)
map.terminalToSpawnPad mustEqual Map(1 -> 2)
map.linkTerminalToSpawnPad(3, 4)
map.terminalToSpawnPad mustEqual Map(1 -> 2, 3 -> 4)
}
"associates mechanical components to implant terminals (doesn't check numbers)" in {
val map = new ZoneMap("map13")
map.terminalToInterface mustEqual Map.empty
map.linkTerminalToInterface(1, 2)
map.terminalToInterface mustEqual Map(1 -> 2)
map.linkTerminalToInterface(3, 4)
map.terminalToInterface mustEqual Map(1 -> 2, 3 -> 4)
}
"associate turrets to weapons" in {
val map = new ZoneMap("map13")
map.turretToWeapon mustEqual Map.empty
map.linkTurretToWeapon(1, 2)
map.turretToWeapon mustEqual Map(1 -> 2)
map.linkTurretToWeapon(3, 4)
map.turretToWeapon mustEqual Map(1 -> 2, 3 -> 4)
}
}
val map13 = new ZoneMap("map13")
map13.addLocalBuilding("Building", buildingGuid = 0, mapId = 10, FoundationBuilder(test))
class TestObject extends IdentifiableEntity
"Zone" should {
"construct" in {
val zone = new Zone("home3", map13, 13)
zone.EquipmentOnGround mustEqual List.empty[Equipment]
zone.Vehicles mustEqual List.empty[Vehicle]
zone.Players mustEqual List.empty[Player]
zone.Corpses mustEqual List.empty[Player]
}
"can have its unique identifier system changed if no objects were added to it" in {
val zone = new Zone("home3", map13, 13)
val guid1: NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(100))
zone.GUID(guid1) mustEqual true
zone.AddPool("pool1", (0 to 50).toList)
zone.AddPool("pool2", (51 to 75).toList)
val obj = new TestObject()
guid1.register(obj, "pool2").isSuccess mustEqual true
guid1.WhichPool(obj).contains("pool2") mustEqual true
zone.GUID(new NumberPoolHub(new LimitedNumberSource(150))) mustEqual false
}
}
}
class ZoneActorTest extends ActorTest {
"Zone" should {
"refuse new number pools after the Actor is started" in {
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} }
zone.GUID(new NumberPoolHub(new LimitedNumberSource(40150)))
zone.actor = system.spawn(ZoneActor(zone), "test-add-pool-actor-init")
expectNoMessage(Duration.create(500, "ms"))
assert(!zone.AddPool("test1", 1 to 2))
}
"refuse to remove number pools after the Actor is started" in {
val zone = new Zone("test", new ZoneMap("map6"), 1) { override def SetupNumberPools() = {} }
zone.GUID(new NumberPoolHub(new LimitedNumberSource(10)))
zone.AddPool("test", 1 to 2)
zone.actor = system.spawn(ZoneActor(zone), "test-remove-pool-actor-init")
expectNoMessage(Duration.create(300, "ms"))
assert(!zone.RemovePool("test"))
}
"set up spawn groups based on buildings" in {
val map6 = new ZoneMap("map6") {
addLocalBuilding(
"Building",
buildingGuid = 1,
mapId = 1,
FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 1, 1)))
)
addLocalObject(2, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero))
addLocalObject(3, Terminal.Constructor(Vector3.Zero, GlobalDefinitions.dropship_vehicle_terminal))
addLocalObject(4, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero))
linkObjectToBuilding(2, 1)
linkObjectToBuilding(3, 1)
linkObjectToBuilding(4, 1)
addLocalBuilding(
"Building",
buildingGuid = 5,
mapId = 2,
FoundationBuilder(Building.Structure(StructureType.Building))
)
addLocalObject(6, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
linkObjectToBuilding(6, 5)
addLocalBuilding(
"Building",
buildingGuid = 7,
mapId = 3,
FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 1, 1)))
)
addLocalObject(8, Terminal.Constructor(Vector3.Zero, GlobalDefinitions.dropship_vehicle_terminal))
addLocalObject(9, SpawnTube.Constructor(Vector3(1, 0, 0), Vector3.Zero))
addLocalObject(10, Terminal.Constructor(Vector3.Zero, GlobalDefinitions.dropship_vehicle_terminal))
linkObjectToBuilding(8, 7)
linkObjectToBuilding(9, 7)
linkObjectToBuilding(10, 7)
}
val zone = new Zone("test", map6, 1) { override def SetupNumberPools() = {} }
zone.actor = system.spawn(ZoneActor(zone), "test-init")
expectNoMessage(Duration.create(1, "seconds"))
val groups = zone.SpawnGroups()
assert(groups.size == 2)
zone
.SpawnGroups()
.foreach({
case (building, tubes) =>
if (building.MapId == 1) {
val building1 = zone.SpawnGroups(building)
assert(tubes.length == 2)
assert(tubes.head == building1.head)
assert(tubes.head.GUID == PlanetSideGUID(2))
assert(tubes(1) == building1(1))
assert(tubes(1).GUID == PlanetSideGUID(4))
} else if (building.MapId == 3) {
val building2 = zone.SpawnGroups(building)
assert(tubes.length == 1)
assert(tubes.head == building2.head)
assert(tubes.head.GUID == PlanetSideGUID(9))
} else {
assert(false)
}
})
}
}
}
class ZonePopulationTest extends ActorTest {
"ZonePopulationActor" should {
"add new user to zones" in {
val zone = new Zone("test", new ZoneMap(""), 0) {
override def SetupNumberPools() = {}
}
val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
assert(zone.Players.isEmpty)
assert(zone.LivePlayers.isEmpty)
zone.Population ! Zone.Population.Join(avatar)
zone.Population ! Zone.Population.Spawn(avatar, Player(avatar), null)
expectNoMessage(Duration.create(200, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
// assert(zone.LivePlayers.isEmpty)
}
"remove user from zones" in {
val zone = new Zone("test", new ZoneMap(""), 0) {
override def SetupNumberPools() = {}
}
val avatar = Avatar(1, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
receiveOne(Duration.create(200, "ms")) //consume
zone.Population ! Zone.Population.Join(avatar)
zone.Population ! Zone.Population.Spawn(avatar, Player(avatar), null)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
zone.Population ! Zone.Population.Leave(avatar)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Zone.Population.PlayerHasLeft])
assert(zone.Players.isEmpty)
}
/* TODO they need AvatarActor, which has further dependencies
"associate user with a character" in {
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val player = Player(avatar)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
zone.Population ! Zone.Population.Join(avatar)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
assert(zone.LivePlayers.isEmpty)
zone.Population ! Zone.Population.Spawn(avatar, player)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
assert(zone.LivePlayers.size == 1)
assert(zone.LivePlayers.head == player)
}
"disassociate character from a user" in {
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val player = Player(avatar)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
zone.Population ! Zone.Population.Join(avatar)
expectNoMessage(Duration.create(100, "ms"))
zone.Population ! Zone.Population.Spawn(avatar, player)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
assert(zone.LivePlayers.size == 1)
assert(zone.LivePlayers.head == player)
zone.Population ! Zone.Population.Release(avatar)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
assert(zone.LivePlayers.isEmpty)
}
"user tries to Leave, but still has an associated character" in {
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val player = Player(avatar)
player.GUID = PlanetSideGUID(1)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
zone.Population ! Zone.Population.Join(avatar)
expectNoMessage(Duration.create(100, "ms"))
zone.Population ! Zone.Population.Spawn(avatar, player)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
assert(zone.LivePlayers.size == 1)
assert(zone.LivePlayers.head == player)
zone.Population ! Zone.Population.Leave(avatar)
val reply = receiveOne(Duration.create(500, "ms"))
assert(zone.Players.isEmpty)
assert(zone.LivePlayers.isEmpty)
assert(reply.isInstanceOf[Zone.Population.PlayerHasLeft])
assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].zone == zone)
assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].player.contains(player))
}
"user tries to Spawn a character, but an associated character already exists" in {
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val player1 = Player(avatar)
val player2 = Player(avatar)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
zone.Population ! Zone.Population.Join(avatar)
expectNoMessage(Duration.create(100, "ms"))
zone.Population ! Zone.Population.Spawn(avatar, player1)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
assert(zone.LivePlayers.size == 1)
assert(zone.LivePlayers.head == player1)
zone.Population ! Zone.Population.Spawn(avatar, player2)
val reply = receiveOne(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
assert(zone.LivePlayers.size == 1)
assert(zone.LivePlayers.head == player1)
assert(reply.isInstanceOf[Zone.Population.PlayerAlreadySpawned])
assert(reply.asInstanceOf[Zone.Population.PlayerAlreadySpawned].player == player1)
}
"user tries to Spawn a character, but did not Join first" in {
val zone = new Zone("test", new ZoneMap(""), 0) { override def SetupNumberPools() = {} }
val avatar = Avatar(0, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
val player = Player(avatar)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
assert(zone.Players.isEmpty)
assert(zone.LivePlayers.isEmpty)
zone.Population ! Zone.Population.Spawn(avatar, player)
val reply = receiveOne(Duration.create(100, "ms"))
assert(zone.Players.isEmpty)
assert(zone.LivePlayers.isEmpty)
assert(reply.isInstanceOf[Zone.Population.PlayerCanNotSpawn])
assert(reply.asInstanceOf[Zone.Population.PlayerCanNotSpawn].zone == zone)
assert(reply.asInstanceOf[Zone.Population.PlayerCanNotSpawn].player == player)
}
*/
"user tries to Release a character, but did not Spawn a character first" in {
val zone = new Zone("test", new ZoneMap(""), 0) {
override def SetupNumberPools() = {}
}
val avatar = Avatar(2, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
zone.Population ! Zone.Population.Join(avatar)
zone.Population ! Zone.Population.Spawn(avatar, Player(avatar), null)
expectNoMessage(Duration.create(100, "ms"))
assert(zone.Players.size == 1)
assert(zone.Players.head == avatar)
// assert(zone.LivePlayers.isEmpty)
zone.Population ! Zone.Population.Release(avatar)
val reply = receiveOne(Duration.create(100, "ms"))
// assert(zone.Players.size == 1)
// assert(zone.Players.head == avatar)
// assert(zone.LivePlayers.isEmpty)
assert(reply.isInstanceOf[Zone.Population.PlayerHasLeft])
assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].zone == zone)
// assert(reply.asInstanceOf[Zone.Population.PlayerHasLeft].player.isEmpty)
}
"user adds character to list of retired characters" in {
val zone = new Zone("test", new ZoneMap(""), 0) {
override def SetupNumberPools() = {}
}
val player = Player(Avatar(3, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
player.Release
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
assert(zone.Corpses.isEmpty)
zone.Population ! Zone.Corpse.Add(player)
expectNoMessage(Duration.create(500, "ms"))
assert(zone.Corpses.size == 1)
assert(zone.Corpses.head == player)
}
"user removes character from the list of retired characters" in {
val zone = new Zone("test", new ZoneMap(""), 0) {
override def SetupNumberPools() = {}
}
val player = Player(Avatar(4, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
player.Release
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
zone.Population ! Zone.Corpse.Add(player)
expectNoMessage(Duration.create(500, "ms"))
assert(zone.Corpses.size == 1)
assert(zone.Corpses.head == player)
zone.Population ! Zone.Corpse.Remove(player)
expectNoMessage(Duration.create(200, "ms"))
assert(zone.Corpses.isEmpty)
}
"user removes THE CORRECT character from the list of retired characters" in {
val zone = new Zone("test", new ZoneMap(""), 0) {
override def SetupNumberPools() = {}
}
val player1 = Player(Avatar(5, "Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
player1.Release
val player2 = Player(Avatar(6, "Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
player2.Release
val player3 = Player(Avatar(7, "Chord3", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
player3.Release
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
zone.Population ! Zone.Corpse.Add(player1)
zone.Population ! Zone.Corpse.Add(player2)
zone.Population ! Zone.Corpse.Add(player3)
expectNoMessage(Duration.create(500, "ms"))
assert(zone.Corpses.size == 3)
assert(zone.Corpses.head == player1)
assert(zone.Corpses(1) == player2)
assert(zone.Corpses(2) == player3)
zone.Population ! Zone.Corpse.Remove(player2)
expectNoMessage(Duration.create(200, "ms"))
assert(zone.Corpses.size == 2)
assert(zone.Corpses.head == player1)
assert(zone.Corpses(1) == player3)
}
"user tries to add character to list of retired characters, but is not in correct state" in {
val zone = new Zone("test", new ZoneMap(""), 0) {
override def SetupNumberPools() = {}
}
val player = Player(Avatar(8, "Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Voice5))
//player.Release !!important
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
assert(zone.Corpses.isEmpty)
zone.Population ! Zone.Corpse.Add(player)
expectNoMessage(Duration.create(200, "ms"))
assert(zone.Corpses.isEmpty)
}
}
}
class ZoneGroundDropItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20))
hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
"DropItem" should {
"drop item on ground" in {
receiveOne(1 second) //consume
assert(!zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.DropItem(item, Vector3(1.1f, 2.2f, 3.3f), Vector3(4.4f, 5.5f, 6.6f))
val reply = receiveOne(200 milliseconds)
assert(reply.isInstanceOf[Zone.Ground.ItemOnGround])
assert(reply.asInstanceOf[Zone.Ground.ItemOnGround].item == item)
assert(reply.asInstanceOf[Zone.Ground.ItemOnGround].pos == Vector3(1.1f, 2.2f, 3.3f))
assert(reply.asInstanceOf[Zone.Ground.ItemOnGround].orient == Vector3(4.4f, 5.5f, 6.6f))
assert(zone.EquipmentOnGround.contains(item))
}
}
}
class ZoneGroundCanNotDropItem1Test extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20))
//hub.register(item, 10) //!important
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
"DropItem" should {
"not drop an item that is not registered" in {
receiveOne(1 second) //consume
assert(!zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero)
val reply = receiveOne(300 milliseconds)
assert(reply.isInstanceOf[Zone.Ground.CanNotDropItem])
assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].item == item)
assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].zone == zone)
assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].reason == "not registered yet")
assert(!zone.EquipmentOnGround.contains(item))
}
}
}
class ZoneGroundCanNotDropItem2Test extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20))
hub.register(item, 10) //!important
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
//zone.GUID(hub) //!important
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
"DropItem" should {
"not drop an item that is not registered to the zone" in {
receiveOne(1 second) //consume
assert(!zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero)
val reply = receiveOne(300 milliseconds)
assert(reply.isInstanceOf[Zone.Ground.CanNotDropItem])
assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].item == item)
assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].zone == zone)
assert(reply.asInstanceOf[Zone.Ground.CanNotDropItem].reason == "registered to some other zone")
assert(!zone.EquipmentOnGround.contains(item))
}
}
}
class ZoneGroundCanNotDropItem3Test extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20))
hub.register(item, 10) //!important
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) //!important
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
"DropItem" should {
"not drop an item that has already been dropped" in {
receiveOne(1 second) //consume
assert(!zone.EquipmentOnGround.contains(item))
assert(zone.EquipmentOnGround.isEmpty)
zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero)
val reply1 = receiveOne(300 milliseconds)
assert(reply1.isInstanceOf[Zone.Ground.ItemOnGround])
assert(reply1.asInstanceOf[Zone.Ground.ItemOnGround].item == item)
assert(zone.EquipmentOnGround.contains(item))
assert(zone.EquipmentOnGround.size == 1)
zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero)
val reply2 = receiveOne(300 milliseconds)
assert(reply2.isInstanceOf[Zone.Ground.CanNotDropItem])
assert(reply2.asInstanceOf[Zone.Ground.CanNotDropItem].item == item)
assert(reply2.asInstanceOf[Zone.Ground.CanNotDropItem].zone == zone)
assert(reply2.asInstanceOf[Zone.Ground.CanNotDropItem].reason == "already dropped")
assert(zone.EquipmentOnGround.size == 1)
}
}
}
class ZoneGroundPickupItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20))
hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub)
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
"PickupItem" should {
"pickup an item from ground" in {
receiveOne(1 second) //consume
assert(!zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero)
val reply1 = receiveOne(200 milliseconds)
assert(reply1.isInstanceOf[Zone.Ground.ItemOnGround])
assert(zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.PickupItem(item.GUID)
val reply2 = receiveOne(200 milliseconds)
assert(reply2.isInstanceOf[Zone.Ground.ItemInHand])
assert(reply2.asInstanceOf[Zone.Ground.ItemInHand].item == item)
assert(!zone.EquipmentOnGround.contains(item))
}
}
}
class ZoneGroundCanNotPickupItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20))
hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) //still registered to this zone
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
"PickupItem" should {
"not pickup an item if it can not be found" in {
receiveOne(1 second) //consume
assert(!zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.PickupItem(item.GUID)
val reply2 = receiveOne(200 milliseconds)
assert(reply2.isInstanceOf[Zone.Ground.CanNotPickupItem])
assert(reply2.asInstanceOf[Zone.Ground.CanNotPickupItem].item_guid == item.GUID)
assert(reply2.asInstanceOf[Zone.Ground.CanNotPickupItem].zone == zone)
assert(reply2.asInstanceOf[Zone.Ground.CanNotPickupItem].reason == "can not find")
}
}
}
class ZoneGroundRemoveItemTest extends ActorTest {
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
val hub = new NumberPoolHub(new LimitedNumberSource(20))
hub.register(item, 10)
val zone = new Zone("test", new ZoneMap("test-map"), 0) { override def SetupNumberPools() = {} }
zone.GUID(hub) //still registered to this zone
zone.actor = system.spawn(ZoneActor(zone), ZoneTest.TestName)
expectNoMessage(200 milliseconds)
"RemoveItem" should {
"remove an item from the ground without callback (even if the item is not found)" in {
receiveOne(1 second)
assert(!zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.DropItem(item, Vector3.Zero, Vector3.Zero)
receiveOne(200 milliseconds)
assert(zone.EquipmentOnGround.contains(item)) //dropped
zone.Ground ! Zone.Ground.RemoveItem(item.GUID)
expectNoMessage(500 milliseconds)
assert(!zone.EquipmentOnGround.contains(item))
zone.Ground ! Zone.Ground.RemoveItem(item.GUID) //repeat
expectNoMessage(500 milliseconds)
assert(!zone.EquipmentOnGround.contains(item))
}
}
}
object ZoneTest {
val testNum = new AtomicInteger(1)
def TestName: String = s"test${testNum.getAndIncrement()}"
}

View file

@ -0,0 +1,21 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskRegisterAmmoTest extends ActorTest {
"RegisterEquipment -> RegisterObjectTask" in {
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = AmmoBox(GlobalDefinitions.energy_cell)
assert(!obj.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterEquipment(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(obj.HasGUID)
}
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskRegisterAvatarTest extends ActorTest {
"RegisterAvatar" in {
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj_wep = Tool(GlobalDefinitions.beamer)
obj.Slot(0).Equipment = obj_wep
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_wep.AmmoSlots.head.Box = obj_wep_ammo
val obj_inv_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj.Slot(6).Equipment = obj_inv_ammo
val obj_locker = obj.Slot(5).Equipment.get
val obj_locker_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_locker.asInstanceOf[LockerEquipment].Inventory += 0 -> obj_locker_ammo
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_wep_ammo.HasGUID)
assert(!obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterAvatar(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_wep_ammo.HasGUID)
assert(obj_inv_ammo.HasGUID)
assert(obj_locker.HasGUID)
assert(obj_locker_ammo.HasGUID)
}
}

View file

@ -0,0 +1,20 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskRegisterObjectTest extends ActorTest {
"RegisterObjectTask" in {
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = new GUIDTaskTest.TestObject
assert(!obj.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterObjectTask(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(obj.HasGUID)
}
}

View file

@ -0,0 +1,42 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskRegisterPlayerTest extends ActorTest {
"RegisterPlayer" in {
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj_wep = Tool(GlobalDefinitions.beamer)
obj.Slot(0).Equipment = obj_wep
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_wep.AmmoSlots.head.Box = obj_wep_ammo
val obj_inv_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj.Slot(6).Equipment = obj_inv_ammo
val obj_locker = obj.Slot(5).Equipment.get
val obj_locker_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_locker.asInstanceOf[LockerEquipment].Inventory += 0 -> obj_locker_ammo
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_wep_ammo.HasGUID)
assert(!obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterPlayer(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_wep_ammo.HasGUID)
assert(obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID)
}
}

View file

@ -0,0 +1,24 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskRegisterToolTest extends ActorTest {
"RegisterEquipment -> RegisterTool" in {
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Tool(GlobalDefinitions.beamer)
obj.AmmoSlots.head.Box = AmmoBox(GlobalDefinitions.energy_cell)
assert(!obj.HasGUID)
assert(!obj.AmmoSlots.head.Box.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterEquipment(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(obj.HasGUID)
assert(obj.AmmoSlots.head.Box.HasGUID)
}
}

View file

@ -0,0 +1,30 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskRegisterTurretTest extends ActorTest {
"RegisterDeployableTurret" in {
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_vs)
val obj_wep = obj.Weapons(1).Equipment.get
val obj_ammo = obj_wep.asInstanceOf[Tool].AmmoSlot.Box
val obj_res = obj.Inventory.Items.map(_.obj)
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_ammo.HasGUID)
obj_res.foreach(box => !box.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterDeployableTurret(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_ammo.HasGUID)
obj_res.foreach(box => box.HasGUID)
}
}

View file

@ -0,0 +1,32 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskRegisterVehicleTest extends ActorTest {
"RegisterVehicle" in {
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Vehicle(GlobalDefinitions.fury)
val obj_wep = obj.WeaponControlledFromSeat(0).get
val obj_wep_ammo = (obj.WeaponControlledFromSeat(0).get.asInstanceOf[Tool].AmmoSlots.head.Box =
AmmoBox(GlobalDefinitions.hellfire_ammo)).get
obj.Trunk += 30 -> AmmoBox(GlobalDefinitions.hellfire_ammo)
val obj_trunk_ammo = obj.Trunk.Items(0).obj
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_wep_ammo.HasGUID)
assert(!obj_trunk_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.RegisterVehicle(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_wep_ammo.HasGUID)
assert(obj_trunk_ammo.HasGUID)
}
}

View file

@ -0,0 +1,51 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import java.util.logging.LogManager
import scala.util.Success
import akka.actor.{ActorRef, ActorSystem, Props}
import akka.testkit.TestProbe
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.actor.{NumberPoolActor, UniqueNumberSystem}
import net.psforever.objects.guid.selector.RandomSelector
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.guid.{NumberPoolHub, Task, TaskResolver}
object GUIDTaskTest {
class TestObject extends IdentifiableEntity
class RegisterTestTask(probe: ActorRef) extends Task {
def Execute(resolver: ActorRef): Unit = {
probe ! Success
resolver ! Success(this)
}
}
def CommonTestSetup(implicit system: ActorSystem): (NumberPoolHub, ActorRef, ActorRef, TestProbe) = {
import akka.actor.Props
import akka.routing.RandomPool
import akka.testkit.TestProbe
val guid: NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(110))
guid.AddPool("dynamic", (1 to 100).toList).Selector = new RandomSelector //TODO name is hardcoded for now
val uns = system.actorOf(
RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, GUIDTaskTest.AllocateNumberPoolActors(guid))),
"uns"
)
val taskResolver = system.actorOf(RandomPool(15).props(Props[TaskResolver]()), "resolver")
LogManager.getLogManager.reset() //suppresses any internal loggers created by the above elements
(guid, uns, taskResolver, TestProbe())
}
/**
* @see `UniqueNumberSystem.AllocateNumberPoolActors(NumberPoolHub)(implicit ActorContext)`
*/
def AllocateNumberPoolActors(poolSource: NumberPoolHub)(implicit system: ActorSystem): Map[String, ActorRef] = {
poolSource.Pools
.map({
case ((pname, pool)) =>
pname -> system.actorOf(Props(classOf[NumberPoolActor], pool), pname)
})
.toMap
}
}

View file

@ -0,0 +1,22 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskUnregisterAmmoTest extends ActorTest {
"UnregisterEquipment -> UnregisterObjectTask" in {
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = AmmoBox(GlobalDefinitions.energy_cell)
guid.register(obj, "dynamic")
assert(obj.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.UnregisterEquipment(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(!obj.HasGUID)
}
}

View file

@ -0,0 +1,48 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskUnregisterAvatarTest extends ActorTest {
"UnregisterAvatar" in {
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj_wep = Tool(GlobalDefinitions.beamer)
obj.Slot(0).Equipment = obj_wep
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_wep.AmmoSlots.head.Box = obj_wep_ammo
val obj_inv_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj.Slot(6).Equipment = obj_inv_ammo
val obj_locker = obj.Slot(5).Equipment.get
val obj_locker_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_locker.asInstanceOf[LockerEquipment].Inventory += 0 -> obj_locker_ammo
guid.register(obj, "dynamic")
guid.register(obj_wep, "dynamic")
guid.register(obj_wep_ammo, "dynamic")
guid.register(obj_inv_ammo, "dynamic")
guid.register(obj_locker, "dynamic")
guid.register(obj_locker_ammo, "dynamic")
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_wep_ammo.HasGUID)
assert(obj_inv_ammo.HasGUID)
assert(obj_locker.HasGUID)
assert(obj_locker_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.UnregisterAvatar(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_wep_ammo.HasGUID)
assert(!obj_inv_ammo.HasGUID)
assert(!obj_locker.HasGUID)
assert(!obj_locker_ammo.HasGUID)
}
}

View file

@ -0,0 +1,21 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskUnregisterObjectTest extends ActorTest {
"UnregisterObjectTask" in {
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = new GUIDTaskTest.TestObject
guid.register(obj, "dynamic")
assert(obj.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.UnregisterObjectTask(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(!obj.HasGUID)
}
}

View file

@ -0,0 +1,48 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
class GUIDTaskUnregisterPlayerTest extends ActorTest {
"UnregisterPlayer" in {
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj_wep = Tool(GlobalDefinitions.beamer)
obj.Slot(0).Equipment = obj_wep
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_wep.AmmoSlots.head.Box = obj_wep_ammo
val obj_inv_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj.Slot(6).Equipment = obj_inv_ammo
val obj_locker = obj.Slot(5).Equipment.get
val obj_locker_ammo = AmmoBox(GlobalDefinitions.energy_cell)
obj_locker.asInstanceOf[LockerEquipment].Inventory += 0 -> obj_locker_ammo
guid.register(obj, "dynamic")
guid.register(obj_wep, "dynamic")
guid.register(obj_wep_ammo, "dynamic")
guid.register(obj_inv_ammo, "dynamic")
guid.register(obj_locker, "dynamic")
guid.register(obj_locker_ammo, "dynamic")
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_wep_ammo.HasGUID)
assert(obj_inv_ammo.HasGUID)
assert(obj_locker.HasGUID)
assert(obj_locker_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.UnregisterPlayer(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_wep_ammo.HasGUID)
assert(!obj_inv_ammo.HasGUID)
assert(obj_locker.HasGUID)
assert(obj_locker_ammo.HasGUID)
}
}

View file

@ -0,0 +1,26 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskUnregisterToolTest extends ActorTest {
"UnregisterEquipment -> UnregisterTool" in {
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Tool(GlobalDefinitions.beamer)
obj.AmmoSlots.head.Box = AmmoBox(GlobalDefinitions.energy_cell)
guid.register(obj, "dynamic")
guid.register(obj.AmmoSlots.head.Box, "dynamic")
assert(obj.HasGUID)
assert(obj.AmmoSlots.head.Box.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.UnregisterEquipment(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(!obj.HasGUID)
assert(!obj.AmmoSlots.head.Box.HasGUID)
}
}

View file

@ -0,0 +1,34 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskUnregisterTurretTest extends ActorTest {
"UnregisterDeployableTurret" in {
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = new TurretDeployable(GlobalDefinitions.portable_manned_turret_vs)
val obj_wep = obj.Weapons(1).Equipment.get
val obj_ammo = obj_wep.asInstanceOf[Tool].AmmoSlot.Box
val obj_res = obj.Inventory.Items.map(_.obj)
guid.register(obj, "dynamic")
guid.register(obj_wep, "dynamic")
guid.register(obj_ammo, "dynamic")
obj_res.foreach(box => guid.register(box, "dynamic"))
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_ammo.HasGUID)
obj_res.foreach(box => box.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.UnregisterDeployableTurret(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_ammo.HasGUID)
obj_res.foreach(box => !box.HasGUID)
}
}

View file

@ -0,0 +1,36 @@
// Copyright (c) 2017 PSForever
package objects.guidtask
import base.ActorTest
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
class GUIDTaskUnregisterVehicleTest extends ActorTest {
"RegisterVehicle" in {
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
val obj = Vehicle(GlobalDefinitions.fury)
val obj_wep = obj.WeaponControlledFromSeat(0).get
val obj_wep_ammo = (obj.WeaponControlledFromSeat(0).get.asInstanceOf[Tool].AmmoSlots.head.Box =
AmmoBox(GlobalDefinitions.hellfire_ammo)).get
obj.Trunk += 30 -> AmmoBox(GlobalDefinitions.hellfire_ammo)
val obj_trunk_ammo = obj.Trunk.Items(0).obj
guid.register(obj, "dynamic")
guid.register(obj_wep, "dynamic")
guid.register(obj_wep_ammo, "dynamic")
guid.register(obj_trunk_ammo, "dynamic")
assert(obj.HasGUID)
assert(obj_wep.HasGUID)
assert(obj_wep_ammo.HasGUID)
assert(obj_trunk_ammo.HasGUID)
taskResolver ! TaskResolver.GiveTask(
new GUIDTaskTest.RegisterTestTask(probe.ref),
List(GUIDTask.UnregisterVehicle(obj)(uns))
)
probe.expectMsg(scala.util.Success)
assert(!obj.HasGUID)
assert(!obj_wep.HasGUID)
assert(!obj_wep_ammo.HasGUID)
assert(!obj_trunk_ammo.HasGUID)
}
}

View file

@ -0,0 +1,51 @@
// Copyright (c) 2017 PSForever
package objects.number
import akka.actor.Props
import base.ActorTest
import net.psforever.objects.guid.actor.NumberPoolActor
import net.psforever.objects.guid.pool.ExclusivePool
import net.psforever.objects.guid.selector.RandomSelector
import scala.concurrent.duration.Duration
class NumberPoolActorTest extends ActorTest {
"NumberPoolActor" should {
"GetAnyNumber" in {
val pool = new ExclusivePool((25 to 50).toList)
pool.Selector = new RandomSelector
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor1")
poolActor ! NumberPoolActor.GetAnyNumber()
val msg = receiveOne(Duration.create(500, "ms"))
assert(msg.isInstanceOf[NumberPoolActor.GiveNumber])
}
}
}
class NumberPoolActorTest1 extends ActorTest {
"NumberPoolActor" should {
"GetSpecificNumber" in {
val pool = new ExclusivePool((25 to 50).toList)
pool.Selector = new RandomSelector
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor2")
poolActor ! NumberPoolActor.GetSpecificNumber(37)
expectMsg(NumberPoolActor.GiveNumber(37, None))
}
}
}
class NumberPoolActorTest2 extends ActorTest {
"NumberPoolActor" should {
"NoNumber" in {
val pool = new ExclusivePool((25 to 25).toList) //pool only has one number - 25
pool.Selector = new RandomSelector
val poolActor = system.actorOf(Props(classOf[NumberPoolActor], pool), name = "poolActor3")
poolActor ! NumberPoolActor.GetAnyNumber()
expectMsg(NumberPoolActor.GiveNumber(25, None))
poolActor ! NumberPoolActor.GetAnyNumber()
val msg = receiveOne(Duration.create(500, "ms"))
assert(msg.isInstanceOf[NumberPoolActor.NoNumber])
}
}
}

View file

@ -0,0 +1,343 @@
// Copyright (c) 2017 PSForever
package objects.number
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.selector.RandomSelector
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.types.PlanetSideGUID
import org.specs2.mutable.Specification
import scala.util.Success
class NumberPoolHubTest extends Specification {
val numberList = 0 :: 1 :: 2 :: 3 :: 5 :: 8 :: 13 :: 21 :: Nil
val numberList1 = 0 :: 1 :: 2 :: 3 :: 5 :: Nil
val numberList2 = 8 :: 13 :: 21 :: 34 :: Nil
val numberSet1 = numberList1.toSet
val numberSet2 = numberList2.toSet
class EntityTestClass extends IdentifiableEntity
"NumberPoolHub" should {
"construct" in {
new NumberPoolHub(new LimitedNumberSource(51))
ok
}
"get a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.GetPool("generic").isDefined mustEqual true //default pool
}
"add a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.Numbers.isEmpty mustEqual true
obj.AddPool("fibonacci", numberList)
obj.Numbers.toSet.equals(numberList.toSet) mustEqual true
val pool = obj.GetPool("fibonacci")
pool.isDefined mustEqual true
pool.get.Numbers.equals(numberList)
}
"enumerate the content of all pools" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.AddPool("fibonacci1", numberList1)
obj.AddPool("fibonacci2", numberList2)
numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1
numberSet2.intersect(obj.Numbers.toSet) mustEqual numberSet2
obj.Numbers.toSet.diff(numberSet1) mustEqual numberSet2
}
"remove a pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.Numbers.isEmpty mustEqual true
obj.AddPool("fibonacci", numberList)
obj.Numbers.toSet.equals(numberList.toSet) mustEqual true
obj.RemovePool("fibonacci").toSet.equals(numberList.toSet) mustEqual true
obj.Numbers.isEmpty mustEqual true
obj.GetPool("fibonacci").isEmpty mustEqual true
}
"block removing the default 'generic' pool" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.RemovePool("generic") must throwA[IllegalArgumentException]
}
"block adding pools that use already-included numbers" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.AddPool("fibonacci1", numberList)
val numberList4 = 3 :: 7 :: 21 :: 34 :: 45 :: Nil
obj.AddPool("fibonacci2", numberList4) must throwA[IllegalArgumentException]
}
"enumerate only the content of all current pools" in {
val obj = new NumberPoolHub(new LimitedNumberSource(51))
obj.AddPool("fibonacci1", numberList1)
obj.AddPool("fibonacci2", numberList2)
numberSet1.intersect(obj.Numbers.toSet) mustEqual numberSet1
numberSet2.intersect(obj.Numbers.toSet) mustEqual numberSet2
obj.RemovePool("fibonacci1")
numberSet1.intersect(obj.Numbers.toSet) mustEqual Set() //no intersect
numberSet2.intersect(obj.Numbers.toSet) mustEqual numberSet2
}
"register an object to a pool" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
obj.GUID must throwA[Exception]
hub.register(obj, "fibonacci") match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
case _ =>
ko
}
}
"lookup a registered object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci") match {
case Success(number) =>
val objFromNumber = hub(number)
objFromNumber.contains(obj) mustEqual true
case _ =>
ko
}
}
"lookup the pool of a(n unassigned) number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci1", numberList1)
hub.AddPool("fibonacci2", numberList2)
hub.WhichPool(13).contains("fibonacci2") mustEqual true
}
"lookup the pool of a registered object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList1)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci")
hub.WhichPool(obj).contains("fibonacci") mustEqual true
}
"register an object to a specific, unused number; it is assigned to pool 'generic'" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList1)
val obj = new EntityTestClass()
obj.GUID must throwA[Exception]
hub.register(obj, 44) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj).contains("generic") mustEqual true
case _ =>
ko
}
}
"register an object to a specific, pooled number (list 1)" in {
val src = new LimitedNumberSource(51)
val hub = new NumberPoolHub(src)
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
obj.GUID must throwA[Exception]
hub.register(obj, 5) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj).contains("fibonacci") mustEqual true
src.Available(5).isEmpty mustEqual true
case _ =>
ko
}
}
"register an object to a specific, pooled number (list 2)" in {
val src = new LimitedNumberSource(51)
val hub = new NumberPoolHub(src)
hub.AddPool("fibonacci", numberList2)
val obj = new EntityTestClass()
obj.GUID must throwA[Exception]
hub.register(obj, 13) match {
case Success(number) =>
obj.GUID mustEqual PlanetSideGUID(number)
hub.WhichPool(obj).contains("fibonacci") mustEqual true
src.Available(13).isEmpty mustEqual true
case _ =>
ko
}
}
"register an object without extra specifications; it is assigned to pool 'generic'" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
val obj = new EntityTestClass()
hub.register(obj)
hub.WhichPool(obj).contains("generic") mustEqual true
}
"unregister an object" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
obj.HasGUID mustEqual false
hub.register(obj, "fibonacci")
hub.WhichPool(obj).contains("fibonacci") mustEqual true
obj.HasGUID mustEqual true
hub.unregister(obj)
obj.HasGUID mustEqual false
hub.WhichPool(obj).isEmpty mustEqual true
}
"not register an object to a different pool" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci1", numberList1)
hub.AddPool("fibonacci2", numberList2)
val obj = new EntityTestClass()
hub.register(obj, "fibonacci1")
hub.register(obj, "fibonacci2")
hub.WhichPool(obj).contains("fibonacci1") mustEqual true
}
"fail to unregister an object that is not registered to this hub" in {
val hub1 = new NumberPoolHub(new LimitedNumberSource(51))
val hub2 = new NumberPoolHub(new LimitedNumberSource(51))
hub1.AddPool("fibonacci", numberList)
hub2.AddPool("fibonacci", numberList)
val obj = new EntityTestClass()
hub1.register(obj, "fibonacci")
hub2.unregister(obj) must throwA[Exception]
}
"pre-register a specific, unused number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.register(13) match {
case Success(_) =>
ok
case _ =>
ko
}
}
"pre-register a specific, pooled number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList)
hub.register(13) match {
case Success(key) =>
key.GUID mustEqual 13
case _ =>
ko
}
}
"pre-register a number from a known pool" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList).Selector = new RandomSelector
hub.register("fibonacci") match {
case Success(key) =>
numberList.contains(key.GUID) mustEqual true
case _ =>
ko
}
}
"unregister a number" in {
val hub = new NumberPoolHub(new LimitedNumberSource(51))
hub.AddPool("fibonacci", numberList).Selector = new RandomSelector //leave this tagged on
val obj = new EntityTestClass()
hub.register(13) match {
case Success(key) =>
key.Object = obj
obj.HasGUID mustEqual true
case _ =>
ko
}
hub.WhichPool(obj).contains("fibonacci") mustEqual true
hub.unregister(13) match {
case Success(thing) =>
thing.contains(obj) mustEqual true
thing.get.HasGUID mustEqual false
case _ =>
ko
}
}
"not affect the hidden restricted pool by adding a new pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
src.Restrict(8) //in fibonacci
src.Restrict(10)
src.Restrict(12)
val hub = new NumberPoolHub(src)
hub.AddPool("fibonacci", numberList) must throwA[IllegalArgumentException]
}
"not register an object to a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
val hub = new NumberPoolHub(src)
val obj = new EntityTestClass()
hub.register(obj, 4).isFailure mustEqual true
}
"not register an object to the restricted pool directly" in {
val src = new LimitedNumberSource(51)
// src.Restrict(4)
val hub = new NumberPoolHub(src)
val obj = new EntityTestClass()
hub.register(obj, "").isFailure mustEqual true //the empty string represents the restricted pool
}
"not register a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
val hub = new NumberPoolHub(src)
hub.register(4).isFailure mustEqual true
}
"not unregister a number belonging to the restricted pool" in {
val src = new LimitedNumberSource(51)
src.Restrict(4)
val hub = new NumberPoolHub(src)
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

@ -0,0 +1,220 @@
// Copyright (c) 2017 PSForever
package objects.number
import net.psforever.objects.guid.pool.{ExclusivePool, GenericPool, SimplePool}
import net.psforever.objects.guid.selector.SpecificSelector
import org.specs2.mutable.Specification
import scala.collection.mutable
import scala.collection.mutable.ListBuffer
import scala.util.Success
class NumberPoolTest extends Specification {
"SimplePool" should {
"construct" in {
new SimplePool(0 :: 1 :: 2 :: Nil)
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 {
val min = 10
val max = 20
val domain = (min to max).toList
val obj = new SimplePool(domain)
obj.Get() match {
case Success(number) =>
(min <= number && number <= max) mustEqual true
case _ =>
ko
}
ok
}
"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 {
//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)
obj.Get() match {
case Success(number) =>
obj.Return(number) mustEqual true
obj.Return(11) mustEqual false
obj.Return(number) mustEqual true
case _ =>
ko
}
}
"numbers remain available" in {
val obj = new SimplePool((0 to 10).toList)
obj.Selector = new SpecificSelector
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 8
obj.Get() mustEqual Success(8)
obj.Get() mustEqual Success(8) //compare to how SpecificSelector works otherwise - it would be an invalid return
}
}
"ExclusivePool" should {
"construct" in {
new ExclusivePool(0 :: 1 :: 2 :: Nil)
ok
}
"get a number" in {
val min = 10
val max = 20
val domain = (min to max).toList
val obj = new ExclusivePool(domain)
obj.Get() match {
case Success(number) =>
(min <= number && number <= max) mustEqual true
case _ =>
ko
}
ok
}
"get all the numbers" in {
val min = 10
val max = 20
val domain = (min to max).toList
val obj = new ExclusivePool(domain)
domain.foreach(_ => {
obj.Get() match {
case Success(number) =>
(min <= number && number <= max) mustEqual true
case _ =>
ko
}
})
ok
}
"return a number" in {
val obj = new ExclusivePool((0 to 10).toList)
obj.Get() match {
case Success(number) =>
try { obj.Return(number) mustEqual true }
catch { case _: Exception => ko }
case _ =>
ko
}
}
"return all the numbers" in {
val range = 0 to 10
val obj = new ExclusivePool((0 to 10).toList)
val list: ListBuffer[Int] = ListBuffer[Int]()
range.foreach(_ => {
obj.Get() match {
case Success(number) =>
list += number
case _ =>
}
})
list.foreach(number => {
try { obj.Return(number) mustEqual true }
catch { case _: Exception => ko }
})
ok
}
}
"GenericPool" should {
"construct" in {
new GenericPool(mutable.LongMap[String](), 11)
ok
}
"get a provided number" in {
val map = mutable.LongMap[String]()
val obj = new GenericPool(map, 11)
obj.Numbers.isEmpty mustEqual true
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 5
obj.Get() match {
case Success(number) =>
number mustEqual 5
map.contains(5) mustEqual true
map(5) mustEqual "generic"
obj.Numbers.contains(5) mustEqual true
case _ =>
ko
}
}
"return a number" in {
val map = mutable.LongMap[String]()
val obj = new GenericPool(map, 11)
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 5
obj.Get()
map.get(5).contains("generic") mustEqual true
obj.Numbers.contains(5) mustEqual true
obj.Return(5) mustEqual true
map.get(5).isEmpty mustEqual true
obj.Numbers.isEmpty mustEqual true
}
"block on numbers that are already defined" in {
val map = mutable.LongMap[String]()
map += 5L -> "test" //5 is defined
val obj = new GenericPool(map, 11)
obj.Numbers.isEmpty mustEqual true
obj.Selector.asInstanceOf[SpecificSelector].SelectionIndex = 5 //5 is requested
obj.Get() match {
case Success(_) =>
ko
case _ =>
obj.Numbers.isEmpty mustEqual true
}
}
"get a free number on own if none provided" in {
val map = mutable.LongMap[String]()
val obj = new GenericPool(map, 11)
obj.Get() match {
case Success(number) =>
number mustEqual 5
case _ =>
ko
}
}
"get a free number that is not already defined" in {
val map = mutable.LongMap[String]()
map += 5L -> "test" //5 is defined; think, -1 :: 5 :: 11
val obj = new GenericPool(map, 11)
obj.Get() match {
case Success(number) =>
number mustEqual 2 // think, -1 :: 2 :: 5 :: 11
case _ => ko
}
}
"get a free number that represents half of the largest delta" in {
val map = mutable.LongMap[String]()
map += 5L -> "test" //5 is defined; think, -1 :: 5 :: 11
map += 4L -> "test" //4 is defined; think, -1 :: 4 :: 5 :: 11
val obj = new GenericPool(map, 11)
obj.Get() match {
case Success(number) =>
number mustEqual 8 // think, -1 :: 4 :: 5 :: 8 :: 11
case _ =>
ko
}
}
}
}

View file

@ -0,0 +1,329 @@
// Copyright (c) 2017 PSForever
package objects.number
import net.psforever.objects.guid.selector.{RandomSequenceSelector, _}
import org.specs2.mutable.Specification
class NumberSelectorTest extends Specification {
def randArrayGen(n: Int = 26, dx: Int = 0): Array[Int] = {
val obj = Array.ofDim[Int](n)
(0 to 25).foreach(x => { obj(x) = x + dx })
obj
}
"RandomSequenceSelector (0, default)" should {
"construct" in {
new RandomSequenceSelector
ok
}
"get a number" in {
val n: Int = 26
val obj = new RandomSequenceSelector
obj.Get(randArrayGen(n)) mustNotEqual -1
}
"return a number" in {
val n: Int = 26
val obj = new RandomSequenceSelector
val ary = randArrayGen(n)
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val n = 26
val obj = new RandomSequenceSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
ok
}
"return all numbers" in {
val n = 26
val obj = new RandomSequenceSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) }) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true }) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new RandomSequenceSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
obj.Get(ary) mustEqual -1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new RandomSequenceSelector).Format(ary)
ary mustEqual Array[Int](-1, -1, 1, 5, 3, 2)
}
}
"RandomSelector" should {
"construct" in {
new RandomSelector
ok
}
"get a number" in {
val obj = new RandomSelector
obj.Get(randArrayGen()) mustNotEqual -1
}
"return a number" in {
val obj = new RandomSelector
val ary = randArrayGen()
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val n = 26
val obj = new RandomSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
ok
}
"return all numbers" in {
val n = 26
val obj = new RandomSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) }) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true }) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new RandomSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
obj.Get(ary) mustEqual -1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new RandomSelector).Format(ary)
ary mustEqual Array[Int](-1, -1, 1, 5, 3, 2)
}
}
"StrictInOrderSelector" should {
"construct" in {
new StrictInOrderSelector
ok
}
"get a number" in {
val obj = new StrictInOrderSelector
obj.Get(randArrayGen()) mustNotEqual -1
}
"return a number" in {
val obj = new StrictInOrderSelector
val ary = randArrayGen()
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val n = 26
val obj = new StrictInOrderSelector
val ary = randArrayGen()
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
ok
}
"return all numbers" in {
val n = 26
val obj = new StrictInOrderSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) }) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true }) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new StrictInOrderSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
obj.Get(ary) mustEqual -1
}
"wait until number is available" in {
val n = 26
val obj = new StrictInOrderSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
obj.Get(ary) mustEqual -1
obj.Return(1, ary) //return a number that isn't the one StrictOrder is waiting on
obj.Get(ary) mustEqual -1
obj.Return(0, ary) //return the number StrictOrder wants
obj.Get(ary) mustEqual 0
obj.Get(ary) mustEqual 1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new StrictInOrderSelector).Format(ary)
ary mustEqual Array[Int](-1, 1, 2, 3, -1, 5)
}
}
"OpportunisticSelector" should {
"construct" in {
new OpportunisticSelector
ok
}
"get a number" in {
val obj = new OpportunisticSelector
obj.Get(randArrayGen()) mustNotEqual -1
}
"return a number" in {
val obj = new OpportunisticSelector
val ary = randArrayGen()
val number = obj.Get(ary)
number mustNotEqual -1
ary.head mustEqual -1 //regardless of which number we actually got, the head of the array is now -1
obj.Return(number, ary)
ary.head mustEqual number //the returned number is at the head of the array
}
"get all numbers" in {
val obj = new OpportunisticSelector
val ary = randArrayGen()
(0 to 25).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
ok
}
"return all numbers" in {
val n = 26
val obj = new OpportunisticSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => { ary2(index) = obj.Get(ary1) }) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true }) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val n = 26
val obj = new OpportunisticSelector
val ary = randArrayGen(n)
(0 until n).foreach(_ => { obj.Get(ary) mustNotEqual -1 })
obj.Get(ary) mustEqual -1
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new OpportunisticSelector).Format(ary)
ary mustEqual Array[Int](-1, -1, 1, 5, 3, 2)
}
}
"SpecificSelector" should {
"construct" in {
new SpecificSelector
ok
}
"get a number" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
obj.Get(ary) mustEqual 5
obj.Get(ary) mustEqual -1 //now that 5 has been selected, the selector will only get a -1 from that position
}
"return a number" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
val number = obj.Get(ary)
number mustEqual 5
obj.Get(ary) mustEqual -1
obj.Return(number, ary)
obj.Get(ary) mustEqual number //the returned number is at the head of the array
}
"return a number (2)" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
val number = obj.Get(ary)
number mustEqual 5
obj.Get(ary) mustEqual -1
ary(number) mustEqual -1
obj.SelectionIndex = 10 //even if we move the selection index, the number will return to its last position
obj.Return(number, ary)
ary(number) mustEqual number //the returned number at the original index
obj.Get(
ary
) mustEqual 10 //of course, with the selection index changed, we will not get the same position next time
}
"get all numbers" in {
val n = 26
val obj = new SpecificSelector
val ary = randArrayGen(n)
(0 until n).foreach(i => {
obj.SelectionIndex = i
obj.Get(ary) mustEqual i
})
ok
}
"return all numbers" in {
val n = 26
val obj = new SpecificSelector
val ary1 = randArrayGen(n)
val ary2 = randArrayGen(n)
(0 until n).foreach(index => {
obj.SelectionIndex = index
ary2(index) = obj.Get(ary1)
}) //move numbers from ary1 to ary2
ary2.toSet.diff(ary1.toSet).size mustEqual n //no numbers between ary2 and ary1 match
(0 until n).foreach(index => { obj.Return(ary2(index), ary1) mustEqual true }) //return numbers from ary2 to ary1
ary2.toSet.diff(ary1.toSet).size mustEqual 0 //no difference in the content between ary2 and ary1
}
"gets invalid index when exhausted" in {
val obj = new SpecificSelector
val ary = randArrayGen()
obj.SelectionIndex = 5
obj.Get(ary) mustEqual 5
obj.Get(ary) mustEqual -1 //yes, it really is that simple
}
"format an array" in {
val ary = Array[Int](1, -1, 5, 3, -1, 2)
(new SpecificSelector).Format(ary)
ary mustEqual Array[Int](-1, 1, 2, 3, -1, 5)
}
}
}

View file

@ -0,0 +1,200 @@
// Copyright (c) 2017 PSForever
package objects.number
import net.psforever.objects.guid.AvailabilityPolicy
import net.psforever.objects.guid.key.{LoanedKey, SecureKey}
import net.psforever.types.PlanetSideGUID
import org.specs2.mutable.Specification
class NumberSourceTest extends Specification {
import net.psforever.objects.entity.IdentifiableEntity
private class TestClass extends IdentifiableEntity
"LimitedNumberSource" should {
import net.psforever.objects.guid.source.LimitedNumberSource
"construct" in {
val obj = LimitedNumberSource(25)
obj.Size mustEqual 26
obj.CountAvailable mustEqual 26
obj.CountUsed mustEqual 0
}
"get a number" in {
val obj = LimitedNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object.isEmpty mustEqual true
obj.Size mustEqual 26
obj.CountAvailable mustEqual 25
obj.CountUsed mustEqual 1
}
"assign the number" in {
val obj = LimitedNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.Object = new TestClass()
ok
}
"return a number (unused)" in {
val obj = LimitedNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret.isEmpty mustEqual true
obj.CountUsed mustEqual 0
}
"return a number (assigned)" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result: Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Object = test
obj.CountUsed mustEqual 1
val ret = obj.Return(result.get)
ret.contains(test) mustEqual true
obj.CountUsed mustEqual 0
}
"restrict a number (unassigned)" in {
val obj = LimitedNumberSource(25)
val result: Option[LoanedKey] = obj.Restrict(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object.isEmpty mustEqual true
}
"restrict a number (assigned + multiple assignments)" in {
val obj = LimitedNumberSource(25)
val test1 = new TestClass()
val test2 = new TestClass()
val result: Option[LoanedKey] = obj.Restrict(5)
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object.isEmpty mustEqual true
result.get.Object = None //assignment 1
result.get.Object.isEmpty mustEqual true //still unassigned
result.get.Object = test1 //assignment 2
result.get.Object.contains(test1) mustEqual true
result.get.Object = test2 //assignment 3
result.get.Object.contains(test1) mustEqual true //same as above
}
"return a restricted number (correctly fail)" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result: Option[LoanedKey] = obj.Restrict(5)
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Restricted
result.get.Object = test
obj.Return(5)
val result2: Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object.contains(test) mustEqual true
}
"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 mustEqual PlanetSideGUID(5)
val result2: Option[SecureKey] = obj.Get(5)
obj.Return(result2.get).contains(test) mustEqual true
}
"restrict a previously-assigned number" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result1: Option[LoanedKey] = obj.Available(5)
result1.isDefined mustEqual true
result1.get.Policy mustEqual AvailabilityPolicy.Leased
result1.get.Object = test
val result2: Option[LoanedKey] = obj.Restrict(5)
result2.isDefined mustEqual true
result2.get.Policy mustEqual AvailabilityPolicy.Restricted
result2.get.Object.contains(test) mustEqual true
}
"check a number (not previously gotten)" in {
val obj = LimitedNumberSource(25)
val result2: Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Available
result2.get.Object.isEmpty mustEqual true
}
"check a number (previously gotten)" in {
val obj = LimitedNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object.isEmpty mustEqual true
val result2: Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object.isEmpty mustEqual true
}
"check a number (assigned)" in {
val obj = LimitedNumberSource(25)
val result: Option[LoanedKey] = obj.Available(5)
result.isDefined mustEqual true
result.get.GUID mustEqual 5
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = new TestClass()
val result2: Option[SecureKey] = obj.Get(5)
result2.get.GUID mustEqual 5
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object mustEqual result.get.Object
}
"check a number (assigned and returned)" in {
val obj = LimitedNumberSource(25)
val test = new TestClass()
val result: Option[LoanedKey] = obj.Available(5)
result.get.Policy mustEqual AvailabilityPolicy.Leased
result.get.Object = test
val result2: Option[SecureKey] = obj.Get(5)
result2.get.Policy mustEqual AvailabilityPolicy.Leased
result2.get.Object.get mustEqual test
obj.Return(5).contains(test) mustEqual true
val result3: Option[SecureKey] = obj.Get(5)
result3.get.Policy mustEqual AvailabilityPolicy.Available
result3.get.Object.isEmpty mustEqual true
}
"clear" in {
val obj = LimitedNumberSource(25)
val test1 = new TestClass()
val test2 = new TestClass()
val test3 = new TestClass()
obj.Available(5) //no assignment
obj.Available(10).get.Object = test1
obj.Available(15).get.Object = test2
obj.Restrict(15)
obj.Restrict(20).get.Object = test3
obj.CountUsed mustEqual 4
val list: List[IdentifiableEntity] = obj.Clear()
obj.CountUsed mustEqual 0
list.size mustEqual 3
list.count(obj => obj == test1) mustEqual 1
list.count(obj => obj == test2) mustEqual 1
list.count(obj => obj == test3) mustEqual 1
}
}
}

View file

@ -0,0 +1,60 @@
// Copyright (c) 2017 PSForever
package objects.number
import akka.actor.ActorRef
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.isEmpty mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.isEmpty mustEqual true
}
"construct (object, callback)" in {
val reg = Register(obj, ActorRef.noSender)
reg.obj mustEqual obj
reg.number.isEmpty mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.contains(ActorRef.noSender) mustEqual true
}
"construct (object, suggested number)" in {
val reg = Register(obj, 5)
reg.obj mustEqual obj
reg.number.contains(5) mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.isEmpty mustEqual true
}
"construct (object, suggested number, callback)" in {
val reg = Register(obj, 5, ActorRef.noSender)
reg.obj mustEqual obj
reg.number.contains(5) mustEqual true
reg.name.isEmpty mustEqual true
reg.callback.contains(ActorRef.noSender) mustEqual true
}
"construct (object, pool name)" in {
val reg = Register(obj, "pool")
reg.obj mustEqual obj
reg.number.isEmpty mustEqual true
reg.name.contains("pool") mustEqual true
reg.callback.isEmpty mustEqual true
}
"construct (object, pool name, callback)" in {
val reg = Register(obj, "pool", ActorRef.noSender)
reg.obj mustEqual obj
reg.number.isEmpty mustEqual true
reg.name.contains("pool") mustEqual true
reg.callback.contains(ActorRef.noSender) mustEqual true
}
}
}

View file

@ -0,0 +1,386 @@
// Copyright (c) 2017 PSForever
package objects.number
import akka.actor.{ActorRef, ActorSystem, Props}
import base.ActorTest
import net.psforever.objects.entity.IdentifiableEntity
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.actor.{NumberPoolActor, Register, UniqueNumberSystem, Unregister}
import net.psforever.objects.guid.selector.RandomSelector
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.types.PlanetSideGUID
import scala.concurrent.duration._
import scala.util.{Failure, Success}
class AllocateNumberPoolActors extends ActorTest {
"AllocateNumberPoolActors" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList)
guid.AddPool("pool2", (3001 to 4000).toList)
guid.AddPool("pool3", (5001 to 6000).toList)
val actorMap = UniqueNumberSystemTest.AllocateNumberPoolActors(guid)
assert(actorMap.size == 4)
assert(actorMap.get("generic").isDefined) //automatically generated
assert(actorMap.get("pool1").isDefined)
assert(actorMap.get("pool2").isDefined)
assert(actorMap.get("pool3").isDefined)
}
}
class UniqueNumberSystemTest extends ActorTest() {
"UniqueNumberSystem" should {
"constructor" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList)
guid.AddPool("pool2", (3001 to 4000).toList)
guid.AddPool("pool3", (5001 to 6000).toList)
system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
//as long as it constructs ...
}
}
}
class UniqueNumberSystemTest1 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Register (success)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
val pool1 = (1001 to 2000).toList
val pool2 = (3001 to 4000).toList
val pool3 = (5001 to 6000).toList
guid.AddPool("pool1", pool1).Selector = new RandomSelector
guid.AddPool("pool2", pool2).Selector = new RandomSelector
guid.AddPool("pool3", pool3).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
assert(src.CountUsed == 0)
//pool1
for (_ <- 1 to 100) {
val testObj = new EntityTestClass()
uns ! Register(testObj, "pool1")
val msg = receiveOne(Duration.create(500, "ms"))
assert(msg.isInstanceOf[Success[_]])
assert(pool1.contains(testObj.GUID.guid))
}
//pool2
for (_ <- 1 to 100) {
val testObj = new EntityTestClass()
uns ! Register(testObj, "pool2")
val msg = receiveOne(Duration.create(500, "ms"))
assert(msg.isInstanceOf[Success[_]])
assert(pool2.contains(testObj.GUID.guid))
}
//pool3
for (_ <- 1 to 100) {
val testObj = new EntityTestClass()
uns ! Register(testObj, "pool3")
val msg = receiveOne(Duration.create(500, "ms"))
assert(msg.isInstanceOf[Success[_]])
assert(pool3.contains(testObj.GUID.guid))
}
assert(src.CountUsed == 300)
}
}
}
class UniqueNumberSystemTest2 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Register (success; already registered)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val testObj = new EntityTestClass()
assert(!testObj.HasGUID)
assert(src.CountUsed == 0)
uns ! Register(testObj, "pool1")
val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Success[_]])
assert(testObj.HasGUID)
assert(src.CountUsed == 1)
val id = testObj.GUID.guid
uns ! Register(testObj, "pool2") //different pool; makes no difference
val msg2 = receiveOne(Duration.create(500, "ms"))
assert(msg2.isInstanceOf[Success[_]])
assert(testObj.HasGUID)
assert(src.CountUsed == 1)
assert(testObj.GUID.guid == id) //unchanged
}
}
//a log.warn should have been generated during this test
}
class UniqueNumberSystemTest3 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Register (failure; no pool)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val testObj = new EntityTestClass()
assert(!testObj.HasGUID)
assert(src.CountUsed == 0)
uns ! Register(testObj, "pool4")
val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Failure[_]])
assert(!testObj.HasGUID)
assert(src.CountUsed == 0)
}
}
}
class UniqueNumberSystemTest4 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Register (failure; empty pool)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
guid.AddPool("pool4", 50 :: Nil).Selector = new RandomSelector //list of one element; can not add an empty list
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val testObj1 = new EntityTestClass()
uns ! Register(testObj1, "pool4")
val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Success[_]]) //pool4 is now empty
val testObj2 = new EntityTestClass()
uns ! Register(testObj2, "pool4")
val msg2 = receiveOne(Duration.create(500, "ms"))
assert(msg2.isInstanceOf[Failure[_]])
}
}
}
class UniqueNumberSystemTest5 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Unregister (success)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
val pool2 = (3001 to 4000).toList
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", pool2).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val testObj = new EntityTestClass()
assert(!testObj.HasGUID)
assert(src.CountUsed == 0)
uns ! Register(testObj, "pool2")
val msg1 = receiveOne(Duration.create(2000, "ms"))
assert(msg1.isInstanceOf[Success[_]])
assert(testObj.HasGUID)
assert(pool2.contains(testObj.GUID.guid))
assert(src.CountUsed == 1)
uns ! Unregister(testObj)
val msg2 = receiveOne(Duration.create(2000, "ms"))
assert(msg2.isInstanceOf[Success[_]])
assert(!testObj.HasGUID)
assert(src.CountUsed == 0)
}
}
}
class UniqueNumberSystemTest6 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Unregister (success; object not registered at all)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val testObj = new EntityTestClass()
assert(!testObj.HasGUID)
assert(src.CountUsed == 0)
uns ! Unregister(testObj)
val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Success[_]])
assert(!testObj.HasGUID)
assert(src.CountUsed == 0)
}
}
}
class UniqueNumberSystemTest7 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Unregister (failure; number not in system)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val testObj = new EntityTestClass()
testObj.GUID = PlanetSideGUID(6001) //fake registering; number too high
assert(testObj.HasGUID)
assert(src.CountUsed == 0)
uns ! Unregister(testObj)
val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Failure[_]])
assert(testObj.HasGUID)
assert(src.CountUsed == 0)
}
}
}
class UniqueNumberSystemTest8 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Unregister (failure; object is not registered to that number)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val testObj = new EntityTestClass()
testObj.GUID = PlanetSideGUID(3500) //fake registering
assert(testObj.HasGUID)
assert(src.CountUsed == 0)
uns ! Unregister(testObj)
val msg1 = receiveOne(Duration.create(500, "ms"))
assert(msg1.isInstanceOf[Failure[_]])
assert(testObj.HasGUID)
assert(src.CountUsed == 0)
}
}
}
class UniqueNumberSystemTest9 extends ActorTest() {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"Failures (manually walking the failure cases)" in {
val src: LimitedNumberSource = LimitedNumberSource(6000)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (1001 to 2000).toList).Selector = new RandomSelector
guid.AddPool("pool2", (3001 to 4000).toList).Selector = new RandomSelector
guid.AddPool("pool3", (5001 to 6000).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
val excp = new Exception("EXCEPTION MESSAGE")
expectNoMessage(Duration.create(200, "ms"))
//GiveNumber
uns ! NumberPoolActor.GiveNumber(1001, Some("test")) //no task associated with id="test"
uns ! NumberPoolActor.GiveNumber(1000, Some("test")) //no task associated with id="test" and number is not pooled
uns ! NumberPoolActor.GiveNumber(1000, Some(1)) //the task could theoretically exist, but does not
//NoNumber
uns ! NumberPoolActor.NoNumber(excp, Some(1))
uns ! NumberPoolActor.NoNumber(excp, None)
uns ! NumberPoolActor.NoNumber(excp, Some("test"))
//ReturnNumberResult A
uns ! NumberPoolActor.ReturnNumberResult(1001, None, Some("test"))
uns ! NumberPoolActor.ReturnNumberResult(1000, None, Some("test"))
uns ! NumberPoolActor.ReturnNumberResult(1001, None, Some(1))
uns ! NumberPoolActor.ReturnNumberResult(1000, None, Some(1))
//ReturnNumberResult B
uns ! NumberPoolActor.ReturnNumberResult(1001, Some(excp), Some("test"))
uns ! NumberPoolActor.ReturnNumberResult(1001, Some(excp), Some(1))
}
}
}
class UniqueNumberSystemTestA extends ActorTest {
class EntityTestClass extends IdentifiableEntity
"UniqueNumberSystem" should {
"remain consistent between registrations" in {
val src: LimitedNumberSource = LimitedNumberSource(10)
val guid: NumberPoolHub = new NumberPoolHub(src)
guid.AddPool("pool1", (0 until 10).toList).Selector = new RandomSelector
val uns = system.actorOf(
Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystemTest.AllocateNumberPoolActors(guid)),
"uns"
)
expectNoMessage(Duration.create(200, "ms"))
assert(src.CountUsed == 0)
(0 to 4).foreach(i => { assert(guid.register(new EntityTestClass(), i).isSuccess) })
assert(src.CountUsed == 5)
(0 to 5).foreach(_ => { uns ! Register(new EntityTestClass(), "pool1") })
assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //6th
assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //7th
assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //8th
assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //9th
assert(receiveOne(200 milliseconds).isInstanceOf[Success[_]]) //10th
assert(receiveOne(200 milliseconds).isInstanceOf[Failure[_]]) //no more
assert(src.CountUsed == 10)
}
}
}
object UniqueNumberSystemTest {
/**
* @see `UniqueNumberSystem.AllocateNumberPoolActors(NumberPoolHub)(implicit ActorContext)`
*/
def AllocateNumberPoolActors(poolSource: NumberPoolHub)(implicit system: ActorSystem): Map[String, ActorRef] = {
poolSource.Pools
.map({
case (pname, pool) =>
pname -> system.actorOf(Props(classOf[NumberPoolActor], pool), pname)
})
.toMap
}
}

View file

@ -0,0 +1,194 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import akka.actor.{ActorSystem, Props}
import base.ActorTest
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.{Default, GlobalDefinitions, Player}
import net.psforever.objects.definition.SeatDefinition
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.LimitedNumberSource
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.vehicles.Seat
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
import org.specs2.mutable.Specification
import scala.concurrent.duration.Duration
class ImplantTerminalMechTest extends Specification {
"Implant_Terminal_Mech" should {
"define" in {
val implant_terminal_mech = GlobalDefinitions.implant_terminal_mech
implant_terminal_mech.ObjectId mustEqual 410
implant_terminal_mech.MountPoints mustEqual Map(1 -> 0)
implant_terminal_mech.Seats.keySet mustEqual Set(0)
implant_terminal_mech.Seats(0).isInstanceOf[SeatDefinition] mustEqual true
implant_terminal_mech
.Seats(0)
.ArmorRestriction mustEqual net.psforever.objects.vehicles.SeatArmorRestriction.NoMax
implant_terminal_mech.Seats(0).Bailable mustEqual false
implant_terminal_mech.Seats(0).ControlledWeapon.isEmpty mustEqual true
}
}
"Implant_Terminal_Mech" should {
"construct" in {
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
obj.Actor mustEqual Default.Actor
obj.Definition mustEqual GlobalDefinitions.implant_terminal_mech
obj.Seats.keySet mustEqual Set(0)
obj.Seats(0).isInstanceOf[Seat] mustEqual true
}
"get seat from mount points" in {
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
obj.GetSeatFromMountPoint(0).isEmpty mustEqual true
obj.GetSeatFromMountPoint(1).contains(0) mustEqual true
obj.GetSeatFromMountPoint(2).isEmpty mustEqual true
}
"get passenger in a seat" in {
val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
obj.PassengerInSeat(player).isEmpty mustEqual true
obj.Seats(0).Occupant = player
obj.PassengerInSeat(player).contains(0) mustEqual true
obj.Seats(0).Occupant = None
obj.PassengerInSeat(player).isEmpty mustEqual true
}
}
}
class ImplantTerminalMechControl1Test extends ActorTest {
"ImplantTerminalMechControl" should {
"construct" in {
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
obj.Actor = system.actorOf(Props(classOf[ImplantTerminalMechControl], obj), "mech")
assert(obj.Actor != Default.Actor)
}
}
}
class ImplantTerminalMechControl2Test extends ActorTest {
"ImplantTerminalMechControl" should {
"let a player mount" in {
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
val msg = Mountable.TryMount(player, 0)
mech.Actor ! msg
val reply = receiveOne(Duration.create(200, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player)
assert(reply2.response.isInstanceOf[Mountable.CanMount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanMount]
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
}
}
}
class ImplantTerminalMechControl3Test extends ActorTest {
import net.psforever.types.CharacterGender
"ImplantTerminalMechControl" should {
"block a player from mounting" in {
val (player1, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
val player2 = Player(Avatar(1, "test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
mech.Actor ! Mountable.TryMount(player1, 0)
receiveOne(Duration.create(100, "ms")) //consume reply
mech.Actor ! Mountable.TryMount(player2, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player2)
assert(reply2.response.isInstanceOf[Mountable.CanNotMount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanNotMount]
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
}
}
}
class ImplantTerminalMechControl4Test extends ActorTest {
"ImplantTerminalMechControl" should {
"dismount player after mounting" in {
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
mech.Actor ! Mountable.TryMount(player, 0)
receiveOne(Duration.create(200, "ms")) //consume reply
assert(mech.Seat(0).get.isOccupied)
mech.Actor ! Mountable.TryDismount(player, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player)
assert(reply2.response.isInstanceOf[Mountable.CanDismount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanDismount]
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
assert(!mech.Seat(0).get.isOccupied)
}
}
}
class ImplantTerminalMechControl5Test extends ActorTest {
"ImplantTerminalMechControl" should {
"block a player from dismounting" in {
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
mech.Actor ! Mountable.TryMount(player, 0)
receiveOne(Duration.create(100, "ms")) //consume reply
assert(mech.Seat(0).get.isOccupied)
mech.Velocity = Vector3(1, 0, 0) //makes no sense, but it works as the "seat" is not bailable
mech.Actor ! Mountable.TryDismount(player, 0)
val reply = receiveOne(Duration.create(100, "ms"))
assert(reply.isInstanceOf[Mountable.MountMessages])
val reply2 = reply.asInstanceOf[Mountable.MountMessages]
assert(reply2.player == player)
assert(reply2.response.isInstanceOf[Mountable.CanNotDismount])
val reply3 = reply2.response.asInstanceOf[Mountable.CanNotDismount]
assert(reply3.obj == mech)
assert(reply3.seat_num == 0)
assert(mech.Seat(0).get.isOccupied)
}
}
}
object ImplantTerminalMechTest {
def SetUpAgents(faction: PlanetSideEmpire.Value)(implicit system: ActorSystem): (Player, ImplantTerminalMech) = {
val guid = new NumberPoolHub(new LimitedNumberSource(10))
val map = new ZoneMap("test")
val zone = new Zone("test", map, 0) {
override def SetupNumberPools() = {}
GUID(guid)
}
val building = new Building(
"Building",
building_guid = 0,
map_id = 0,
zone,
StructureType.Building,
GlobalDefinitions.building
) //guid=3
building.Faction = faction
val interface = Terminal(GlobalDefinitions.implant_terminal_interface) //guid=2
interface.Owner = building
val terminal = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech) //guid=1
terminal.Owner = building
guid.register(terminal, 1)
guid.register(interface, 2)
guid.register(building, 3)
map.linkTerminalToInterface(1, 2)
terminal.Actor = system.actorOf(Props(classOf[ImplantTerminalMechControl], terminal), "terminal-control")
(Player(Avatar(0, "test", faction, CharacterGender.Male, 0, CharacterVoice.Mute)), terminal)
}
}

View file

@ -0,0 +1,32 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal}
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
import net.psforever.packet.game.ItemTransactionMessage
import net.psforever.types._
import org.specs2.mutable.Specification
class MatrixTerminalTest extends Specification {
"MatrixTerminal" should {
"define" in {
val a = new MatrixTerminalDefinition(517)
a.ObjectId mustEqual 517
}
"creation" in {
Terminal(new MatrixTerminalDefinition(518))
ok
}
"invalid message" in {
val player = Player(Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
val terminal = Terminal(new MatrixTerminalDefinition(519))
terminal.Owner = Vehicle(GlobalDefinitions.quadstealth)
terminal.Owner.Faction = PlanetSideEmpire.TR
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
}
}

View file

@ -0,0 +1,197 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.objects._
import net.psforever.objects.avatar.{Avatar, Certification}
import net.psforever.packet.game.ItemTransactionMessage
import net.psforever.types._
import org.specs2.mutable.Specification
class OrderTerminalTest extends Specification {
val avatar = Avatar(0, "test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute)
val player = Player(avatar)
val building = new Building(
"Building",
building_guid = 0,
map_id = 0,
Zone.Nowhere,
StructureType.Building,
GlobalDefinitions.building
)
building.Faction = PlanetSideEmpire.TR
val infantryTerminal = Terminal(GlobalDefinitions.order_terminal)
infantryTerminal.Owner = building
"General terminal behavior" should {
"player can not buy equipment from the wrong page ('9mmbullet_AP', page 10)" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "9mmbullet_AP", 0, PlanetSideGUID(0))
infantryTerminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
}
"Infantry Order Terminal" should {
"player can buy a box of ammunition ('9mmbullet_AP')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "9mmbullet_AP", 0, PlanetSideGUID(0))
val reply = infantryTerminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyEquipment]
reply2.item.isInstanceOf[AmmoBox] mustEqual true
reply2.item.asInstanceOf[AmmoBox].Definition mustEqual GlobalDefinitions.bullet_9mm_AP
}
"player can buy a weapon ('suppressor')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "suppressor", 0, PlanetSideGUID(0))
val reply = infantryTerminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyEquipment]
reply2.item.isInstanceOf[Tool] mustEqual true
reply2.item.asInstanceOf[Tool].Definition mustEqual GlobalDefinitions.suppressor
}
"player can buy different armor ('lite_armor')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
infantryTerminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile)
}
"player can buy a box of ammunition belonging to a special armor type ('dualcycler_ammo')" in {
val msg =
ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "dualcycler_ammo", 0, PlanetSideGUID(0))
val reply = infantryTerminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyEquipment]
reply2.item.isInstanceOf[AmmoBox] mustEqual true
reply2.item.asInstanceOf[AmmoBox].Definition mustEqual GlobalDefinitions.dualcycler_ammo
}
"player can buy a support tool ('bank')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 2, "bank", 0, PlanetSideGUID(0))
val reply = infantryTerminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyEquipment]
reply2.item.isInstanceOf[Tool] mustEqual true
reply2.item.asInstanceOf[Tool].Definition mustEqual GlobalDefinitions.bank
}
"player can buy a box of vehicle ammunition ('105mmbullet')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 3, "105mmbullet", 0, PlanetSideGUID(0))
val reply = infantryTerminal.Request(player, msg)
reply.isInstanceOf[Terminal.BuyEquipment] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.BuyEquipment]
reply2.item.isInstanceOf[AmmoBox] mustEqual true
reply2.item.asInstanceOf[AmmoBox].Definition mustEqual GlobalDefinitions.bullet_105mm
}
"player can not buy fake equipment ('sabot')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "sabot", 0, PlanetSideGUID(0))
infantryTerminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
"player can not retrieve an infantry loadout from the wrong line" in {
val msg = infantryTerminal.Request(
player,
ItemTransactionMessage(PlanetSideGUID(10), TransactionType.Loadout, 4, "", 1, PlanetSideGUID(0))
)
msg.isInstanceOf[Terminal.NoDeal] mustEqual true
}
}
"Vehicle Terminal" should {
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
terminal.Owner = building
"player can spawn a vehicle and its default trunk contents" in {
val msg =
ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 46769, "quadassault", 0, PlanetSideGUID(0))
terminal.Request(player, msg) match {
case Terminal.BuyVehicle(vehicle, weapons, trunk) =>
vehicle.Definition mustEqual GlobalDefinitions.quadassault
weapons.size mustEqual 0 //note: vehicles never have custom weapons using the default loadout
trunk.size mustEqual 4
trunk.head.obj.Definition mustEqual GlobalDefinitions.bullet_12mm
trunk(1).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
trunk(2).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
trunk(3).obj.Definition mustEqual GlobalDefinitions.bullet_12mm
case _ =>
ko
}
}
"player can not spawn a fake vehicle ('harasser')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 46769, "harasser", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
}
"Certification Terminal" should {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Owner = building
"player can learn a certification ('medium_assault')" in {
val msg =
ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.LearnCertification(Certification.MediumAssault)
}
"player can not learn a fake certification ('juggling')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "juggling", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
"player can forget a certification ('medium_assault')" in {
val msg =
ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.SellCertification(Certification.MediumAssault)
}
"player can not forget a fake certification ('juggling')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "juggling", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
}
"Implant_Terminal_Interface" should {
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
terminal.Owner = building
"player can learn an implant ('darklight_vision')" in {
val msg =
ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "darklight_vision", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.LearnImplant] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.LearnImplant]
reply2.implant mustEqual GlobalDefinitions.darklight_vision
}
"player can not learn a fake implant ('aimbot')" in {
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "aimbot", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
"player can un-learn an implant ('darklight_vision')" in {
val msg =
ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "darklight_vision", 0, PlanetSideGUID(0))
val reply = terminal.Request(player, msg)
reply.isInstanceOf[Terminal.SellImplant] mustEqual true
val reply2 = reply.asInstanceOf[Terminal.SellImplant]
reply2.implant mustEqual GlobalDefinitions.darklight_vision
}
"player can not un-learn a fake implant ('aimbot')" in {
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "aimbot", 0, PlanetSideGUID(0))
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
}
}
}

View file

@ -0,0 +1,429 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import java.util.concurrent.atomic.AtomicInteger
import akka.actor.Props
import akka.testkit.TestProbe
import base.ActorTest
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.terminals.{
ProximityTerminal,
ProximityTerminalControl,
ProximityUnit,
Terminal
}
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, PlanetSideGUID}
import org.specs2.mutable.Specification
import net.psforever.services.Service
import net.psforever.services.local.LocalService
import scala.concurrent.duration._
import akka.actor.typed.scaladsl.adapter._
import net.psforever.objects.avatar.Avatar
class ProximityTest extends Specification {
"ProximityUnit" should {
"construct (with a Terminal object)" in {
val obj = new ProximityTest.SampleTerminal()
obj.NumberUsers mustEqual 0
}
"keep track of users (add)" in {
val avatar1 =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar1.Spawn()
avatar1.Health = 50
val avatar2 =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter2",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar2.Spawn()
avatar2.Health = 50
val obj = new ProximityTerminal(GlobalDefinitions.medical_terminal)
obj.NumberUsers mustEqual 0
obj.AddUser(avatar1) mustEqual true
obj.NumberUsers mustEqual 1
obj.AddUser(avatar2) mustEqual true
obj.NumberUsers mustEqual 2
}
"keep track of users (remove)" in {
val avatar1 =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar1.Spawn()
avatar1.Health = 50
val avatar2 =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter2",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar2.Spawn()
avatar2.Health = 50
val obj = new ProximityTerminal(GlobalDefinitions.medical_terminal)
obj.NumberUsers mustEqual 0
obj.AddUser(avatar1) mustEqual true
obj.NumberUsers mustEqual 1
obj.AddUser(avatar2) mustEqual true
obj.NumberUsers mustEqual 2
obj.RemoveUser(avatar1) mustEqual true
obj.NumberUsers mustEqual 1
obj.RemoveUser(avatar2) mustEqual true
obj.NumberUsers mustEqual 0
}
"can not add a user twice" in {
val avatar =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar.Spawn()
avatar.Health = 50
val obj = new ProximityTerminal(GlobalDefinitions.medical_terminal)
obj.AddUser(avatar) mustEqual true
obj.NumberUsers mustEqual 1
obj.AddUser(avatar) // mustEqual false
obj.NumberUsers mustEqual 1
}
"can not remove a user that was not added" in {
val avatar =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar.Spawn()
avatar.Health = 50
val obj = new ProximityTest.SampleTerminal()
obj.RemoveUser(avatar) mustEqual false
obj.NumberUsers mustEqual 0
}
}
"ProximityTerminal" should {
"construct" in {
ProximityTerminal(GlobalDefinitions.medical_terminal)
ok
}
}
}
class ProximityTerminalControlStartTest extends ActorTest {
"ProximityTerminalControl" should {
//setup
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
actor = system.spawn(ZoneActor(this), "test-zone")
override def SetupNumberPools() = {
AddPool("dynamic", 1 to 10)
}
}
val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal)
terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox")
new Building("Building", building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) {
Amenities = terminal
Faction = PlanetSideEmpire.VS
}
val avatar =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar.Continent = "test"
avatar.Spawn()
avatar.Health = 50
avatar.GUID = PlanetSideGUID(1)
terminal.GUID = PlanetSideGUID(2)
terminal.Actor ! Service.Startup()
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback")
zone.LocalEvents = probe1.ref
"send out a start message" in {
assert(terminal.NumberUsers == 0)
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect])
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
assert(terminal.NumberUsers == 1)
}
}
}
class ProximityTerminalControlTwoUsersTest extends ActorTest {
"ProximityTerminalControl" should {
//setup
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
actor = system.spawn(ZoneActor(this), "test-zone")
override def SetupNumberPools() = {
AddPool("dynamic", 1 to 10)
}
}
val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal)
terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox")
new Building("Building", building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) {
Amenities = terminal
Faction = PlanetSideEmpire.VS
}
val avatar =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar.Continent = "test"
avatar.Spawn()
avatar.Health = 50
val avatar2 =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter2",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar2.Continent = "test"
avatar2.Spawn()
avatar2.Health = 50
avatar.GUID = PlanetSideGUID(1)
avatar2.GUID = PlanetSideGUID(2)
terminal.GUID = PlanetSideGUID(3)
terminal.Actor ! Service.Startup()
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback-1")
val probe3 = new TestProbe(system, "target-callback-2")
zone.LocalEvents = probe1.ref
"not send out a start message if not the first user" in {
assert(terminal.NumberUsers == 0)
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect])
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
terminal.Actor.tell(CommonMessages.Use(avatar2, Some(avatar2)), probe3.ref)
probe1.expectNoMessage(1 second)
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
probe3.expectMsgClass(1 second, classOf[ProximityUnit.Action])
assert(terminal.NumberUsers == 2)
}
}
}
class ProximityTerminalControlStopTest extends ActorTest {
"ProximityTerminalControl" should {
//setup
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
actor = system.spawn(ZoneActor(this), "test-zone")
override def SetupNumberPools() = {
AddPool("dynamic", 1 to 10)
}
}
val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal)
terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox")
new Building("Building", building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) {
Amenities = terminal
Faction = PlanetSideEmpire.VS
}
val avatar =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar.Continent = "test"
avatar.Spawn()
avatar.Health = 50
avatar.GUID = PlanetSideGUID(1)
terminal.GUID = PlanetSideGUID(2)
terminal.Actor ! Service.Startup()
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback-1")
zone.LocalEvents = probe1.ref
"send out a stop message" in {
assert(terminal.NumberUsers == 0)
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
probe1.expectMsgClass(1 second, classOf[Terminal.StartProximityEffect])
probe2.expectMsgClass(1 second, classOf[ProximityUnit.Action])
terminal.Actor ! CommonMessages.Unuse(avatar, Some(avatar))
probe1.expectMsgClass(1 second, classOf[Terminal.StopProximityEffect])
assert(terminal.NumberUsers == 0)
}
}
}
class ProximityTerminalControlNotStopTest extends ActorTest {
"ProximityTerminalControl" should {
//setup
val zone: Zone = new Zone("test", new ZoneMap("test-map"), 0) {
actor = system.spawn(ZoneActor(this), "test-zone")
override def SetupNumberPools() = {
AddPool("dynamic", 1 to 10)
}
}
val terminal = new ProximityTerminal(GlobalDefinitions.medical_terminal)
terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-prox")
new Building("Building", building_guid = 0, map_id = 0, zone, StructureType.Facility, GlobalDefinitions.building) {
Amenities = terminal
Faction = PlanetSideEmpire.VS
}
val avatar =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter1",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar.Continent = "test"
avatar.Spawn()
avatar.Health = 50
val avatar2 =
Player(
Avatar(
ProximityTest.avatarId.getAndIncrement(),
"TestCharacter2",
PlanetSideEmpire.VS,
CharacterGender.Female,
1,
CharacterVoice.Voice1
)
)
avatar2.Continent = "test"
avatar2.Spawn()
avatar2.Health = 50
avatar.GUID = PlanetSideGUID(1)
avatar2.GUID = PlanetSideGUID(2)
terminal.GUID = PlanetSideGUID(3)
terminal.Actor ! Service.Startup()
expectNoMessage(500 milliseconds) //spacer
val probe1 = new TestProbe(system, "local-events")
val probe2 = new TestProbe(system, "target-callback-1")
val probe3 = new TestProbe(system, "target-callback-2")
zone.LocalEvents = probe1.ref
"will not send out one stop message until last user" in {
assert(terminal.NumberUsers == 0)
assert(terminal.Owner.Continent.equals("test"))
terminal.Actor.tell(CommonMessages.Use(avatar, Some(avatar)), probe2.ref)
probe1.expectMsgClass(100 millisecond, classOf[Terminal.StartProximityEffect])
assert(terminal.NumberUsers == 1)
terminal.Actor.tell(CommonMessages.Use(avatar2, Some(avatar2)), probe3.ref)
probe1.expectNoMessage(100 millisecond)
assert(terminal.NumberUsers == 2)
terminal.Actor ! CommonMessages.Unuse(avatar, Some(avatar))
probe1.expectNoMessage(100 millisecond)
assert(terminal.NumberUsers == 1)
terminal.Actor ! CommonMessages.Unuse(avatar2, Some(avatar2))
probe1.expectMsgClass(100 millisecond, classOf[Terminal.StopProximityEffect])
assert(terminal.NumberUsers == 0)
}
}
}
object ProximityTest {
val avatarId = new AtomicInteger(0)
class SampleTerminal extends Terminal(GlobalDefinitions.dropship_vehicle_terminal) with ProximityUnit
class ProbedLocalService(probe: TestProbe, zone: Zone) extends LocalService(zone) {
self.tell(Service.Join("test"), probe.ref)
}
}

View file

@ -0,0 +1,148 @@
// Copyright (c) 2017 PSForever
package objects.terminal
import akka.actor.{ActorSystem, Props}
import base.ActorTest
import net.psforever.objects.avatar.{Avatar, Certification}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl, TerminalDefinition}
import net.psforever.objects.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player}
import net.psforever.packet.game.ItemTransactionMessage
import net.psforever.types._
import scala.concurrent.duration.Duration
class TerminalControl1Test extends ActorTest {
"TerminalControl" should {
"construct (cert terminal)" in {
val terminal = Terminal(GlobalDefinitions.cert_terminal)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-cert-term")
}
}
}
class TerminalControl2Test extends ActorTest {
"TerminalControl can not process wrong messages" in {
val (_, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
terminal.Actor ! "hello"
expectNoMessage(Duration.create(500, "ms"))
}
}
//terminal control is mostly a pass-through actor for Terminal.Exchange messages, wrapped in Terminal.TerminalMessage protocol
//test for Cert_Terminal messages (see CertTerminalTest)
class CertTerminalControl1Test extends ActorTest {
"TerminalControl can be used to learn a certification ('medium_assault')" in {
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
val msg =
ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Terminal.TerminalMessage])
val reply2 = reply.asInstanceOf[Terminal.TerminalMessage]
assert(reply2.player == player)
assert(reply2.msg == msg)
assert(reply2.response == Terminal.LearnCertification(Certification.MediumAssault))
}
}
class CertTerminalControl2Test extends ActorTest {
"TerminalControl can be used to warn about not learning a fake certification ('juggling')" in {
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "juggling", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Terminal.TerminalMessage])
val reply2 = reply.asInstanceOf[Terminal.TerminalMessage]
assert(reply2.player == player)
assert(reply2.msg == msg)
assert(reply2.response == Terminal.NoDeal())
}
}
class CertTerminalControl3Test extends ActorTest {
"TerminalControl can be used to forget a certification ('medium_assault')" in {
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "medium_assault", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Terminal.TerminalMessage])
val reply2 = reply.asInstanceOf[Terminal.TerminalMessage]
assert(reply2.player == player)
assert(reply2.msg == msg)
assert(reply2.response == Terminal.SellCertification(Certification.MediumAssault))
}
}
class VehicleTerminalControl1Test extends ActorTest {
"TerminalControl can be used to buy a vehicle ('two_man_assault_buggy')" in {
val (player, terminal) =
TerminalControlTest.SetUpAgents(GlobalDefinitions.ground_vehicle_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(
PlanetSideGUID(1),
TransactionType.Buy,
46769,
"two_man_assault_buggy",
0,
PlanetSideGUID(0)
)
terminal.Actor ! Terminal.Request(player, msg)
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Terminal.TerminalMessage])
val reply2 = reply.asInstanceOf[Terminal.TerminalMessage]
assert(reply2.player == player)
assert(reply2.msg == msg)
assert(reply2.response.isInstanceOf[Terminal.BuyVehicle])
val reply3 = reply2.response.asInstanceOf[Terminal.BuyVehicle]
assert(reply3.vehicle.Definition == GlobalDefinitions.two_man_assault_buggy)
assert(reply3.weapons == Nil)
assert(reply3.inventory.length == 6) //TODO
assert(reply3.inventory.head.obj.Definition == GlobalDefinitions.bullet_12mm)
assert(reply3.inventory(1).obj.Definition == GlobalDefinitions.bullet_12mm)
assert(reply3.inventory(2).obj.Definition == GlobalDefinitions.bullet_12mm)
assert(reply3.inventory(3).obj.Definition == GlobalDefinitions.bullet_12mm)
assert(reply3.inventory(4).obj.Definition == GlobalDefinitions.bullet_12mm)
assert(reply3.inventory(5).obj.Definition == GlobalDefinitions.bullet_12mm)
}
}
class VehicleTerminalControl2Test extends ActorTest {
"TerminalControl can be used to warn about not buy a vehicle ('harasser')" in {
val (player, terminal) =
TerminalControlTest.SetUpAgents(GlobalDefinitions.ground_vehicle_terminal, PlanetSideEmpire.TR)
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "harasser", 0, PlanetSideGUID(0))
terminal.Actor ! Terminal.Request(player, msg)
val reply = receiveOne(Duration.create(500, "ms"))
assert(reply.isInstanceOf[Terminal.TerminalMessage])
val reply2 = reply.asInstanceOf[Terminal.TerminalMessage]
assert(reply2.player == player)
assert(reply2.msg == msg)
assert(reply2.response == Terminal.NoDeal())
}
}
object TerminalControlTest {
def SetUpAgents(tdef: TerminalDefinition, faction: PlanetSideEmpire.Value)(implicit
system: ActorSystem
): (Player, Terminal) = {
val terminal = Terminal(tdef)
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-term")
terminal.Owner = new Building(
"Building",
building_guid = 0,
map_id = 0,
Zone.Nowhere,
StructureType.Building,
GlobalDefinitions.building
)
terminal.Owner.Faction = faction
(Player(Avatar(0, "test", faction, CharacterGender.Male, 0, CharacterVoice.Mute)), terminal)
}
}