mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-02-26 10:03:41 +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
440 lines
16 KiB
Scala
440 lines
16 KiB
Scala
// 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.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 services.avatar.{AvatarAction, AvatarServiceMessage}
|
|
import 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("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("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("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("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("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("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 {}
|