mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-02-23 16:43:43 +00:00
* Add .scalafmt.conf
* Adopt quill for database access
* Removed postgresql-async
* Refactored all instances of database access
* Creating duplicate characters of the same account is no longer possible
* Rewrote large parts of LoginSessionActor
* Implement migrations
* Move overrides into subdirectory
* Make usernames case insensitive
* Use LOWER(?) comparison instead of storing lowercased username
* import scala.util.{Success, Failure}
* Add config and joda-time dependencies
* Add sbt-scalafmt
* Use defaultWithAlign scalafmt preset
* Format all
* Add scalafix
* Remove unused imports
* Don't lowercase username when inserting
* Update readme
* Listen on worldserver.Hostname address
* Remove database test on startup
It could fail when the global thread pool is busy loading zone
maps. Migrations run on the main thread and also serve the
purpose of verifying the database configuration so it's fine to
remove the test altogether.
* Refactor chat message handlers, zones
What started as a small change to how zones are stored turned
into a pretty big effort of refactoring the chat message handler.
The !hack command was removed, the /capturebase commandwas added.
* Expose db ports in docker-compose.yml
* Silence property override log
* Rework configuration
* Unify configuration using the typesafe.config library
* Add configuration option for public address
* Configuration is now loaded from application.conf rather than worldserver.ini
* Refactor PsLogin and remove unnecessary logging
* Move pslogin into net.psforever.pslogin namespace
* Fix coverage
850 lines
30 KiB
Scala
850 lines
30 KiB
Scala
// Copyright (c) 2020 PSForever
|
|
package objects
|
|
|
|
import akka.actor.{ActorRef, Props}
|
|
import akka.testkit.TestProbe
|
|
import base.ActorTest
|
|
import net.psforever.objects.ballistics._
|
|
import net.psforever.objects.{Avatar, 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 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("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("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("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("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("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("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("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("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("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)
|
|
}
|
|
}
|
|
}
|