From 35ed000ccc752bb87beb68947e4a42be8a06335a Mon Sep 17 00:00:00 2001 From: FateJH Date: Wed, 18 Apr 2018 18:29:40 -0400 Subject: [PATCH] code documentation and tests --- .../objects/serverobject/CommonMessages.scala | 2 + .../terminals/MedicalTerminalDefinition.scala | 10 +- .../terminals/ProximityTerminal.scala | 18 ++- .../terminals/ProximityTerminalControl.scala | 12 +- .../serverobject/terminals/Terminal.scala | 8 ++ .../objects/ServerObjectBuilderTest.scala | 19 +++ .../terminal/MedicalTerminalTest.scala | 90 +++++++++++++ .../ProximityTerminalControlTest.scala | 121 ++++++++++++++++++ .../src/main/scala/WorldSessionActor.scala | 94 ++++++++++---- pslogin/src/test/scala/LocalServiceTest.scala | 115 +++++++++++++++++ 10 files changed, 452 insertions(+), 37 deletions(-) create mode 100644 common/src/test/scala/objects/terminal/MedicalTerminalTest.scala create mode 100644 common/src/test/scala/objects/terminal/ProximityTerminalControlTest.scala create mode 100644 pslogin/src/test/scala/LocalServiceTest.scala diff --git a/common/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala b/common/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala index c73b7a23..ad7a26b6 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala @@ -5,6 +5,8 @@ import net.psforever.objects.Player //temporary location for these messages object CommonMessages { + final case class Use(player : Player) + final case class Unuse(player : Player) final case class Hack(player : Player) final case class ClearHack() } diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala index a6abc94c..fbd7f012 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/MedicalTerminalDefinition.scala @@ -4,6 +4,14 @@ package net.psforever.objects.serverobject.terminals import net.psforever.objects.Player import net.psforever.packet.game.ItemTransactionMessage +/** + * The definition for any `Terminal` that is of a type "medical_terminal". + * This includes the limited proximity-based functionality of the formal medical terminals + * and the actual proximity-based functionality of the cavern crystals.
+ *
+ * Do not confuse the "medical_terminal" category and the actual `medical_terminal` object (529). + * Objects created by this definition being linked by their use of `ProximityTerminalUseMessage` is more accurate. + */ class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objectId) { Name = if(objectId == 38) { "adv_med_terminal" @@ -21,7 +29,7 @@ class MedicalTerminalDefinition(objectId : Int) extends TerminalDefinition(objec "portable_med_terminal" } else { - throw new IllegalArgumentException("terminal must be either object id 38, object id 529, or object id 689") + throw new IllegalArgumentException("medical terminal must be either object id 38, 225, 226, 529, or 689") } def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal() diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala index b553a07d..c98e7da5 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminal.scala @@ -1,10 +1,17 @@ // Copyright (c) 2017 PSForever package net.psforever.objects.serverobject.terminals -import net.psforever.objects.Player import net.psforever.packet.game.PlanetSideGUID -class ProximityTerminal(tdef : TerminalDefinition) extends Terminal(tdef) { +/** + * A server object that is a "terminal" that can be accessed for amenities and services, + * triggered when a certain distance from the unit itself (proximity-based).
+ *
+ * Unlike conventional terminals, this structure is not necessarily structure-owned. + * For example, the cavern crystals are considered owner-neutral elements that are not attached to a `Building` object. + * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields + */ +class ProximityTerminal(tdef : MedicalTerminalDefinition) extends Terminal(tdef) { private var users : Set[PlanetSideGUID] = Set.empty def NumberUsers : Int = users.size @@ -21,14 +28,11 @@ class ProximityTerminal(tdef : TerminalDefinition) extends Terminal(tdef) { } object ProximityTerminal { - final case class Use(player : Player) - final case class Unuse(player : Player) - /** * Overloaded constructor. * @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields */ - def apply(tdef : TerminalDefinition) : ProximityTerminal = { + def apply(tdef : MedicalTerminalDefinition) : ProximityTerminal = { new ProximityTerminal(tdef) } @@ -41,7 +45,7 @@ object ProximityTerminal { * @param context a context to allow the object to properly set up `ActorSystem` functionality * @return the `Terminal` object */ - def Constructor(tdef : TerminalDefinition)(id : Int, context : ActorContext) : Terminal = { + def Constructor(tdef : MedicalTerminalDefinition)(id : Int, context : ActorContext) : Terminal = { import akka.actor.Props val obj = ProximityTerminal(tdef) obj.Actor = context.actorOf(Props(classOf[ProximityTerminalControl], obj), s"${tdef.Name}_$id") diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala index 3964ff30..407fd0cb 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityTerminalControl.scala @@ -2,20 +2,28 @@ package net.psforever.objects.serverobject.terminals import akka.actor.Actor +import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage +/** + * + * An `Actor` that handles messages being dispatched to a specific `ProximityTerminal`. + * Although this "terminal" itself does not accept the same messages as a normal `Terminal` object, + * it returns the same type of messages - wrapped in a `TerminalMessage` - to the `sender`. + * @param term the proximity unit (terminal) + */ class ProximityTerminalControl(term : ProximityTerminal) extends Actor with FactionAffinityBehavior.Check { def FactionObject : FactionAffinity = term def receive : Receive = checkBehavior.orElse { - case ProximityTerminal.Use(player) => + case CommonMessages.Use(player) => val hadNoUsers = term.NumberUsers == 0 if(term.AddUser(player.GUID) == 1 && hadNoUsers) { sender ! TerminalMessage(player, null, Terminal.StartProximityEffect(term)) } - case ProximityTerminal.Unuse(player) => + case CommonMessages.Unuse(player) => val hadUsers = term.NumberUsers > 0 if(term.RemoveUser(player.GUID) == 0 && hadUsers) { sender ! TerminalMessage(player, null, Terminal.StopProximityEffect(term)) diff --git a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala index 1bcf7455..b031a990 100644 --- a/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala +++ b/common/src/main/scala/net/psforever/objects/serverobject/terminals/Terminal.scala @@ -190,8 +190,16 @@ object Terminal { */ final case class InfantryLoadout(exosuit : ExoSuitType.Value, subtype : Int = 0, holsters : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange + /** + * Start the special effects caused by a proximity-base service. + * @param terminal the proximity-based unit + */ final case class StartProximityEffect(terminal : ProximityTerminal) extends Exchange + /** + * Stop the special effects caused by a proximity-base service. + * @param terminal the proximity-based unit + */ final case class StopProximityEffect(terminal : ProximityTerminal) extends Exchange /** diff --git a/common/src/test/scala/objects/ServerObjectBuilderTest.scala b/common/src/test/scala/objects/ServerObjectBuilderTest.scala index 813dbe36..49678d5f 100644 --- a/common/src/test/scala/objects/ServerObjectBuilderTest.scala +++ b/common/src/test/scala/objects/ServerObjectBuilderTest.scala @@ -6,6 +6,7 @@ import net.psforever.objects.guid.NumberPoolHub import net.psforever.packet.game.PlanetSideGUID 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.Vector3 @@ -130,6 +131,24 @@ class TerminalObjectBuilderTest extends ActorTest { } } +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 { diff --git a/common/src/test/scala/objects/terminal/MedicalTerminalTest.scala b/common/src/test/scala/objects/terminal/MedicalTerminalTest.scala new file mode 100644 index 00000000..89efb86f --- /dev/null +++ b/common/src/test/scala/objects/terminal/MedicalTerminalTest.scala @@ -0,0 +1,90 @@ +// Copyright (c) 2017 PSForever +package objects.terminal + +import akka.actor.ActorRef +import net.psforever.objects.serverobject.terminals.{MedicalTerminalDefinition, ProximityTerminal, Terminal} +import net.psforever.objects.{GlobalDefinitions, Player} +import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID} +import net.psforever.types.{CharacterGender, PlanetSideEmpire, TransactionType} +import org.specs2.mutable.Specification + +class MedicalTerminalTest extends Specification { + "MedicalTerminal" should { + "define (a)" in { + val a = new MedicalTerminalDefinition(38) + a.ObjectId mustEqual 38 + a.Name mustEqual "adv_med_terminal" + } + + "define (b)" in { + val b = new MedicalTerminalDefinition(225) + b.ObjectId mustEqual 225 + b.Name mustEqual "crystals_health_a" + } + + "define (c)" in { + val c = new MedicalTerminalDefinition(226) + c.ObjectId mustEqual 226 + c.Name mustEqual "crystals_health_b" + } + + "define (d)" in { + val d = new MedicalTerminalDefinition(529) + d.ObjectId mustEqual 529 + d.Name mustEqual "medical_terminal" + } + + "define (e)" in { + val e = new MedicalTerminalDefinition(689) + e.ObjectId mustEqual 689 + e.Name mustEqual "portable_med_terminal" + } + + "define (invalid)" in { + var id : Int = (math.random * Int.MaxValue).toInt + if(id == 224) { + id += 2 + } + else if(id == 37) { + id += 1 + } + else if(id == 528) { + id += 1 + } + else if(id == 688) { + id += 1 + } + + new MedicalTerminalDefinition(id) must throwA[IllegalArgumentException] + } + } + + "Medical_Terminal" should { + "construct" in { + ProximityTerminal(GlobalDefinitions.medical_terminal).Actor mustEqual ActorRef.noSender + } + + "can add a a player to a list of users" in { + val terminal = ProximityTerminal(GlobalDefinitions.medical_terminal) + terminal.NumberUsers mustEqual 0 + terminal.AddUser(PlanetSideGUID(10)) + terminal.NumberUsers mustEqual 1 + } + + "can remove a a player to a list of users" in { + val terminal = ProximityTerminal(GlobalDefinitions.medical_terminal) + terminal.AddUser(PlanetSideGUID(10)) + terminal.NumberUsers mustEqual 1 + terminal.RemoveUser(PlanetSideGUID(10)) + terminal.NumberUsers mustEqual 0 + } + + "player can not interact with the proximity terminal normally (buy)" in { + val terminal = ProximityTerminal(GlobalDefinitions.medical_terminal) + val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0) + val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0)) + + terminal.Request(player, msg) mustEqual Terminal.NoDeal() + } + } +} diff --git a/common/src/test/scala/objects/terminal/ProximityTerminalControlTest.scala b/common/src/test/scala/objects/terminal/ProximityTerminalControlTest.scala new file mode 100644 index 00000000..d288ff11 --- /dev/null +++ b/common/src/test/scala/objects/terminal/ProximityTerminalControlTest.scala @@ -0,0 +1,121 @@ +// Copyright (c) 2017 PSForever +package objects.terminal + +import akka.actor.{ActorSystem, Props} +import net.psforever.objects.serverobject.CommonMessages +import net.psforever.objects.{GlobalDefinitions, Player} +import net.psforever.objects.serverobject.terminals._ +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.{CharacterGender, PlanetSideEmpire} +import objects.ActorTest + +import scala.concurrent.duration.Duration + +class ProximityTerminalControl1Test extends ActorTest() { + "ProximityTerminalControl" should { + "construct (medical terminal)" in { + val terminal = ProximityTerminal(GlobalDefinitions.medical_terminal) + terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-term") + } + } +} + +class ProximityTerminalControl2Test extends ActorTest() { + "ProximityTerminalControl can not process wrong messages" in { + val (_, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR) + + terminal.Actor !"hello" + val reply = receiveOne(Duration.create(500, "ms")) + assert(reply.isInstanceOf[Terminal.NoDeal]) + } +} + +//terminal control is mostly a pass-through actor for Terminal.Exchange messages, wrapped in Terminal.TerminalMessage protocol +class MedicalTerminalControl1Test extends ActorTest() { + "ProximityTerminalControl sends a message to the first new user only" in { + val (player, terminal) = ProximityTerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR) + player.GUID = PlanetSideGUID(10) + val player2 = Player("someothertest", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0) + player2.GUID = PlanetSideGUID(11) + + terminal.Actor ! CommonMessages.Use(player) + 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 == null) + assert(reply2.response.isInstanceOf[Terminal.StartProximityEffect]) + assert(reply2.response.asInstanceOf[Terminal.StartProximityEffect].terminal == terminal) + assert(terminal.NumberUsers == 1) + + terminal.Actor ! CommonMessages.Use(player2) + expectNoMsg(Duration.create(500, "ms")) + assert(terminal.NumberUsers == 2) + } +} + +class MedicalTerminalControl2Test extends ActorTest() { + "ProximityTerminalControl sends a message to the last user only" in { + val (player, terminal) : (Player, ProximityTerminal) = ProximityTerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR) + player.GUID = PlanetSideGUID(10) + val player2 = Player("someothertest", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0) + player2.GUID = PlanetSideGUID(11) + + terminal.Actor ! CommonMessages.Use(player) + receiveOne(Duration.create(500, "ms")) + terminal.Actor ! CommonMessages.Use(player2) + expectNoMsg(Duration.create(500, "ms")) + assert(terminal.NumberUsers == 2) + + terminal.Actor ! CommonMessages.Unuse(player) + expectNoMsg(Duration.create(500, "ms")) + assert(terminal.NumberUsers == 1) + + terminal.Actor ! CommonMessages.Unuse(player2) + val reply = receiveOne(Duration.create(500, "ms")) + assert(reply.isInstanceOf[Terminal.TerminalMessage]) + val reply2 = reply.asInstanceOf[Terminal.TerminalMessage] + assert(reply2.player == player2) + assert(reply2.msg == null) + assert(reply2.response.isInstanceOf[Terminal.StopProximityEffect]) + assert(reply2.response.asInstanceOf[Terminal.StopProximityEffect].terminal == terminal) + assert(terminal.NumberUsers == 0) + } +} + +class MedicalTerminalControl3Test extends ActorTest() { + "ProximityTerminalControl sends a message to the last user only (confirmation of test #2)" in { + val (player, terminal) : (Player, ProximityTerminal) = ProximityTerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR) + player.GUID = PlanetSideGUID(10) + val player2 = Player("someothertest", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0) + player2.GUID = PlanetSideGUID(11) + + terminal.Actor ! CommonMessages.Use(player) + receiveOne(Duration.create(500, "ms")) + terminal.Actor ! CommonMessages.Use(player2) + expectNoMsg(Duration.create(500, "ms")) + assert(terminal.NumberUsers == 2) + + terminal.Actor ! CommonMessages.Unuse(player2) + expectNoMsg(Duration.create(500, "ms")) + assert(terminal.NumberUsers == 1) + + terminal.Actor ! CommonMessages.Unuse(player) + val reply = receiveOne(Duration.create(500, "ms")) + assert(reply.isInstanceOf[Terminal.TerminalMessage]) + val reply2 = reply.asInstanceOf[Terminal.TerminalMessage] + assert(reply2.player == player) //important! + assert(reply2.msg == null) + assert(reply2.response.isInstanceOf[Terminal.StopProximityEffect]) + assert(reply2.response.asInstanceOf[Terminal.StopProximityEffect].terminal == terminal) + assert(terminal.NumberUsers == 0) + } +} + +object ProximityTerminalControlTest { + def SetUpAgents(tdef : MedicalTerminalDefinition, faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, ProximityTerminal) = { + val terminal = ProximityTerminal(tdef) + terminal.Actor = system.actorOf(Props(classOf[ProximityTerminalControl], terminal), "test-term") + (Player("test", faction, CharacterGender.Male, 0, 0), terminal) + } +} diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index 19b0caa5..9ff88e90 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -2199,7 +2199,7 @@ class WorldSessionActor extends Actor with MDCContextAware { continent.GUID(object_guid) match { case Some(obj : ProximityTerminal) => if(usingProximityTerminal.contains(object_guid)) { - SelectProximityTerminal(obj) + SelectProximityUnit(obj) } else { //obj.Actor ! ProximityTerminal.Use(player) @@ -3637,6 +3637,11 @@ class WorldSessionActor extends Actor with MDCContextAware { } } + /** + * Start using a proximity-base service. + * Special note is warranted in the case of a medical terminal or an advanced medical terminal. + * @param terminal the proximity-based unit + */ def StartUsingProximityUnit(terminal : ProximityTerminal) : Unit = { val term_guid = terminal.GUID if(!usingProximityTerminal.contains(term_guid)) { @@ -3646,10 +3651,15 @@ class WorldSessionActor extends Actor with MDCContextAware { case _ => ; } usingProximityTerminal += term_guid - terminal.Actor ! ProximityTerminal.Use(player) + terminal.Actor ! CommonMessages.Use(player) } } + /** + * Stop using a proximity-base service. + * Special note is warranted in the case of a medical terminal or an advanced medical terminal. + * @param terminal the proximity-based unit + */ def StopUsingProximityUnit(terminal : ProximityTerminal) : Unit = { val term_guid = terminal.GUID if(usingProximityTerminal.contains(term_guid)) { @@ -3657,11 +3667,16 @@ class WorldSessionActor extends Actor with MDCContextAware { usingMedicalTerminal = None } usingProximityTerminal -= term_guid - terminal.Actor ! ProximityTerminal.Unuse(player) + terminal.Actor ! CommonMessages.Unuse(player) } } - def SelectProximityTerminal(terminal : ProximityTerminal) : Unit = { + /** + * Determine which functionality to pursue, by being given a generic proximity-functional unit + * and determinig which kind of unit is being utilized. + * @param terminal the proximity-based unit + */ + def SelectProximityUnit(terminal : ProximityTerminal) : Unit = { terminal.Definition match { case GlobalDefinitions.adv_med_terminal | GlobalDefinitions.medical_terminal => ProximityMedicalTerminal(terminal) @@ -3673,47 +3688,72 @@ class WorldSessionActor extends Actor with MDCContextAware { } } + /** + * When standing on the platform of a(n advanced) medical terminal, + * resotre the player's health and armor points (when they need their health and armor points restored). + * If the player is both fully healed and fully repaired, stop using the terminal. + * @param unit the medical terminal + */ def ProximityMedicalTerminal(terminal : ProximityTerminal) : Unit = { - val object_guid : PlanetSideGUID = terminal.GUID val healthUp : Boolean = player.Health < player.MaxHealth val armorUp : Boolean = player.Armor < player.MaxArmor if(healthUp || armorUp) { - val player_guid = player.GUID - val fullHealth = ProximityHeal(player_guid, object_guid) - val fullArmor = ProximityArmorRepair(player_guid, object_guid) + val fullHealth = HealAction(player) + val fullArmor = ArmorRepairAction(player) if(fullHealth && fullArmor) { - log.info(s"ProximityTerminal: ${player.Name} is all healed up") + log.info(s"${player.Name} is all healed up") StopUsingProximityUnit(terminal) } } } - def ProximityHealCrystal(terminal : ProximityTerminal) : Unit = { - val object_guid : PlanetSideGUID = terminal.GUID + /** + * When near a red cavern crystal, resotre the player's health (when they need their health restored). + * If the player is fully healed, stop using the crystal. + * @param unit the healing crystal + */ + def ProximityHealCrystal(unit : ProximityTerminal) : Unit = { val healthUp : Boolean = player.Health < player.MaxHealth if(healthUp) { - val player_guid = player.GUID - if(ProximityHeal(object_guid, player.GUID)) { - log.info(s"ProximityTerminal: ${player.Name} is all healed up") - StopUsingProximityUnit(terminal) + if(HealAction(player)) { + log.info(s"${player.Name} is all healed up") + StopUsingProximityUnit(unit) } } } - def ProximityHeal(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, healValue : Int = 10) : Boolean = { - log.info(s"ProximityTerminal: dispensing health to ${player.Name} - <3") - player.Health = player.Health + healValue - sendResponse(PlanetsideAttributeMessage(player_guid, 0, player.Health)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 0, player.Health)) - player.Health == player.MaxHealth + /** + * Restore, at most, a specific amount of health points on a player. + * Send messages to connected client and to events system. + * @param tplayer the player + * @param repairValue the amount to heal; + * 10 by default + * @return whether the player can be repaired for any more health points + */ + def HealAction(tplayer : Player, healValue : Int = 10) : Boolean = { + log.info(s"Dispensing health to ${tplayer.Name} - <3") + val player_guid = tplayer.GUID + tplayer.Health = tplayer.Health + healValue + sendResponse(PlanetsideAttributeMessage(player_guid, 0, tplayer.Health)) + avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, tplayer.Health)) + tplayer.Health == tplayer.MaxHealth } - def ProximityArmorRepair(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, repairValue : Int = 10) : Boolean = { - log.info(s"ProximityTerminal: dispensing armor to ${player.Name} - c[=") - player.Armor = player.Armor + repairValue - sendResponse(PlanetsideAttributeMessage(player_guid, 4, player.Armor)) - avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player.GUID, 4, player.Armor)) - player.Armor == player.MaxArmor + /** + * Restore, at most, a specific amount of personal armor points on a player. + * Send messages to connected client and to events system. + * @param tplayer the player + * @param repairValue the amount to repair; + * 10 by default + * @return whether the player can be repaired for any more armor points + */ + def ArmorRepairAction(tplayer : Player, repairValue : Int = 10) : Boolean = { + log.info(s"Dispensing armor to ${tplayer.Name} - c[=") + val player_guid = tplayer.GUID + tplayer.Armor = tplayer.Armor + repairValue + sendResponse(PlanetsideAttributeMessage(player_guid, 4, tplayer.Armor)) + avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 4, tplayer.Armor)) + tplayer.Armor == tplayer.MaxArmor } def failWithError(error : String) = { diff --git a/pslogin/src/test/scala/LocalServiceTest.scala b/pslogin/src/test/scala/LocalServiceTest.scala new file mode 100644 index 00000000..b6cbd696 --- /dev/null +++ b/pslogin/src/test/scala/LocalServiceTest.scala @@ -0,0 +1,115 @@ +// Copyright (c) 2017 PSForever +import akka.actor.Props +import net.psforever.objects.serverobject.PlanetSideServerObject +import net.psforever.packet.game.PlanetSideGUID +import net.psforever.types.{PlanetSideEmpire, Vector3} +import services.Service +import services.local._ + +class LocalService1Test extends ActorTest { + "LocalService" should { + "construct" in { + system.actorOf(Props[LocalService], "service") + assert(true) + } + } +} + +class LocalService2Test extends ActorTest { + "LocalService" should { + "subscribe" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + assert(true) + } + } +} + +class LocalService3Test extends ActorTest { + "LocalService" should { + "subscribe to a specific channel" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + service ! Service.Leave() + assert(true) + } + } +} + +class LocalService4Test extends ActorTest { + "LocalService" should { + "subscribe" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + service ! Service.LeaveAll() + assert(true) + } + } +} + +class LocalService5Test extends ActorTest { + "LocalService" should { + "pass an unhandled message" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + service ! "hello" + expectNoMsg() + } + } +} + +class DoorClosesTest extends ActorTest { + "LocalService" should { + "pass DoorCloses" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + service ! LocalServiceMessage("test", LocalAction.DoorCloses(PlanetSideGUID(10), PlanetSideGUID(40))) + expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.DoorCloses(PlanetSideGUID(40)))) + } + } +} + +class HackClearTest extends ActorTest { + val obj = new PlanetSideServerObject() { + def Faction = PlanetSideEmpire.NEUTRAL + def Definition = null + GUID = PlanetSideGUID(40) + } + + "LocalService" should { + "pass HackClear" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + service ! LocalServiceMessage("test", LocalAction.HackClear(PlanetSideGUID(10), obj, 0L, 1000L)) + expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.HackClear(PlanetSideGUID(40), 0L, 1000L))) + } + } +} + +class ProximityTerminalEffectTest extends ActorTest { + "LocalService" should { + "pass ProximityTerminalEffect" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + service ! LocalServiceMessage("test", LocalAction.ProximityTerminalEffect(PlanetSideGUID(10), PlanetSideGUID(40), true)) + expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.ProximityTerminalEffect(PlanetSideGUID(40), true))) + } + } +} + +class TriggerSoundTest extends ActorTest { + import net.psforever.packet.game.TriggeredSound + + "LocalService" should { + "pass TriggerSound" in { + val service = system.actorOf(Props[LocalService], "service") + service ! Service.Join("test") + service ! LocalServiceMessage("test", LocalAction.TriggerSound(PlanetSideGUID(10), TriggeredSound.LockedOut, Vector3(1.1f, 2.2f, 3.3f), 0, 0.75f)) + expectMsg(LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.TriggerSound(TriggeredSound.LockedOut, Vector3(1.1f, 2.2f, 3.3f), 0, 0.75f))) + } + } +} + +object LocalServiceTest { + //decoy +}