mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-04-29 16:25:30 +00:00
Merge pull request #196 from Fate-JH/spawn-tube
The Real Resurrection Update
This commit is contained in:
commit
d8fe6bab28
70 changed files with 4562 additions and 1410 deletions
206
common/src/main/scala/net/psforever/objects/Avatar.scala
Normal file
206
common/src/main/scala/net/psforever/objects/Avatar.scala
Normal file
|
|
@ -0,0 +1,206 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects
|
||||||
|
|
||||||
|
import net.psforever.objects.definition.{AvatarDefinition, ImplantDefinition}
|
||||||
|
import net.psforever.objects.equipment.EquipmentSize
|
||||||
|
import net.psforever.types.{CertificationType, CharacterGender, ImplantType, PlanetSideEmpire}
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import scala.collection.mutable
|
||||||
|
|
||||||
|
class Avatar(val name : String, val faction : PlanetSideEmpire.Value, val sex : CharacterGender.Value, val head : Int, val voice : Int) {
|
||||||
|
/** Battle Experience Points */
|
||||||
|
private var bep : Long = 0
|
||||||
|
/** Command Experience Points */
|
||||||
|
private var cep : Long = 0
|
||||||
|
/** Certifications */
|
||||||
|
private val certs : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]()
|
||||||
|
/** Implants<br>
|
||||||
|
* Unlike other objects, the maximum number of `ImplantSlots` are built into the `Avatar`.
|
||||||
|
* Additionally, implants do not have tightly-coupled "`Definition` objects" that explain a formal implant object.
|
||||||
|
* The `ImplantDefinition` objects themselves are moved around as if they were the implants.
|
||||||
|
* The terms externally used for the states of process is "installed" and "uninstalled."
|
||||||
|
* @see `ImplantSlot`
|
||||||
|
* @see `DetailedCharacterData.implants`
|
||||||
|
*/
|
||||||
|
private val implants : Array[ImplantSlot] = Array.fill[ImplantSlot](3)(new ImplantSlot)
|
||||||
|
/** Loadouts */
|
||||||
|
private val loadouts : Array[Option[Loadout]] = Array.fill[Option[Loadout]](10)(None)
|
||||||
|
/** Locker (fifth inventory slot) */
|
||||||
|
private val locker : LockerContainer = LockerContainer()
|
||||||
|
|
||||||
|
def BEP : Long = bep
|
||||||
|
|
||||||
|
def BEP_=(battleExperiencePoints : Long) : Long = {
|
||||||
|
bep = math.max(0L, math.min(battleExperiencePoints, 4294967295L))
|
||||||
|
BEP
|
||||||
|
}
|
||||||
|
|
||||||
|
def Certifications : mutable.Set[CertificationType.Value] = certs
|
||||||
|
|
||||||
|
def CEP : Long = cep
|
||||||
|
|
||||||
|
def CEP_=(commandExperiencePoints : Long) : Long = {
|
||||||
|
cep = math.max(0L, math.min(commandExperiencePoints, 4294967295L))
|
||||||
|
CEP
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the three implant slots for this player.
|
||||||
|
* @return an `Array` of `ImplantSlot` objects
|
||||||
|
*/
|
||||||
|
def Implants : Array[ImplantSlot] = implants
|
||||||
|
|
||||||
|
/**
|
||||||
|
* What kind of implant is installed into the given slot number?
|
||||||
|
* @see `ImplantType`
|
||||||
|
* @param slot the slot number
|
||||||
|
* @return the tye of implant
|
||||||
|
*/
|
||||||
|
def Implant(slot : Int) : ImplantType.Value = {
|
||||||
|
if(-1 < slot && slot < implants.length) { implants(slot).Implant } else { ImplantType.None }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a new implant, assign it into a vacant implant slot on this player.<br>
|
||||||
|
* <br>
|
||||||
|
* The implant must be unique in terms of which implants have already been assigned to this player.
|
||||||
|
* Multiple of a type of implant being assigned at once is not supported.
|
||||||
|
* Additionally, the implant is inserted into the earliest yet-unknown but vacant slot.
|
||||||
|
* Implant slots are vacant by just being unlocked or by having their previous implant uninstalled.
|
||||||
|
* @param implant the implant being installed
|
||||||
|
* @return the index of the `ImplantSlot` where the implant was installed
|
||||||
|
*/
|
||||||
|
def InstallImplant(implant : ImplantDefinition) : Option[Int] = {
|
||||||
|
implants.find({p => p.Installed.contains(implant) || p.Implant == implant.Type}) match { //try to find the installed implant
|
||||||
|
case None =>
|
||||||
|
recursiveFindImplantInSlot(implants.iterator, ImplantType.None) match { //install in a free slot
|
||||||
|
case Some(slot) =>
|
||||||
|
implants(slot).Implant = implant
|
||||||
|
Some(slot)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
case Some(_) =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a specific implant from a player's allocated installed implants.<br>
|
||||||
|
* <br>
|
||||||
|
* Due to the exclusiveness of installed implants,
|
||||||
|
* any implant slot with a matching `Definition` can be uninstalled safely.
|
||||||
|
* (There will never be any doubles.)
|
||||||
|
* This operation can lead to an irregular pattern of installed and uninstalled `ImplantSlot` objects.
|
||||||
|
* Despite that breach of pattern, the logic here is consistent as demonstrated by the client and by packets.
|
||||||
|
* The client also assigns and removes implants based on slot numbers that only express availability of a "slot."
|
||||||
|
* @see `AvatarImplantMessage.implantSlot`
|
||||||
|
* @param implantType the type of implant being uninstalled
|
||||||
|
* @return the index of the `ImplantSlot` where the implant was found and uninstalled
|
||||||
|
*/
|
||||||
|
def UninstallImplant(implantType : ImplantType.Value) : Option[Int] = {
|
||||||
|
recursiveFindImplantInSlot(implants.iterator, implantType) match {
|
||||||
|
case Some(slot) =>
|
||||||
|
implants(slot).Implant = None
|
||||||
|
Some(slot)
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Locate the index of the encountered implant type.
|
||||||
|
* Functional implants may be exclusive in as far as the input `Iterator`'s source is concerned,
|
||||||
|
* but any number of `ImplantType.None` values are alway allowed in the source in any order.
|
||||||
|
* @param iter an `Iterator` of `ImplantSlot` objects
|
||||||
|
* @param implantType the target implant being sought
|
||||||
|
* @param index a defaulted index value representing the structure underlying the `Iterator` param
|
||||||
|
* @return the index where the target implant is installed
|
||||||
|
*/
|
||||||
|
@tailrec private def recursiveFindImplantInSlot(iter : Iterator[ImplantSlot], implantType : ImplantType.Value, index : Int = 0) : Option[Int] = {
|
||||||
|
if(!iter.hasNext) {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val slot = iter.next
|
||||||
|
if(slot.Unlocked && slot.Implant == implantType) {
|
||||||
|
Some(index)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recursiveFindImplantInSlot(iter, implantType, index + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def ResetAllImplants() : Unit = {
|
||||||
|
implants.foreach(slot => {
|
||||||
|
slot.Installed match {
|
||||||
|
case Some(_) =>
|
||||||
|
slot.Initialized = false
|
||||||
|
case None => ;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
def SaveLoadout(owner : Player, label : String, line : Int) : Unit = {
|
||||||
|
if(line > -1 && line < 10) {
|
||||||
|
loadouts(line) = Some(Loadout.Create(owner, label))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def LoadLoadout(line : Int) : Option[Loadout] = loadouts.lift(line).getOrElse(None)
|
||||||
|
|
||||||
|
def DeleteLoadout(line : Int) : Unit = {
|
||||||
|
loadouts(line) = None
|
||||||
|
}
|
||||||
|
|
||||||
|
def Locker : LockerContainer = locker
|
||||||
|
|
||||||
|
def FifthSlot : EquipmentSlot = {
|
||||||
|
new OffhandEquipmentSlot(EquipmentSize.Inventory) {
|
||||||
|
Equipment = locker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def Definition : AvatarDefinition = Avatar.definition
|
||||||
|
|
||||||
|
/*
|
||||||
|
Merit Commendations and Ribbons
|
||||||
|
*/
|
||||||
|
// private var tosRibbon : MeritCommendation.Value = MeritCommendation.None
|
||||||
|
// private var upperRibbon : MeritCommendation.Value = MeritCommendation.None
|
||||||
|
// private var middleRibbon : MeritCommendation.Value = MeritCommendation.None
|
||||||
|
// private var lowerRibbon : MeritCommendation.Value = MeritCommendation.None
|
||||||
|
|
||||||
|
def canEqual(other: Any): Boolean = other.isInstanceOf[Avatar]
|
||||||
|
|
||||||
|
override def equals(other : Any) : Boolean = other match {
|
||||||
|
case that: Avatar =>
|
||||||
|
(that canEqual this) &&
|
||||||
|
name == that.name &&
|
||||||
|
faction == that.faction &&
|
||||||
|
sex == that.sex &&
|
||||||
|
head == that.head &&
|
||||||
|
voice == that.voice
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
override def hashCode() : Int = {
|
||||||
|
val state = Seq(name, faction, sex, head, voice)
|
||||||
|
state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def toString: String = Avatar.toString(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Avatar {
|
||||||
|
final private val definition : AvatarDefinition = new AvatarDefinition(121)
|
||||||
|
|
||||||
|
def apply(name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, head : Int, voice : Int) : Avatar = {
|
||||||
|
new Avatar(name, faction, sex, head, voice)
|
||||||
|
}
|
||||||
|
|
||||||
|
def toString(avatar : Avatar) : String = s"${avatar.faction} ${avatar.name}"
|
||||||
|
}
|
||||||
|
|
@ -487,7 +487,7 @@ object GlobalDefinitions {
|
||||||
*/
|
*/
|
||||||
val order_terminal = new OrderTerminalDefinition
|
val order_terminal = new OrderTerminalDefinition
|
||||||
|
|
||||||
val ams_respawn_tube = new SpawnTubeDefinition(49) { Name = "ams_respawn_tube" }
|
val ams_respawn_tube = new SpawnTubeDefinition(49)
|
||||||
|
|
||||||
val matrix_terminalc = new MatrixTerminalDefinition(519)
|
val matrix_terminalc = new MatrixTerminalDefinition(519)
|
||||||
|
|
||||||
|
|
@ -509,6 +509,12 @@ object GlobalDefinitions {
|
||||||
|
|
||||||
val vehicle_terminal_combined = new VehicleTerminalCombinedDefinition
|
val vehicle_terminal_combined = new VehicleTerminalCombinedDefinition
|
||||||
|
|
||||||
|
val spawn_terminal = new MatrixTerminalDefinition(812)
|
||||||
|
|
||||||
|
val respawn_tube = new SpawnTubeDefinition(732)
|
||||||
|
|
||||||
|
val respawn_tube_tower = new SpawnTubeDefinition(733)
|
||||||
|
|
||||||
val spawn_pad = new VehicleSpawnPadDefinition
|
val spawn_pad = new VehicleSpawnPadDefinition
|
||||||
|
|
||||||
val mb_locker = new LockerDefinition
|
val mb_locker = new LockerDefinition
|
||||||
|
|
@ -643,7 +649,7 @@ object GlobalDefinitions {
|
||||||
* @param faction the faction
|
* @param faction the faction
|
||||||
* @return the `ToolDefinition` for the launcher
|
* @return the `ToolDefinition` for the launcher
|
||||||
*/
|
*/
|
||||||
def AntiVehicular(faction : PlanetSideEmpire.Value) : ToolDefinition = {
|
def AntiVehicularLauncher(faction : PlanetSideEmpire.Value) : ToolDefinition = {
|
||||||
faction match {
|
faction match {
|
||||||
case PlanetSideEmpire.TR => striker
|
case PlanetSideEmpire.TR => striker
|
||||||
case PlanetSideEmpire.NC => hunterseeker
|
case PlanetSideEmpire.NC => hunterseeker
|
||||||
|
|
@ -683,6 +689,17 @@ object GlobalDefinitions {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def isMaxArms(tdef : ToolDefinition) : Boolean = {
|
||||||
|
tdef match {
|
||||||
|
case `trhev_dualcycler` | `nchev_scattercannon` | `vshev_quasar`
|
||||||
|
| `trhev_pounder` | `nchev_falcon` | `vshev_comet`
|
||||||
|
| `trhev_burster` | `nchev_sparrow` | `vshev_starfire` =>
|
||||||
|
true
|
||||||
|
case _ =>
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def AIMAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
|
def AIMAX(faction : PlanetSideEmpire.Value) : ToolDefinition = {
|
||||||
faction match {
|
faction match {
|
||||||
case PlanetSideEmpire.TR => trhev_dualcycler
|
case PlanetSideEmpire.TR => trhev_dualcycler
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
|
||||||
import scala.collection.concurrent.{Map, TrieMap}
|
import scala.collection.concurrent.{Map, TrieMap}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -12,157 +9,42 @@ import scala.collection.concurrent.{Map, TrieMap}
|
||||||
*/
|
*/
|
||||||
private class LivePlayerList {
|
private class LivePlayerList {
|
||||||
/** key - the session id; value - a `Player` object */
|
/** key - the session id; value - a `Player` object */
|
||||||
private val sessionMap : Map[Long, Player] = new TrieMap[Long, Player]
|
private val sessionMap : Map[Long, Avatar] = new TrieMap[Long, Avatar]
|
||||||
/** the index of the List corresponds to zone number 1-32 with 0 being "Nowhere" */
|
|
||||||
/** each mapping: key - the global unique identifier; value - the session id */
|
|
||||||
private val zoneMap : List[Map[Int, Long]] = List.fill(33)(new TrieMap[Int,Long])
|
|
||||||
|
|
||||||
def WorldPopulation(predicate : ((_, Player)) => Boolean) : List[Player] = {
|
def WorldPopulation(predicate : ((_, Avatar)) => Boolean) : List[Avatar] = {
|
||||||
sessionMap.filter(predicate).values.toList
|
sessionMap.filter(predicate).values.toList
|
||||||
}
|
}
|
||||||
|
|
||||||
def ZonePopulation(zone : Int, predicate : ((_, Player)) => Boolean) : List[Player] = {
|
def Add(sessionId : Long, avatar : Avatar) : Boolean = {
|
||||||
zoneMap.lift(zone) match {
|
sessionMap.values.find(char => char.equals(avatar)) match {
|
||||||
case Some(map) =>
|
|
||||||
val list = map.values.toList
|
|
||||||
sessionMap.filter({ case ((sess, _)) => list.contains(sess) }).filter(predicate).values.toList
|
|
||||||
case None =>
|
case None =>
|
||||||
Nil
|
sessionMap.putIfAbsent(sessionId, avatar).isEmpty
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Add(sessionId : Long, player : Player) : Boolean = {
|
|
||||||
sessionMap.values.find(char => char.equals(player)) match {
|
|
||||||
case None =>
|
|
||||||
sessionMap.putIfAbsent(sessionId, player).isEmpty
|
|
||||||
case Some(_) =>
|
case Some(_) =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def Remove(sessionId : Long) : Option[Player] = {
|
def Remove(sessionId : Long) : Option[Avatar] = {
|
||||||
sessionMap.remove(sessionId) match {
|
sessionMap.remove(sessionId)
|
||||||
case Some(char) =>
|
|
||||||
zoneMap.foreach(zone => {
|
|
||||||
recursiveRemoveSession(zone.iterator, sessionId) match {
|
|
||||||
case Some(guid) =>
|
|
||||||
zone.remove(guid)
|
|
||||||
case None => ;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
Some(char)
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@tailrec private def recursiveRemoveSession(iter : Iterator[(Int, Long)], sessionId : Long) : Option[Int] = {
|
def Shutdown : List[Avatar] = {
|
||||||
if(!iter.hasNext) {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val (guid : Int, sess : Long) = iter.next
|
|
||||||
if(sess == sessionId) {
|
|
||||||
Some(guid)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
recursiveRemoveSession(iter, sessionId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Get(zone : Int, guid : PlanetSideGUID) : Option[Player] = {
|
|
||||||
Get(zone, guid.guid)
|
|
||||||
}
|
|
||||||
|
|
||||||
def Get(zone : Int, guid : Int) : Option[Player] = {
|
|
||||||
zoneMap.lift(zone) match {
|
|
||||||
case Some(map) =>
|
|
||||||
map.get(guid) match {
|
|
||||||
case Some(sessionId) =>
|
|
||||||
sessionMap.get(sessionId)
|
|
||||||
case _ =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Assign(zone: Int, sessionId : Long, guid : PlanetSideGUID) : Boolean = Assign(zone, sessionId, guid.guid)
|
|
||||||
|
|
||||||
def Assign(zone : Int, sessionId : Long, guid : Int) : Boolean = {
|
|
||||||
sessionMap.get(sessionId) match {
|
|
||||||
case Some(_) =>
|
|
||||||
zoneMap.lift(zone) match {
|
|
||||||
case Some(zn) =>
|
|
||||||
AssignToZone(zn, sessionId, guid)
|
|
||||||
case None =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
case None =>
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private def AssignToZone(zone : Map[Int, Long], sessionId : Long, guid : Int) : Boolean = {
|
|
||||||
zone.get(guid) match {
|
|
||||||
case Some(_) =>
|
|
||||||
false
|
|
||||||
case None =>
|
|
||||||
zone(guid) = sessionId
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Drop(zone : Int, guid : PlanetSideGUID) : Option[Player] = Drop(zone, guid.guid)
|
|
||||||
|
|
||||||
def Drop(zone : Int, guid : Int) : Option[Player] = {
|
|
||||||
zoneMap.lift(zone) match {
|
|
||||||
case Some(map) =>
|
|
||||||
map.remove(guid) match {
|
|
||||||
case Some(sessionId) =>
|
|
||||||
sessionMap.get(sessionId)
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def Shutdown : List[Player] = {
|
|
||||||
val list = sessionMap.values.toList
|
val list = sessionMap.values.toList
|
||||||
sessionMap.clear
|
sessionMap.clear
|
||||||
zoneMap.foreach(map => map.clear())
|
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class for storing `Player` mappings for users that are currently online.
|
* A class for storing `Player` mappings for users that are currently online.
|
||||||
* The mapping system is tightly coupled between the `Player` class and to an instance of `WorldSessionActor`.
|
* The mapping system is tightly coupled between the `Avatar` class and to an instance of `WorldSessionActor`.
|
||||||
* Looser couplings exist between the instance of `WorldSessionActor` and a given `Player`'s globally unique id.
|
|
||||||
* These looser couplings are zone-specific.
|
|
||||||
* Though the user may have local knowledge of the zone they inhabit on their `Player` object,
|
|
||||||
* it should not be trusted.<br>
|
|
||||||
* <br>
|
* <br>
|
||||||
* Use:<br>
|
* Use:<br>
|
||||||
* 1) When a users logs in during `WorldSessionActor`, associate that user's session id and the character.<br>
|
* 1) When a users logs in during `WorldSessionActor`, associate that user's session id and their character (avatar).<br>
|
||||||
* `LivePlayerList.Add(session, player)`<br>
|
* `LivePlayerList.Add(session, avatar)`<br>
|
||||||
* 2) When that user's chosen character is declared his avatar using `SetCurrentAvatarMessage`,
|
* 2) In between the previous two steps, a range of characters may be queried based on provided statistics.<br>
|
||||||
* also associate the user's session with their current GUID.<br>
|
|
||||||
* `LivePlayerList.Assign(zone, session, guid)`<br>
|
|
||||||
* 3) Repeat the previous step for as many times the user's GUID changes, especially during the aforementioned condition.<br>
|
|
||||||
* 4a) In between the previous two steps, a user's character may be referenced by their current GUID.<br>
|
|
||||||
* `LivePlayerList.Get(zone, guid)`<br>
|
|
||||||
* 4b) Also in between those same previous steps, a range of characters may be queried based on provided statistics.<br>
|
|
||||||
* `LivePlayerList.WorldPopulation(...)`<br>
|
* `LivePlayerList.WorldPopulation(...)`<br>
|
||||||
* `LivePlayerList.ZonePopulation(zone, ...)`<br>
|
* 3) When the user leaves the game entirely, his character's entry is removed from the mapping.<br>
|
||||||
* 5) When the user navigates away from a region completely, their entry is forgotten.<br>
|
|
||||||
* `LivePlayerList.Drop(zone, guid)`<br>
|
|
||||||
* 6) When the user leaves the game entirely, his character's entries are removed from the mappings.<br>
|
|
||||||
* `LivePlayerList.Remove(session)`
|
* `LivePlayerList.Remove(session)`
|
||||||
*/
|
*/
|
||||||
object LivePlayerList {
|
object LivePlayerList {
|
||||||
|
|
@ -179,100 +61,28 @@ object LivePlayerList {
|
||||||
* @param predicate the conditions for filtering the live `Player`s
|
* @param predicate the conditions for filtering the live `Player`s
|
||||||
* @return a list of users's `Player`s that fit the criteria
|
* @return a list of users's `Player`s that fit the criteria
|
||||||
*/
|
*/
|
||||||
def WorldPopulation(predicate : ((_, Player)) => Boolean) : List[Player] = Instance.WorldPopulation(predicate)
|
def WorldPopulation(predicate : ((_, Avatar)) => Boolean) : List[Avatar] = Instance.WorldPopulation(predicate)
|
||||||
|
|
||||||
/**
|
|
||||||
* Given some criteria, examine the mapping of user characters for a zone and find the ones that fulfill the requirements.<br>
|
|
||||||
* <br>
|
|
||||||
* Note the signature carefully.
|
|
||||||
* A two-element tuple is checked, but only the second element of that tuple - a `Player` - is eligible for being queried.
|
|
||||||
* The first element is ignored.
|
|
||||||
* Even a predicate as simple as `{ case ((x : Long, _)) => x > 0 }` will not work for that reason.
|
|
||||||
* @param zone the number of the zone
|
|
||||||
* @param predicate the conditions for filtering the live `Player`s
|
|
||||||
* @return a list of users's `Player`s that fit the criteria
|
|
||||||
*/
|
|
||||||
def ZonePopulation(zone : Int, predicate : ((_, Player)) => Boolean) : List[Player] = Instance.ZonePopulation(zone, predicate)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mapped entry between the user's session and a user's character.
|
* Create a mapped entry between the user's session and a user's character.
|
||||||
* Neither the player nor the session may exist in the current mappings if this is to work.
|
* Neither the player nor the session may exist in the current mappings if this is to work.
|
||||||
* @param sessionId the session
|
* @param sessionId the session
|
||||||
* @param player the character
|
* @param avatar the character
|
||||||
* @return `true`, if the session was association was made; `false`, otherwise
|
* @return `true`, if the session was association was made; `false`, otherwise
|
||||||
*/
|
*/
|
||||||
def Add(sessionId : Long, player : Player) : Boolean = Instance.Add(sessionId, player)
|
def Add(sessionId : Long, avatar : Avatar) : Boolean = Instance.Add(sessionId, avatar)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove all entries related to the given session identifier from the mappings.
|
* Remove all entries related to the given session identifier from the mappings.
|
||||||
* The player no longer counts as "online."
|
* The character no longer counts as "online."
|
||||||
* This function cleans up __all__ associations - those created by `Add`, and those created by `Assign`.
|
|
||||||
* @param sessionId the session
|
* @param sessionId the session
|
||||||
* @return any character that was afffected by the mapping removal
|
* @return any character that was afffected by the mapping removal
|
||||||
*/
|
*/
|
||||||
def Remove(sessionId : Long) : Option[Player] = Instance.Remove(sessionId)
|
def Remove(sessionId : Long) : Option[Avatar] = Instance.Remove(sessionId)
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a user's character from the mappings.
|
|
||||||
* @param zone the number of the zone
|
|
||||||
* @param guid the current GUID of the character
|
|
||||||
* @return the character, if it can be found using the GUID
|
|
||||||
*/
|
|
||||||
def Get(zone : Int, guid : PlanetSideGUID) : Option[Player] = Instance.Get(zone, guid)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a user's character from the mappings.
|
|
||||||
* @param zone the number of the zone
|
|
||||||
* @param guid the current GUID of the character
|
|
||||||
* @return the character, if it can be found using the GUID
|
|
||||||
*/
|
|
||||||
def Get(zone : Int, guid : Int) : Option[Player] = Instance.Get(zone, guid)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a session that maps to a user's character, create a mapping between the character's current GUID and the session.
|
|
||||||
* If the user already has a GUID in the mappings, remove it and assert the new one.
|
|
||||||
* @param zone the number of the zone
|
|
||||||
* @param sessionId the session
|
|
||||||
* @param guid the GUID to associate with the character;
|
|
||||||
* technically, it has already been assigned and should be findable using `{character}.GUID.guid`
|
|
||||||
* @return `true`, if the mapping was created;
|
|
||||||
* `false`, if the session can not be found or if the character's GUID doesn't match the one provided
|
|
||||||
*/
|
|
||||||
def Assign(zone : Int, sessionId : Long, guid : PlanetSideGUID) : Boolean = Instance.Assign(zone, sessionId, guid)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a session that maps to a user's character, create a mapping between the character's current GUID and the session.
|
|
||||||
* If the user already has a GUID in the mappings, remove it and assert the new one.
|
|
||||||
* @param zone the number of the zone
|
|
||||||
* @param sessionId the session
|
|
||||||
* @param guid the GUID to associate with the character;
|
|
||||||
* technically, it has already been assigned and should be findable using `{character}.GUID.guid`
|
|
||||||
* @return `true`, if the mapping was created;
|
|
||||||
* `false`, if the session can not be found or if the character's GUID doesn't match the one provided
|
|
||||||
*/
|
|
||||||
def Assign(zone : Int, sessionId : Long, guid : Int) : Boolean = Instance.Assign(zone, sessionId, guid)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a GUID, remove any record of it.
|
|
||||||
* @param zone the number of the zone
|
|
||||||
* @param guid a GUID associated with the character;
|
|
||||||
* it does not have to be findable using `{character}.GUID.guid`
|
|
||||||
* @return any `Player` that may have been associated with this GUID
|
|
||||||
*/
|
|
||||||
def Drop(zone : Int, guid : PlanetSideGUID) : Option[Player] = Instance.Drop(zone, guid)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a GUID, remove any record of it.
|
|
||||||
* @param zone the number of the zone
|
|
||||||
* @param guid a GUID associated with the character;
|
|
||||||
* it does not have to be findable using `{character}.GUID.guid`
|
|
||||||
* @return any `Player` that may have been associated with this GUID
|
|
||||||
*/
|
|
||||||
def Drop(zone : Int, guid : Int) : Option[Player] = Instance.Drop(zone, guid)
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hastily remove all mappings and ids.
|
* Hastily remove all mappings and ids.
|
||||||
* @return an unsorted list of the characters that were still online
|
* @return an unsorted list of the characters that were still online
|
||||||
*/
|
*/
|
||||||
def Shutdown : List[Player] = Instance.Shutdown
|
def Shutdown : List[Avatar] = Instance.Shutdown
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,14 +8,6 @@ import net.psforever.types.ExoSuitType
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
||||||
//trait Loadout {
|
|
||||||
// def Label : String
|
|
||||||
// def VisibleSlots : List[Loadout.SimplifiedEntry]
|
|
||||||
// def Inventory : List[Loadout.SimplifiedEntry]
|
|
||||||
// def ExoSuit : ExoSuitType.Value
|
|
||||||
// def Subtype : Int
|
|
||||||
//}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* From a `Player` their current exo-suit and their `Equipment`, retain a set of instructions to reconstruct this arrangement.<br>
|
* From a `Player` their current exo-suit and their `Equipment`, retain a set of instructions to reconstruct this arrangement.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
@ -113,7 +105,9 @@ object Loadout {
|
||||||
/**
|
/**
|
||||||
* A basic `Trait` connecting all of the `Equipment` blueprints.
|
* A basic `Trait` connecting all of the `Equipment` blueprints.
|
||||||
*/
|
*/
|
||||||
sealed trait Simplification
|
sealed trait Simplification {
|
||||||
|
def definition : ObjectDefinition
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An entry in the `Loadout`, wrapping around a slot index and what is in the slot index.
|
* An entry in the `Loadout`, wrapping around a slot index and what is in the slot index.
|
||||||
|
|
@ -125,17 +119,17 @@ object Loadout {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The simplified form of an `AmmoBox`.
|
* The simplified form of an `AmmoBox`.
|
||||||
* @param adef the `AmmoBoxDefinition` that describes this future object
|
* @param definition the `AmmoBoxDefinition` that describes this future object
|
||||||
* @param capacity the amount of ammunition, if any, to initialize;
|
* @param capacity the amount of ammunition, if any, to initialize;
|
||||||
* if `None`, then the previous `AmmoBoxDefinition` will be referenced for the amount later
|
* if `None`, then the previous `AmmoBoxDefinition` will be referenced for the amount later
|
||||||
*/
|
*/
|
||||||
final case class ShorthandAmmoBox(adef : AmmoBoxDefinition, capacity : Int) extends Simplification
|
final case class ShorthandAmmoBox(definition : AmmoBoxDefinition, capacity : Int) extends Simplification
|
||||||
/**
|
/**
|
||||||
* The simplified form of a `Tool`.
|
* The simplified form of a `Tool`.
|
||||||
* @param tdef the `ToolDefinition` that describes this future object
|
* @param definition the `ToolDefinition` that describes this future object
|
||||||
* @param ammo the blueprints to construct the correct number of ammunition slots in the `Tool`
|
* @param ammo the blueprints to construct the correct number of ammunition slots in the `Tool`
|
||||||
*/
|
*/
|
||||||
final case class ShorthandTool(tdef : ToolDefinition, ammo : List[ShorthandAmmoSlot]) extends Simplification
|
final case class ShorthandTool(definition : ToolDefinition, ammo : List[ShorthandAmmoSlot]) extends Simplification
|
||||||
/**
|
/**
|
||||||
* The simplified form of a `Tool` `FireMode`
|
* The simplified form of a `Tool` `FireMode`
|
||||||
* @param ammoIndex the index that points to the type of ammunition this slot currently uses
|
* @param ammoIndex the index that points to the type of ammunition this slot currently uses
|
||||||
|
|
@ -144,19 +138,19 @@ object Loadout {
|
||||||
final case class ShorthandAmmoSlot(ammoIndex : Int, ammo : ShorthandAmmoBox)
|
final case class ShorthandAmmoSlot(ammoIndex : Int, ammo : ShorthandAmmoBox)
|
||||||
/**
|
/**
|
||||||
* The simplified form of a `ConstructionItem`.
|
* The simplified form of a `ConstructionItem`.
|
||||||
* @param cdef the `ConstructionItemDefinition` that describes this future object
|
* @param definition the `ConstructionItemDefinition` that describes this future object
|
||||||
*/
|
*/
|
||||||
final case class ShorthandConstructionItem(cdef : ConstructionItemDefinition) extends Simplification
|
final case class ShorthandConstructionItem(definition : ConstructionItemDefinition) extends Simplification
|
||||||
/**
|
/**
|
||||||
* The simplified form of a `SimpleItem`.
|
* The simplified form of a `SimpleItem`.
|
||||||
* @param sdef the `SimpleItemDefinition` that describes this future object
|
* @param definition the `SimpleItemDefinition` that describes this future object
|
||||||
*/
|
*/
|
||||||
final case class ShorthandSimpleItem(sdef : SimpleItemDefinition) extends Simplification
|
final case class ShorthandSimpleItem(definition : SimpleItemDefinition) extends Simplification
|
||||||
/**
|
/**
|
||||||
* The simplified form of a `Kit`.
|
* The simplified form of a `Kit`.
|
||||||
* @param kdef the `KitDefinition` that describes this future object
|
* @param definition the `KitDefinition` that describes this future object
|
||||||
*/
|
*/
|
||||||
final case class ShorthandKit(kdef : KitDefinition) extends Simplification
|
final case class ShorthandKit(definition : KitDefinition) extends Simplification
|
||||||
|
|
||||||
def DetermineSubtype(player : Player) : Int = {
|
def DetermineSubtype(player : Player) : Int = {
|
||||||
if(player.ExoSuit == ExoSuitType.MAX) {
|
if(player.ExoSuit == ExoSuitType.MAX) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects
|
package net.psforever.objects
|
||||||
|
|
||||||
import net.psforever.objects.definition.{AvatarDefinition, ImplantDefinition}
|
import net.psforever.objects.definition.AvatarDefinition
|
||||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
||||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
|
|
@ -9,15 +9,9 @@ import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import scala.collection.mutable
|
|
||||||
import scala.util.{Success, Try}
|
import scala.util.{Success, Try}
|
||||||
|
|
||||||
class Player(private val name : String,
|
class Player(private val core : Avatar) extends PlanetSideGameObject with FactionAffinity with Container {
|
||||||
private val faction : PlanetSideEmpire.Value,
|
|
||||||
private val sex : CharacterGender.Value,
|
|
||||||
private val head : Int,
|
|
||||||
private val voice : Int
|
|
||||||
) extends PlanetSideGameObject with FactionAffinity with Container {
|
|
||||||
private var alive : Boolean = false
|
private var alive : Boolean = false
|
||||||
private var backpack : Boolean = false
|
private var backpack : Boolean = false
|
||||||
private var health : Int = 0
|
private var health : Int = 0
|
||||||
|
|
@ -29,46 +23,20 @@ class Player(private val name : String,
|
||||||
private var exosuit : ExoSuitType.Value = ExoSuitType.Standard
|
private var exosuit : ExoSuitType.Value = ExoSuitType.Standard
|
||||||
private val freeHand : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory)
|
private val freeHand : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory)
|
||||||
private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot)
|
private val holsters : Array[EquipmentSlot] = Array.fill[EquipmentSlot](5)(new EquipmentSlot)
|
||||||
private val fifthSlot : EquipmentSlot = new OffhandEquipmentSlot(EquipmentSize.Inventory)
|
|
||||||
private val inventory : GridInventory = GridInventory()
|
private val inventory : GridInventory = GridInventory()
|
||||||
private var drawnSlot : Int = Player.HandsDownSlot
|
private var drawnSlot : Int = Player.HandsDownSlot
|
||||||
private var lastDrawnSlot : Int = Player.HandsDownSlot
|
private var lastDrawnSlot : Int = Player.HandsDownSlot
|
||||||
|
|
||||||
private val loadouts : Array[Option[Loadout]] = Array.fill[Option[Loadout]](10)(None)
|
|
||||||
|
|
||||||
private var bep : Long = 0
|
|
||||||
private var cep : Long = 0
|
|
||||||
private val certifications : mutable.Set[CertificationType.Value] = mutable.Set[CertificationType.Value]()
|
|
||||||
/**
|
|
||||||
* Unlike other objects, the maximum number of `ImplantSlots` are built into the `Player`.
|
|
||||||
* Additionally, "implants" do not have tightly-coupled "`Definition` objects" that explain a formal implant object.
|
|
||||||
* The `ImplantDefinition` objects themselves are moved around as if they were the implants.
|
|
||||||
* The term internally used for this process is "installed" and "uninstalled."
|
|
||||||
* @see `ImplantSlot`
|
|
||||||
* @see `DetailedCharacterData.implants`
|
|
||||||
* @see `AvatarConverter.MakeImplantEntries`
|
|
||||||
*/
|
|
||||||
private val implants : Array[ImplantSlot] = Array.fill[ImplantSlot](3)(new ImplantSlot)
|
|
||||||
|
|
||||||
// private var tosRibbon : MeritCommendation.Value = MeritCommendation.None
|
|
||||||
// private var upperRibbon : MeritCommendation.Value = MeritCommendation.None
|
|
||||||
// private var middleRibbon : MeritCommendation.Value = MeritCommendation.None
|
|
||||||
// private var lowerRibbon : MeritCommendation.Value = MeritCommendation.None
|
|
||||||
|
|
||||||
private var facingYawUpper : Float = 0f
|
private var facingYawUpper : Float = 0f
|
||||||
private var crouching : Boolean = false
|
private var crouching : Boolean = false
|
||||||
private var jumping : Boolean = false
|
private var jumping : Boolean = false
|
||||||
private var cloaked : Boolean = false
|
private var cloaked : Boolean = false
|
||||||
private var backpackAccess : Option[PlanetSideGUID] = None
|
private var backpackAccess : Option[PlanetSideGUID] = None
|
||||||
|
|
||||||
private var admin : Boolean = false
|
|
||||||
private var spectator : Boolean = false
|
|
||||||
|
|
||||||
private var vehicleSeated : Option[PlanetSideGUID] = None
|
private var vehicleSeated : Option[PlanetSideGUID] = None
|
||||||
private var vehicleOwned : Option[PlanetSideGUID] = None
|
private var vehicleOwned : Option[PlanetSideGUID] = None
|
||||||
|
|
||||||
private var continent : String = "home2" //the zone id
|
private var continent : String = "home2" //the zone id
|
||||||
private val playerDef : AvatarDefinition = Player.definition //TODO could be a var
|
|
||||||
|
|
||||||
//SouNourS things
|
//SouNourS things
|
||||||
/** Last medkituse. */
|
/** Last medkituse. */
|
||||||
|
|
@ -76,23 +44,20 @@ class Player(private val name : String,
|
||||||
var death_by : Int = 0
|
var death_by : Int = 0
|
||||||
var lastSeenStreamMessage : Array[Long] = Array.fill[Long](65535)(0L)
|
var lastSeenStreamMessage : Array[Long] = Array.fill[Long](65535)(0L)
|
||||||
var lastShotSeq_time : Int = -1
|
var lastShotSeq_time : Int = -1
|
||||||
/** The player is shooting. */
|
|
||||||
var shooting : Boolean = false
|
|
||||||
/** From PlanetsideAttributeMessage */
|
/** From PlanetsideAttributeMessage */
|
||||||
var PlanetsideAttribute : Array[Long] = Array.ofDim(120)
|
var PlanetsideAttribute : Array[Long] = Array.ofDim(120)
|
||||||
|
|
||||||
Player.SuitSetup(this, ExoSuit)
|
Player.SuitSetup(this, ExoSuit)
|
||||||
fifthSlot.Equipment = new LockerContainer //the fifth slot is the player's "locker"
|
|
||||||
|
|
||||||
def Name : String = name
|
def Name : String = core.name
|
||||||
|
|
||||||
def Faction : PlanetSideEmpire.Value = faction
|
def Faction : PlanetSideEmpire.Value = core.faction
|
||||||
|
|
||||||
def Sex : CharacterGender.Value = sex
|
def Sex : CharacterGender.Value = core.sex
|
||||||
|
|
||||||
def Voice : Int = voice
|
def Head : Int = core.head
|
||||||
|
|
||||||
def Head : Int = head
|
def Voice : Int = core.voice
|
||||||
|
|
||||||
def isAlive : Boolean = alive
|
def isAlive : Boolean = alive
|
||||||
|
|
||||||
|
|
@ -173,9 +138,7 @@ class Player(private val name : String,
|
||||||
holsters(slot)
|
holsters(slot)
|
||||||
}
|
}
|
||||||
else if(slot == 5) {
|
else if(slot == 5) {
|
||||||
new OffhandEquipmentSlot(EquipmentSize.Inventory) {
|
core.FifthSlot
|
||||||
Equipment = fifthSlot.Equipment
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(slot == Player.FreeHandSlot) {
|
else if(slot == Player.FreeHandSlot) {
|
||||||
freeHand
|
freeHand
|
||||||
|
|
@ -189,7 +152,7 @@ class Player(private val name : String,
|
||||||
|
|
||||||
def Inventory : GridInventory = inventory
|
def Inventory : GridInventory = inventory
|
||||||
|
|
||||||
def Locker : LockerContainer = fifthSlot.Equipment.get.asInstanceOf[LockerContainer]
|
def Locker : LockerContainer = core.Locker
|
||||||
|
|
||||||
def Fit(obj : Equipment) : Option[Int] = {
|
def Fit(obj : Equipment) : Option[Int] = {
|
||||||
recursiveHolsterFit(holsters.iterator, obj.Size) match {
|
recursiveHolsterFit(holsters.iterator, obj.Size) match {
|
||||||
|
|
@ -220,20 +183,6 @@ class Player(private val name : String,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def Equip(slot : Int, obj : Equipment) : Boolean = {
|
|
||||||
if(-1 < slot && slot < 5) {
|
|
||||||
holsters(slot).Equipment = obj
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else if(slot == Player.FreeHandSlot) {
|
|
||||||
freeHand.Equipment = obj
|
|
||||||
true
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
inventory += slot -> obj
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def FreeHand = freeHand
|
def FreeHand = freeHand
|
||||||
|
|
||||||
def FreeHand_=(item : Option[Equipment]) : Option[Equipment] = {
|
def FreeHand_=(item : Option[Equipment]) : Option[Equipment] = {
|
||||||
|
|
@ -243,33 +192,22 @@ class Player(private val name : String,
|
||||||
FreeHand.Equipment
|
FreeHand.Equipment
|
||||||
}
|
}
|
||||||
|
|
||||||
def SaveLoadout(label : String, line : Int) : Unit = {
|
|
||||||
loadouts(line) = Some(Loadout.Create(this, label))
|
|
||||||
}
|
|
||||||
|
|
||||||
def LoadLoadout(line : Int) : Option[Loadout] = loadouts(line)
|
|
||||||
|
|
||||||
def DeleteLoadout(line : Int) : Unit = {
|
|
||||||
loadouts(line) = None
|
|
||||||
}
|
|
||||||
|
|
||||||
def Find(obj : Equipment) : Option[Int] = Find(obj.GUID)
|
def Find(obj : Equipment) : Option[Int] = Find(obj.GUID)
|
||||||
|
|
||||||
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
def Find(guid : PlanetSideGUID) : Option[Int] = {
|
||||||
findInHolsters(holsters.iterator, guid) match {
|
findInHolsters(holsters.iterator, guid)
|
||||||
|
.orElse(findInInventory(inventory.Items.values.iterator, guid)) match {
|
||||||
case Some(index) =>
|
case Some(index) =>
|
||||||
Some(index)
|
Some(index)
|
||||||
case None =>
|
case None =>
|
||||||
findInInventory(inventory.Items.values.iterator, guid) match {
|
if(Locker.Find(guid).isDefined) {
|
||||||
case Some(index) =>
|
Some(5)
|
||||||
Some(index)
|
}
|
||||||
case None =>
|
else if(freeHand.Equipment.isDefined && freeHand.Equipment.get.GUID == guid) {
|
||||||
if(freeHand.Equipment.isDefined && freeHand.Equipment.get.GUID == guid) {
|
Some(Player.FreeHandSlot)
|
||||||
Some(Player.FreeHandSlot)
|
}
|
||||||
}
|
else {
|
||||||
else {
|
None
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -349,27 +287,13 @@ class Player(private val name : String,
|
||||||
exosuit = suit
|
exosuit = suit
|
||||||
}
|
}
|
||||||
|
|
||||||
def BEP : Long = bep
|
def LoadLoadout(line : Int) : Option[Loadout] = core.LoadLoadout(line)
|
||||||
|
|
||||||
def BEP_=(battleExperiencePoints : Long) : Long = {
|
def BEP : Long = core.BEP
|
||||||
bep = math.max(0L, math.min(battleExperiencePoints, 4294967295L))
|
|
||||||
BEP
|
|
||||||
}
|
|
||||||
|
|
||||||
def CEP : Long = cep
|
def CEP : Long = core.CEP
|
||||||
|
|
||||||
def CEP_=(commandExperiencePoints : Long) : Long = {
|
def Certifications : Set[CertificationType.Value] = core.Certifications.toSet
|
||||||
cep = math.max(0L, math.min(commandExperiencePoints, 4294967295L))
|
|
||||||
CEP
|
|
||||||
}
|
|
||||||
|
|
||||||
def Certifications : mutable.Set[CertificationType.Value] = certifications
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the three implant slots for this player.
|
|
||||||
* @return an `Array` of `ImplantSlot` objects
|
|
||||||
*/
|
|
||||||
def Implants : Array[ImplantSlot] = implants
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* What kind of implant is installed into the given slot number?
|
* What kind of implant is installed into the given slot number?
|
||||||
|
|
@ -377,91 +301,17 @@ class Player(private val name : String,
|
||||||
* @param slot the slot number
|
* @param slot the slot number
|
||||||
* @return the tye of implant
|
* @return the tye of implant
|
||||||
*/
|
*/
|
||||||
def Implant(slot : Int) : ImplantType.Value = {
|
def Implant(slot : Int) : ImplantType.Value = core.Implant(slot)
|
||||||
if(-1 < slot && slot < implants.length) { implants(slot).Implant } else { ImplantType.None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a new implant, assign it into a vacant implant slot on this player.<br>
|
* A read-only `Array` of tuples representing important information about all unlocked implant slots.
|
||||||
* <br>
|
* @return a maximum of three implant types, initialization times, and active flags
|
||||||
* The implant must be unique in terms of which implants have already been assigned to this player.
|
|
||||||
* Multiple of a type of implant being assigned at once is not supported.
|
|
||||||
* Additionally, the implant is inserted into the earliest yet-unknown but vacant slot.
|
|
||||||
* Implant slots are vacant by just being unlocked or by having their previous implant uninstalled.
|
|
||||||
* @param implant the implant being installed
|
|
||||||
* @return the index of the `ImplantSlot` where the implant was installed
|
|
||||||
*/
|
*/
|
||||||
def InstallImplant(implant : ImplantDefinition) : Option[Int] = {
|
def Implants : Array[(ImplantType.Value, Long, Boolean)] = {
|
||||||
implants.find({p => p.Installed.contains(implant)}) match { //try to find the installed implant
|
core.Implants.takeWhile(_.Unlocked).map( implant => { (implant.Implant, implant.MaxTimer, implant.Active) })
|
||||||
case None =>
|
|
||||||
recursiveFindImplantInSlot(implants.iterator, ImplantType.None) match { //install in a free slot
|
|
||||||
case Some(slot) =>
|
|
||||||
implants(slot).Implant = implant
|
|
||||||
Some(slot)
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
case Some(_) =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
def ResetAllImplants() : Unit = core.ResetAllImplants()
|
||||||
* Remove a specific implant from a player's allocated installed implants.<br>
|
|
||||||
* <br>
|
|
||||||
* Due to the exclusiveness of installed implants,
|
|
||||||
* any implant slot with a matching `Definition` can be uninstalled safely.
|
|
||||||
* (There will never be any doubles.)
|
|
||||||
* This operation can lead to an irregular pattern of installed and uninstalled `ImplantSlot` objects.
|
|
||||||
* Despite that breach of pattern, the logic here is consistent as demonstrated by the client and by packets.
|
|
||||||
* The client also assigns and removes implants based on slot numbers that only express availability of a "slot."
|
|
||||||
* @see `AvatarImplantMessage.implantSlot`
|
|
||||||
* @param implantType the type of implant being uninstalled
|
|
||||||
* @return the index of the `ImplantSlot` where the implant was found and uninstalled
|
|
||||||
*/
|
|
||||||
def UninstallImplant(implantType : ImplantType.Value) : Option[Int] = {
|
|
||||||
recursiveFindImplantInSlot(implants.iterator, implantType) match {
|
|
||||||
case Some(slot) =>
|
|
||||||
implants(slot).Implant = None
|
|
||||||
Some(slot)
|
|
||||||
case None =>
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locate the index of the encountered implant type.
|
|
||||||
* Functional implants may be exclusive in as far as the input `Iterator`'s source is concerned,
|
|
||||||
* but any number of `ImplantType.None` values are alway allowed in the source in any order.
|
|
||||||
* @param iter an `Iterator` of `ImplantSlot` objects
|
|
||||||
* @param implantType the target implant being sought
|
|
||||||
* @param index a defaulted index value representing the structure underlying the `Iterator` param
|
|
||||||
* @return the index where the target implant is installed
|
|
||||||
*/
|
|
||||||
@tailrec private def recursiveFindImplantInSlot(iter : Iterator[ImplantSlot], implantType : ImplantType.Value, index : Int = 0) : Option[Int] = {
|
|
||||||
if(!iter.hasNext) {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
val slot = iter.next
|
|
||||||
if(slot.Unlocked && slot.Implant == implantType) {
|
|
||||||
Some(index)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
recursiveFindImplantInSlot(iter, implantType, index + 1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def ResetAllImplants() : Unit = {
|
|
||||||
implants.foreach(slot => {
|
|
||||||
slot.Installed match {
|
|
||||||
case Some(_) =>
|
|
||||||
slot.Initialized = false
|
|
||||||
case None => ;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
def FacingYawUpper : Float = facingYawUpper
|
def FacingYawUpper : Float = facingYawUpper
|
||||||
|
|
||||||
|
|
@ -524,10 +374,6 @@ class Player(private val name : String,
|
||||||
isBackpack && (backpackAccess.isEmpty || backpackAccess.contains(player.GUID))
|
isBackpack && (backpackAccess.isEmpty || backpackAccess.contains(player.GUID))
|
||||||
}
|
}
|
||||||
|
|
||||||
def Admin : Boolean = admin
|
|
||||||
|
|
||||||
def Spectator : Boolean = spectator
|
|
||||||
|
|
||||||
def VehicleSeated : Option[PlanetSideGUID] = vehicleSeated
|
def VehicleSeated : Option[PlanetSideGUID] = vehicleSeated
|
||||||
|
|
||||||
def VehicleSeated_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = VehicleSeated_=(Some(guid))
|
def VehicleSeated_=(guid : PlanetSideGUID) : Option[PlanetSideGUID] = VehicleSeated_=(Some(guid))
|
||||||
|
|
@ -553,52 +399,34 @@ class Player(private val name : String,
|
||||||
Continent
|
Continent
|
||||||
}
|
}
|
||||||
|
|
||||||
def Definition : AvatarDefinition = playerDef
|
def Definition : AvatarDefinition = core.Definition
|
||||||
|
|
||||||
override def toString : String = {
|
|
||||||
Player.toString(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
def canEqual(other: Any): Boolean = other.isInstanceOf[Player]
|
def canEqual(other: Any): Boolean = other.isInstanceOf[Player]
|
||||||
|
|
||||||
override def equals(other : Any) : Boolean = other match {
|
override def equals(other : Any) : Boolean = other match {
|
||||||
case that: Player =>
|
case that: Player =>
|
||||||
(that canEqual this) &&
|
(that canEqual this) &&
|
||||||
name == that.name &&
|
core == that.core
|
||||||
faction == that.faction &&
|
|
||||||
sex == that.sex &&
|
|
||||||
voice == that.voice &&
|
|
||||||
head == that.head
|
|
||||||
case _ =>
|
case _ =>
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
override def hashCode() : Int = {
|
override def hashCode() : Int = {
|
||||||
val state = Seq(name, faction, sex, voice, head)
|
core.hashCode()
|
||||||
state.map(_.hashCode()).foldLeft(0)((a, b) => 31 * a + b)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override def toString : String = Player.toString(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Player {
|
object Player {
|
||||||
final private val definition : AvatarDefinition = new AvatarDefinition(121)
|
final val LockerSlot : Int = 5
|
||||||
final val FreeHandSlot : Int = 250
|
final val FreeHandSlot : Int = 250
|
||||||
final val HandsDownSlot : Int = 255
|
final val HandsDownSlot : Int = 255
|
||||||
|
|
||||||
def apply(name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, head : Int, voice : Int) : Player = {
|
def apply(core : Avatar) : Player = {
|
||||||
new Player(name, faction, sex, head, voice)
|
new Player(core)
|
||||||
}
|
}
|
||||||
|
|
||||||
// /**
|
|
||||||
// * Change the type of `AvatarDefinition` is used to define the player.
|
|
||||||
// * @param player the player
|
|
||||||
// * @param avatarDef the player's new definition entry
|
|
||||||
// * @return the changed player
|
|
||||||
// */
|
|
||||||
// def apply(player : Player, avatarDef : AvatarDefinition) : Player = {
|
|
||||||
// player.playerDef = avatarDef
|
|
||||||
// player
|
|
||||||
// }
|
|
||||||
|
|
||||||
def SuitSetup(player : Player, eSuit : ExoSuitType.Value) : Unit = {
|
def SuitSetup(player : Player, eSuit : ExoSuitType.Value) : Unit = {
|
||||||
val esuitDef : ExoSuitDefinition = ExoSuitDefinition.Select(eSuit)
|
val esuitDef : ExoSuitDefinition = ExoSuitDefinition.Select(eSuit)
|
||||||
//exosuit
|
//exosuit
|
||||||
|
|
@ -611,37 +439,11 @@ object Player {
|
||||||
(0 until 5).foreach(index => { player.Slot(index).Size = esuitDef.Holster(index) })
|
(0 until 5).foreach(index => { player.Slot(index).Size = esuitDef.Holster(index) })
|
||||||
}
|
}
|
||||||
|
|
||||||
def Administrate(player : Player, isAdmin : Boolean) : Player = {
|
def Respawn(player : Player) : Player = {
|
||||||
player.admin = isAdmin
|
|
||||||
player
|
|
||||||
}
|
|
||||||
|
|
||||||
def Spectate(player : Player, isSpectator : Boolean) : Player = {
|
|
||||||
player.spectator = isSpectator
|
|
||||||
player
|
|
||||||
}
|
|
||||||
|
|
||||||
def Release(player : Player) : Player = {
|
|
||||||
if(player.Release) {
|
if(player.Release) {
|
||||||
val obj = new Player(player.Name, player.Faction, player.Sex, player.Voice, player.Head)
|
val obj = new Player(player.core)
|
||||||
obj.VehicleOwned = player.VehicleOwned
|
obj.VehicleOwned = player.VehicleOwned
|
||||||
obj.Continent = player.Continent
|
obj.Continent = player.Continent
|
||||||
//hand over loadouts
|
|
||||||
(0 until 10).foreach(index => {
|
|
||||||
obj.loadouts(index) = player.loadouts(index)
|
|
||||||
})
|
|
||||||
//hand over implants
|
|
||||||
(0 until 3).foreach(index => {
|
|
||||||
if(obj.Implants(index).Unlocked = player.Implants(index).Unlocked) {
|
|
||||||
obj.Implants(index).Implant = player.Implants(index).Installed
|
|
||||||
}
|
|
||||||
})
|
|
||||||
//hand over knife
|
|
||||||
obj.Slot(4).Equipment = player.Slot(4).Equipment
|
|
||||||
player.Slot(4).Equipment = None
|
|
||||||
//hand over ???
|
|
||||||
obj.fifthSlot.Equipment = player.fifthSlot.Equipment
|
|
||||||
player.fifthSlot.Equipment = None
|
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -650,7 +452,7 @@ object Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
def toString(obj : Player) : String = {
|
def toString(obj : Player) : String = {
|
||||||
val name : String = if(obj.VehicleSeated.isDefined) { s"[${obj.name}, ${obj.VehicleSeated.get.guid}]" } else { obj.Name }
|
val guid = if(obj.HasGUID) { s" ${obj.Continent}-${obj.GUID.guid}" } else { "" }
|
||||||
s"[player $name, ${obj.Faction} (${obj.Health}/${obj.MaxHealth})(${obj.Armor}/${obj.MaxArmor})]"
|
s"${obj.core}$guid ${obj.Health}/${obj.MaxHealth} ${obj.Armor}/${obj.MaxArmor}"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.definition.converter
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
import net.psforever.objects.{EquipmentSlot, ImplantSlot, Player}
|
import net.psforever.objects.{EquipmentSlot, Player}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, Cosmetics, DetailedCharacterData, DrawnSlot, ImplantEffects, ImplantEntry, InternalSlot, InventoryData, PlacementData, RibbonBars, UniformStyle}
|
import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, Cosmetics, DetailedCharacterData, DrawnSlot, ImplantEffects, ImplantEntry, InternalSlot, InventoryData, PlacementData, RibbonBars, UniformStyle}
|
||||||
import net.psforever.types.{GrenadeState, ImplantType}
|
import net.psforever.types.{GrenadeState, ImplantType}
|
||||||
|
|
@ -136,18 +136,12 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
||||||
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
private def MakeImplantEntries(obj : Player) : List[ImplantEntry] = {
|
||||||
val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP)
|
val numImplants : Int = DetailedCharacterData.numberOfImplantSlots(obj.BEP)
|
||||||
val implants = obj.Implants
|
val implants = obj.Implants
|
||||||
(0 until numImplants).map(index => {
|
obj.Implants.map({ case(implant, initialization, active) =>
|
||||||
val slot = implants(index)
|
if(initialization == 0) {
|
||||||
slot.Installed match {
|
ImplantEntry(implant, None)
|
||||||
case Some(implant) =>
|
}
|
||||||
if(slot.Initialized) {
|
else {
|
||||||
ImplantEntry(slot.Implant, None)
|
ImplantEntry(implant, Some(math.max(0,initialization).toInt))
|
||||||
}
|
|
||||||
else {
|
|
||||||
ImplantEntry(slot.Implant, Some(implant.Initialization.toInt))
|
|
||||||
}
|
|
||||||
case None =>
|
|
||||||
ImplantEntry(ImplantType.None, None)
|
|
||||||
}
|
}
|
||||||
}).toList
|
}).toList
|
||||||
}
|
}
|
||||||
|
|
@ -157,14 +151,14 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
|
||||||
* @param iter an `Iterator` of `ImplantSlot` objects
|
* @param iter an `Iterator` of `ImplantSlot` objects
|
||||||
* @return the effect of an active implant
|
* @return the effect of an active implant
|
||||||
*/
|
*/
|
||||||
@tailrec private def recursiveMakeImplantEffects(iter : Iterator[ImplantSlot]) : Option[ImplantEffects.Value] = {
|
@tailrec private def recursiveMakeImplantEffects(iter : Iterator[(ImplantType.Value, Long, Boolean)]) : Option[ImplantEffects.Value] = {
|
||||||
if(!iter.hasNext) {
|
if(!iter.hasNext) {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val slot = iter.next
|
val(implant, _, active) = iter.next
|
||||||
if(slot.Active) {
|
if(active) {
|
||||||
slot.Implant match {
|
implant match {
|
||||||
case ImplantType.AdvancedRegen =>
|
case ImplantType.AdvancedRegen =>
|
||||||
Some(ImplantEffects.RegenEffects)
|
Some(ImplantEffects.RegenEffects)
|
||||||
case ImplantType.DarklightVision =>
|
case ImplantType.DarklightVision =>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,124 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.definition.converter
|
||||||
|
|
||||||
|
import net.psforever.objects.{EquipmentSlot, Player}
|
||||||
|
import net.psforever.objects.equipment.Equipment
|
||||||
|
import net.psforever.packet.game.objectcreate.{BasicCharacterData, CharacterAppearanceData, CharacterData, DetailedCharacterData, DrawnSlot, InternalSlot, InventoryData, PlacementData, RibbonBars}
|
||||||
|
import net.psforever.types.{CharacterGender, GrenadeState, Vector3}
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import scala.util.{Failure, Success, Try}
|
||||||
|
|
||||||
|
class CorpseConverter extends AvatarConverter {
|
||||||
|
override def ConstructorData(obj : Player) : Try[CharacterData] =
|
||||||
|
Failure(new Exception("CorpseConverter should not be used to generate CharacterData"))
|
||||||
|
|
||||||
|
override def DetailedConstructorData(obj : Player) : Try[DetailedCharacterData] = {
|
||||||
|
Success(
|
||||||
|
DetailedCharacterData(
|
||||||
|
MakeAppearanceData(obj),
|
||||||
|
0, 0, 0, 0, 0, 0, 0,
|
||||||
|
Nil, Nil, Nil, Nil,
|
||||||
|
None,
|
||||||
|
InventoryData((MakeHolsters(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
|
||||||
|
DrawnSlot.None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compose some data from a `Player` into a representation common to both `CharacterData` and `DetailedCharacterData`.
|
||||||
|
* @param obj the `Player` game object
|
||||||
|
* @return the resulting `CharacterAppearanceData`
|
||||||
|
*/
|
||||||
|
private def MakeAppearanceData(obj : Player) : CharacterAppearanceData = {
|
||||||
|
CharacterAppearanceData(
|
||||||
|
PlacementData(obj.Position, Vector3(0,0, obj.Orientation.z)),
|
||||||
|
BasicCharacterData(obj.Name, obj.Faction, CharacterGender.Male, 0, 0),
|
||||||
|
0,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
obj.ExoSuit,
|
||||||
|
"",
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
obj.Orientation.y, //TODO is this important?
|
||||||
|
0,
|
||||||
|
true,
|
||||||
|
GrenadeState.None,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
RibbonBars()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a player with an inventory, convert the contents of that inventory into converted-decoded packet data.
|
||||||
|
* The inventory is not represented in a `0x17` `Player`, so the conversion is only valid for `0x18` avatars.
|
||||||
|
* It will always be "`Detailed`".
|
||||||
|
* @param obj the `Player` game object
|
||||||
|
* @return a list of all items that were in the inventory in decoded packet form
|
||||||
|
*/
|
||||||
|
private def MakeInventory(obj : Player) : List[InternalSlot] = {
|
||||||
|
obj.Inventory.Items
|
||||||
|
.map({
|
||||||
|
case(_, item) =>
|
||||||
|
val equip : Equipment = item.obj
|
||||||
|
BuildEquipment(item.start, equip)
|
||||||
|
}).toList
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given a player with equipment holsters, convert the contents of those holsters into converted-decoded packet data.
|
||||||
|
* The decoded packet form is determined by the function in the parameters as both `0x17` and `0x18` conversions are available,
|
||||||
|
* with exception to the contents of the fifth slot.
|
||||||
|
* The fifth slot is only represented if the `Player` is an `0x18` type.
|
||||||
|
* @param obj the `Player` game object
|
||||||
|
* @return a list of all items that were in the holsters in decoded packet form
|
||||||
|
*/
|
||||||
|
private def MakeHolsters(obj : Player) : List[InternalSlot] = {
|
||||||
|
recursiveMakeHolsters(obj.Holsters().iterator)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given some equipment holsters, convert the contents of those holsters into converted-decoded packet data.
|
||||||
|
* @param iter an `Iterator` of `EquipmentSlot` objects that are a part of the player's holsters
|
||||||
|
* @param list the current `List` of transformed data
|
||||||
|
* @param index which holster is currently being explored
|
||||||
|
* @return the `List` of inventory data created from the holsters
|
||||||
|
*/
|
||||||
|
@tailrec private def recursiveMakeHolsters(iter : Iterator[EquipmentSlot], list : List[InternalSlot] = Nil, index : Int = 0) : List[InternalSlot] = {
|
||||||
|
if(!iter.hasNext) {
|
||||||
|
list
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val slot : EquipmentSlot = iter.next
|
||||||
|
if(slot.Equipment.isDefined) {
|
||||||
|
val equip : Equipment = slot.Equipment.get
|
||||||
|
recursiveMakeHolsters(
|
||||||
|
iter,
|
||||||
|
list :+ BuildEquipment(index, equip),
|
||||||
|
index + 1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recursiveMakeHolsters(iter, list, index + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A builder method for turning an object into `0x17` decoded packet form.
|
||||||
|
* @param index the position of the object
|
||||||
|
* @param equip the game object
|
||||||
|
* @return the game object in decoded packet form
|
||||||
|
*/
|
||||||
|
private def BuildEquipment(index : Int, equip : Equipment) : InternalSlot = {
|
||||||
|
InternalSlot(equip.Definition.ObjectId, equip.GUID, index, equip.Definition.Packet.DetailedConstructorData(equip).get)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CorpseConverter {
|
||||||
|
val converter = new CorpseConverter
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
|
||||||
PlanetSideGUID(0) //if(obj.Owner.isDefined) { obj.Owner.get } else { PlanetSideGUID(0) } //TODO is this really Owner?
|
PlanetSideGUID(0) //if(obj.Owner.isDefined) { obj.Owner.get } else { PlanetSideGUID(0) } //TODO is this really Owner?
|
||||||
),
|
),
|
||||||
0,
|
0,
|
||||||
obj.Health / obj.MaxHealth * 255, //TODO not precise
|
255 * obj.Health / obj.MaxHealth, //TODO not precise
|
||||||
false, false,
|
false, false,
|
||||||
obj.DeploymentState,
|
obj.DeploymentState,
|
||||||
false,
|
false,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,13 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.guid
|
package net.psforever.objects.guid
|
||||||
|
|
||||||
import net.psforever.objects.vehicles.Utility
|
import akka.actor.ActorRef
|
||||||
|
import net.psforever.objects.entity.IdentifiableEntity
|
||||||
|
import net.psforever.objects.equipment.Equipment
|
||||||
|
import net.psforever.objects.{EquipmentSlot, LockerContainer, Player, Tool, Vehicle}
|
||||||
|
import net.psforever.objects.inventory.Container
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The basic compiled tasks for assigning (registering) and revoking (unregistering) globally unique identifiers.<br>
|
* The basic compiled tasks for assigning (registering) and revoking (unregistering) globally unique identifiers.<br>
|
||||||
|
|
@ -14,17 +20,13 @@ import net.psforever.objects.vehicles.Utility
|
||||||
* It will get passed from the more complicated functions down into the less complicated functions,
|
* It will get passed from the more complicated functions down into the less complicated functions,
|
||||||
* until it has found the basic number assignment functionality.<br>
|
* until it has found the basic number assignment functionality.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* All functions produce a `TaskResolver.GiveTask` container object that is expected to be used by a `TaskResolver`.
|
* All functions produce a `TaskResolver.GiveTask` container object
|
||||||
* These "task containers" can also be unpackaged into their tasks, sorted into other containers,
|
* or a list of `TaskResolver.GiveTask` container objects that is expected to be used by a `TaskResolver` `Actor`.
|
||||||
* and combined with other "task containers" to enact more complicated sequences of operations.
|
* These "task containers" can also be unpackaged into their component tasks, sorted into other containers,
|
||||||
|
* and combined with other tasks to enact more complicated sequences of operations.
|
||||||
|
* Almost all tasks have an explicit registering and an unregistering activity defined for it.
|
||||||
*/
|
*/
|
||||||
object GUIDTask {
|
object GUIDTask {
|
||||||
import akka.actor.ActorRef
|
|
||||||
import net.psforever.objects.entity.IdentifiableEntity
|
|
||||||
import net.psforever.objects.equipment.Equipment
|
|
||||||
import net.psforever.objects.{EquipmentSlot, Player, Tool, Vehicle}
|
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
|
||||||
/**
|
/**
|
||||||
* Construct tasking that registers an object with a globally unique identifier selected from a pool of numbers.<br>
|
* Construct tasking that registers an object with a globally unique identifier selected from a pool of numbers.<br>
|
||||||
* <br>
|
* <br>
|
||||||
|
|
@ -76,9 +78,34 @@ object GUIDTask {
|
||||||
TaskResolver.GiveTask(RegisterObjectTask(obj).task, ammoTasks)
|
TaskResolver.GiveTask(RegisterObjectTask(obj).task, ammoTasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that registers a `LockerContainer` object
|
||||||
|
* with a globally unique identifier selected from a pool of numbers.
|
||||||
|
* @param obj the object being registered
|
||||||
|
* @param guid implicit reference to a unique number system
|
||||||
|
* @see `GUIDTask.UnregisterLocker`
|
||||||
|
* @return a `TaskResolver.GiveTask` message
|
||||||
|
*/
|
||||||
|
def RegisterLocker(obj : LockerContainer)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
|
TaskResolver.GiveTask(RegisterObjectTask(obj).task, RegisterInventory(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that registers the objects that are within the given container's inventory
|
||||||
|
* with a globally unique identifier selected from a pool of numbers for each object.
|
||||||
|
* @param container the storage unit in which objects can be found
|
||||||
|
* @param guid implicit reference to a unique number system
|
||||||
|
* @see `GUID.UnregisterInventory`<br>
|
||||||
|
* `Container`
|
||||||
|
* @return a list of `TaskResolver.GiveTask` messages
|
||||||
|
*/
|
||||||
|
def RegisterInventory(container : Container)(implicit guid : ActorRef) : List[TaskResolver.GiveTask] = {
|
||||||
|
container.Inventory.Items.values.map(entry => { RegisterEquipment(entry.obj)}).toList
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct tasking that registers an object with a globally unique identifier selected from a pool of numbers,
|
* Construct tasking that registers an object with a globally unique identifier selected from a pool of numbers,
|
||||||
* after determining whether the object is complex (`Tool`) or simple.<br>
|
* after determining whether the object is complex (`Tool` or `Locker`) or is simple.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* The objects in this case are specifically `Equipment`, a subclass of the basic register-able `IdentifiableEntity`.
|
* The objects in this case are specifically `Equipment`, a subclass of the basic register-able `IdentifiableEntity`.
|
||||||
* About five subclasses of `Equipment` exist, but they decompose into two groups - "complex objects" and "simple objects."
|
* About five subclasses of `Equipment` exist, but they decompose into two groups - "complex objects" and "simple objects."
|
||||||
|
|
@ -96,6 +123,8 @@ object GUIDTask {
|
||||||
obj match {
|
obj match {
|
||||||
case tool : Tool =>
|
case tool : Tool =>
|
||||||
RegisterTool(tool)
|
RegisterTool(tool)
|
||||||
|
case locker : LockerContainer =>
|
||||||
|
RegisterLocker(locker)
|
||||||
case _ =>
|
case _ =>
|
||||||
RegisterObjectTask(obj)
|
RegisterObjectTask(obj)
|
||||||
}
|
}
|
||||||
|
|
@ -118,17 +147,24 @@ object GUIDTask {
|
||||||
* @return a `TaskResolver.GiveTask` message
|
* @return a `TaskResolver.GiveTask` message
|
||||||
*/
|
*/
|
||||||
def RegisterAvatar(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
def RegisterAvatar(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
import net.psforever.objects.LockerContainer
|
val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), RegisterEquipment)
|
||||||
import net.psforever.objects.inventory.InventoryItem
|
val lockerTask = List(RegisterLocker(tplayer.Locker))
|
||||||
val holsterTasks = recursiveHolsterTaskBuilding(tplayer.Holsters().iterator, RegisterEquipment)
|
val inventoryTasks = RegisterInventory(tplayer)
|
||||||
val fifthHolsterTask = tplayer.Slot(5).Equipment match {
|
TaskResolver.GiveTask(RegisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks)
|
||||||
case Some(locker) =>
|
}
|
||||||
RegisterObjectTask(locker) :: locker.asInstanceOf[LockerContainer].Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => RegisterEquipment(entry.obj)}).toList
|
|
||||||
case None =>
|
/**
|
||||||
List.empty[TaskResolver.GiveTask];
|
* Construct tasking that registers an object with a globally unique identifier selected from a pool of numbers, as a `Player`.<br>
|
||||||
}
|
* <br>
|
||||||
val inventoryTasks = tplayer.Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => RegisterEquipment(entry.obj)})
|
* Similar to `RegisterAvatar` but the locker components are skipped.
|
||||||
TaskResolver.GiveTask(RegisterObjectTask(tplayer).task, holsterTasks ++ fifthHolsterTask ++ inventoryTasks)
|
* @param tplayer the `Player` object being registered
|
||||||
|
* @param guid implicit reference to a unique number system
|
||||||
|
* @return a `TaskResolver.GiveTask` message
|
||||||
|
*/
|
||||||
|
def RegisterPlayer(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
|
val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), RegisterEquipment)
|
||||||
|
val inventoryTasks = RegisterInventory(tplayer)
|
||||||
|
TaskResolver.GiveTask(GUIDTask.RegisterObjectTask(tplayer)(guid).task, holsterTasks ++ inventoryTasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -149,10 +185,9 @@ object GUIDTask {
|
||||||
* @return a `TaskResolver.GiveTask` message
|
* @return a `TaskResolver.GiveTask` message
|
||||||
*/
|
*/
|
||||||
def RegisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
def RegisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
import net.psforever.objects.inventory.InventoryItem
|
val weaponTasks = VisibleSlotTaskBuilding(vehicle.Weapons.values, RegisterEquipment)
|
||||||
val weaponTasks = vehicle.Weapons.map({ case(_ : Int, entry : EquipmentSlot) => RegisterEquipment(entry.Equipment.get)}).toList
|
val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).values.map(util => { RegisterObjectTask(util())}).toList
|
||||||
val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).map({case (_ : Int, util : Utility) => RegisterObjectTask(util())}).toList
|
val inventoryTasks = RegisterInventory(vehicle)
|
||||||
val inventoryTasks = vehicle.Trunk.Items.map({ case((_ : Int, entry : InventoryItem)) => RegisterEquipment(entry.obj)})
|
|
||||||
TaskResolver.GiveTask(RegisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
|
TaskResolver.GiveTask(RegisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -201,9 +236,33 @@ object GUIDTask {
|
||||||
TaskResolver.GiveTask(UnregisterObjectTask(obj).task, ammoTasks)
|
TaskResolver.GiveTask(UnregisterObjectTask(obj).task, ammoTasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that unregisters a `LockerContainer` object from a globally unique identifier system.
|
||||||
|
* @param obj the object being unregistered
|
||||||
|
* @param guid implicit reference to a unique number system
|
||||||
|
* @see `GUIDTask.RegisterLocker`
|
||||||
|
* @return a `TaskResolver.GiveTask` message
|
||||||
|
*/
|
||||||
|
def UnregisterLocker(obj : LockerContainer)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
|
TaskResolver.GiveTask(UnregisterObjectTask(obj).task, UnregisterInventory(obj))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that unregisters the objects that are within the given container's inventory
|
||||||
|
* from a globally unique identifier system.
|
||||||
|
* @param container the storage unit in which objects can be found
|
||||||
|
* @param guid implicit reference to a unique number system
|
||||||
|
* @see `GUIDTask.RegisterInventory`<br>
|
||||||
|
* `Container`
|
||||||
|
* @return a list of `TaskResolver.GiveTask` messages
|
||||||
|
*/
|
||||||
|
def UnregisterInventory(container : Container)(implicit guid : ActorRef) : List[TaskResolver.GiveTask] = {
|
||||||
|
container.Inventory.Items.values.map(entry => { UnregisterEquipment(entry.obj)}).toList
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct tasking that unregisters an object from a globally unique identifier system
|
* Construct tasking that unregisters an object from a globally unique identifier system
|
||||||
* after determining whether the object is complex (`Tool`) or simple.<br>
|
* after determining whether the object is complex (`Tool` or `Locker`) or is simple.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* This task performs an operation that reverses the effect of `RegisterEquipment`.
|
* This task performs an operation that reverses the effect of `RegisterEquipment`.
|
||||||
* @param obj the `Equipment` object being unregistered
|
* @param obj the `Equipment` object being unregistered
|
||||||
|
|
@ -215,6 +274,8 @@ object GUIDTask {
|
||||||
obj match {
|
obj match {
|
||||||
case tool : Tool =>
|
case tool : Tool =>
|
||||||
UnregisterTool(tool)
|
UnregisterTool(tool)
|
||||||
|
case locker : LockerContainer =>
|
||||||
|
UnregisterLocker(locker)
|
||||||
case _ =>
|
case _ =>
|
||||||
UnregisterObjectTask(obj)
|
UnregisterObjectTask(obj)
|
||||||
}
|
}
|
||||||
|
|
@ -230,36 +291,58 @@ object GUIDTask {
|
||||||
* @return a `TaskResolver.GiveTask` message
|
* @return a `TaskResolver.GiveTask` message
|
||||||
*/
|
*/
|
||||||
def UnregisterAvatar(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
def UnregisterAvatar(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
import net.psforever.objects.LockerContainer
|
val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), UnregisterEquipment)
|
||||||
import net.psforever.objects.inventory.InventoryItem
|
val lockerTask = List(UnregisterLocker(tplayer.Locker))
|
||||||
val holsterTasks = recursiveHolsterTaskBuilding(tplayer.Holsters().iterator, UnregisterEquipment)
|
val inventoryTasks = UnregisterInventory(tplayer)
|
||||||
val inventoryTasks = tplayer.Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => UnregisterEquipment(entry.obj)})
|
TaskResolver.GiveTask(UnregisterObjectTask(tplayer).task, holsterTasks ++ lockerTask ++ inventoryTasks)
|
||||||
val fifthHolsterTask = tplayer.Slot(5).Equipment match {
|
|
||||||
case Some(locker) =>
|
|
||||||
UnregisterObjectTask(locker) :: locker.asInstanceOf[LockerContainer].Inventory.Items.map({ case((_ : Int, entry : InventoryItem)) => UnregisterEquipment(entry.obj)}).toList
|
|
||||||
case None =>
|
|
||||||
List.empty[TaskResolver.GiveTask];
|
|
||||||
}
|
|
||||||
TaskResolver.GiveTask(UnregisterObjectTask(tplayer).task, holsterTasks ++ fifthHolsterTask ++ inventoryTasks)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct tasking that unregisters a `Vehicle` object from a globally unique identifier system.<br>
|
* Construct tasking that unregisters a portion of a `Player` object from a globally unique identifier system.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* This task performs an operation that reverses the effect of `RegisterVehicle`.
|
* Similar to `UnregisterAvatar` but the locker components are skipped.
|
||||||
* @param vehicle the `Vehicle` object being unregistered
|
* This task performs an operation that reverses the effect of `RegisterPlayer`.
|
||||||
* @param guid implicit reference to a unique number system
|
* @param tplayer the `Player` object being unregistered
|
||||||
* @see `GUIDTask.RegisterVehicle`
|
* @param guid implicit reference to a unique number system
|
||||||
* @return a `TaskResolver.GiveTask` message
|
* @see `GUIDTask.RegisterAvatar`
|
||||||
*/
|
* @return a `TaskResolver.GiveTask` message
|
||||||
|
*/
|
||||||
|
def UnregisterPlayer(tplayer : Player)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
|
val holsterTasks = VisibleSlotTaskBuilding(tplayer.Holsters(), UnregisterEquipment)
|
||||||
|
val inventoryTasks = UnregisterInventory(tplayer)
|
||||||
|
TaskResolver.GiveTask(GUIDTask.UnregisterObjectTask(tplayer).task, holsterTasks ++ inventoryTasks)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that unregisters a `Vehicle` object from a globally unique identifier system.<br>
|
||||||
|
* <br>
|
||||||
|
* This task performs an operation that reverses the effect of `RegisterVehicle`.
|
||||||
|
* @param vehicle the `Vehicle` object being unregistered
|
||||||
|
* @param guid implicit reference to a unique number system
|
||||||
|
* @see `GUIDTask.RegisterVehicle`
|
||||||
|
* @return a `TaskResolver.GiveTask` message
|
||||||
|
*/
|
||||||
def UnregisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
def UnregisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
|
||||||
import net.psforever.objects.inventory.InventoryItem
|
val weaponTasks = VisibleSlotTaskBuilding(vehicle.Weapons.values, UnregisterEquipment)
|
||||||
val weaponTasks = vehicle.Weapons.map({ case(_ : Int, entry : EquipmentSlot) => UnregisterTool(entry.Equipment.get.asInstanceOf[Tool]) }).toList
|
val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).values.map(util => { UnregisterObjectTask(util())}).toList
|
||||||
val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).map({case (_ : Int, util : Utility) => UnregisterObjectTask(util())}).toList
|
val inventoryTasks = UnregisterInventory(vehicle)
|
||||||
val inventoryTasks = vehicle.Trunk.Items.map({ case((_ : Int, entry : InventoryItem)) => UnregisterEquipment(entry.obj)})
|
|
||||||
TaskResolver.GiveTask(UnregisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
|
TaskResolver.GiveTask(UnregisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Construct tasking that allocates work upon encountered `Equipment` objects
|
||||||
|
* in reference to a globally unique identifier system of a pool of numbers.
|
||||||
|
* "Visible slots" are locations that can be viewed by multiple observers across a number of clients.
|
||||||
|
* @param list an `Iterable` sequence of `EquipmentSlot` objects that may or may not have equipment
|
||||||
|
* @param func the function used to build tasking from any discovered `Equipment`;
|
||||||
|
* strictly either `RegisterEquipment` or `UnregisterEquipment`
|
||||||
|
* @param guid implicit reference to a unique number system
|
||||||
|
* @return a list of `TaskResolver.GiveTask` messages
|
||||||
|
*/
|
||||||
|
def VisibleSlotTaskBuilding(list : Iterable[EquipmentSlot], func : ((Equipment)=>TaskResolver.GiveTask))(implicit guid : ActorRef) : List[TaskResolver.GiveTask] = {
|
||||||
|
recursiveVisibleSlotTaskBuilding(list.iterator, func)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Iterate over a group of `EquipmentSlot`s, some of which may be occupied with an item.
|
* Iterate over a group of `EquipmentSlot`s, some of which may be occupied with an item.
|
||||||
* Use `func` on any discovered `Equipment` to transform items into tasking, and add the tasking to a `List`.
|
* Use `func` on any discovered `Equipment` to transform items into tasking, and add the tasking to a `List`.
|
||||||
|
|
@ -267,18 +350,19 @@ object GUIDTask {
|
||||||
* @param func the function used to build tasking from any discovered `Equipment`;
|
* @param func the function used to build tasking from any discovered `Equipment`;
|
||||||
* strictly either `RegisterEquipment` or `UnregisterEquipment`
|
* strictly either `RegisterEquipment` or `UnregisterEquipment`
|
||||||
* @param list a persistent `List` of `Equipment` tasking
|
* @param list a persistent `List` of `Equipment` tasking
|
||||||
|
* @see `VisibleSlotTaskBuilding`
|
||||||
* @return a `List` of `Equipment` tasking
|
* @return a `List` of `Equipment` tasking
|
||||||
*/
|
*/
|
||||||
@tailrec private def recursiveHolsterTaskBuilding(iter : Iterator[EquipmentSlot], func : ((Equipment)=>TaskResolver.GiveTask), list : List[TaskResolver.GiveTask] = Nil)(implicit guid : ActorRef) : List[TaskResolver.GiveTask] = {
|
@tailrec private def recursiveVisibleSlotTaskBuilding(iter : Iterator[EquipmentSlot], func : ((Equipment)=>TaskResolver.GiveTask), list : List[TaskResolver.GiveTask] = Nil)(implicit guid : ActorRef) : List[TaskResolver.GiveTask] = {
|
||||||
if(!iter.hasNext) {
|
if(!iter.hasNext) {
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iter.next.Equipment match {
|
iter.next.Equipment match {
|
||||||
case Some(item) =>
|
case Some(item) =>
|
||||||
recursiveHolsterTaskBuilding(iter, func, list :+ func(item))
|
recursiveVisibleSlotTaskBuilding(iter, func, list :+ func(item))
|
||||||
case None =>
|
case None =>
|
||||||
recursiveHolsterTaskBuilding(iter, func, list)
|
recursiveVisibleSlotTaskBuilding(iter, func, list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -287,12 +287,7 @@ class UniqueNumberSystem(private val guid : NumberPoolHub, private val poolActor
|
||||||
* @see `UniqueNumberSystem.UnregistrationProcess(Option[GUIDRequest], Int, Int)`
|
* @see `UniqueNumberSystem.UnregistrationProcess(Option[GUIDRequest], Int, Int)`
|
||||||
*/
|
*/
|
||||||
private def NoCallbackReturnNumber(number : Int, poolName : String) : Unit = {
|
private def NoCallbackReturnNumber(number : Int, poolName : String) : Unit = {
|
||||||
poolActors.get(poolName) match {
|
poolActors(poolName) ! NumberPoolActor.ReturnNumber(number, Some(Long.MinValue))
|
||||||
case Some(pool) =>
|
|
||||||
pool ! NumberPoolActor.ReturnNumber(number, Some(Long.MinValue))
|
|
||||||
case None =>
|
|
||||||
log.error(s"critical: tried to return number $number but did not find pool $poolName")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -316,12 +311,7 @@ class UniqueNumberSystem(private val guid : NumberPoolHub, private val poolActor
|
||||||
* @see `UniqueNumberSystem.RegistrationProcess(Option[GUIDRequest], Int, Int)`
|
* @see `UniqueNumberSystem.RegistrationProcess(Option[GUIDRequest], Int, Int)`
|
||||||
*/
|
*/
|
||||||
private def NoCallbackGetSpecificNumber(number : Int, poolName : String) : Unit = {
|
private def NoCallbackGetSpecificNumber(number : Int, poolName : String) : Unit = {
|
||||||
poolActors.get(poolName) match {
|
poolActors(poolName) ! NumberPoolActor.GetSpecificNumber(number, Some(Long.MinValue))
|
||||||
case Some(pool) =>
|
|
||||||
pool ! NumberPoolActor.GetSpecificNumber(number, Some(Long.MinValue))
|
|
||||||
case None =>
|
|
||||||
log.error(s"critical: tried to re-register number $number but did not find pool $poolName")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ import net.psforever.objects.guid.NumberPoolHub
|
||||||
* a closed number space, which is also the `Zone`.
|
* a closed number space, which is also the `Zone`.
|
||||||
* It utilizes those qualities of the enclosing region to construct the entity within that region.<br>
|
* It utilizes those qualities of the enclosing region to construct the entity within that region.<br>
|
||||||
* <br>
|
* <br>
|
||||||
* Example: `ServerObjectBuilder(n, function)`
|
* Example: `ServerObjectBuilder(n, function)`<br>
|
||||||
* Example: `new ServerBuilderObject[A](n, function)`, where `function` is a `(Int,Context)=>A`
|
* Example: `new ServerBuilderObject[A](n, function)`, where `function` is a `(Int,Context)=>A`
|
||||||
* @see `ZoneMap`
|
* @see `ZoneMap`
|
||||||
* @see `Zone.Init`
|
* @see `Zone.Init`
|
||||||
|
|
@ -28,7 +28,7 @@ import net.psforever.objects.guid.NumberPoolHub
|
||||||
* can be inferred from the output of `constructor`
|
* can be inferred from the output of `constructor`
|
||||||
*/
|
*/
|
||||||
class ServerObjectBuilder[A <: PlanetSideServerObject](private val id : Int,
|
class ServerObjectBuilder[A <: PlanetSideServerObject](private val id : Int,
|
||||||
private val constructor : (Int, ActorContext) => A
|
private val constructor : ServerObjectBuilder.ConstructorType[A]
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Instantiate and configure the given server object.
|
* Instantiate and configure the given server object.
|
||||||
|
|
@ -49,6 +49,8 @@ class ServerObjectBuilder[A <: PlanetSideServerObject](private val id : Int,
|
||||||
}
|
}
|
||||||
|
|
||||||
object ServerObjectBuilder {
|
object ServerObjectBuilder {
|
||||||
|
type ConstructorType[A <: PlanetSideServerObject] = (Int, ActorContext)=>A
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overloaded constructor.
|
* Overloaded constructor.
|
||||||
* @param id the unqiue id that will be assigned to this entity
|
* @param id the unqiue id that will be assigned to this entity
|
||||||
|
|
@ -56,7 +58,7 @@ object ServerObjectBuilder {
|
||||||
* @tparam A any object that extends from PlanetSideServerObject that will be produced by this class
|
* @tparam A any object that extends from PlanetSideServerObject that will be produced by this class
|
||||||
* @return a `ServerObjectBuilder` object
|
* @return a `ServerObjectBuilder` object
|
||||||
*/
|
*/
|
||||||
def apply[A <: PlanetSideServerObject](id : Int, constructor : (Int, ActorContext) => A) : ServerObjectBuilder[A] = {
|
def apply[A <: PlanetSideServerObject](id : Int, constructor : ConstructorType[A]) : ServerObjectBuilder[A] = {
|
||||||
new ServerObjectBuilder[A](id, constructor)
|
new ServerObjectBuilder[A](id, constructor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,14 +6,19 @@ import net.psforever.objects.definition.ObjectDefinition
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
|
|
||||||
class Building(private val id : Int, private val zone : Zone) extends PlanetSideServerObject {
|
class Building(private val mapId : Int, private val zone : Zone, private val buildingType : StructureType.Value) extends PlanetSideServerObject {
|
||||||
|
/**
|
||||||
|
* The mapId is the identifier number used in BuildingInfoUpdateMessage.
|
||||||
|
* The modelId is the identifier number used in SetEmpireMessage.
|
||||||
|
*/
|
||||||
|
private var modelId : Option[Int] = None
|
||||||
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||||
private var amenities : List[Amenity] = List.empty
|
private var amenities : List[Amenity] = List.empty
|
||||||
GUID = PlanetSideGUID(0)
|
GUID = PlanetSideGUID(0)
|
||||||
|
|
||||||
def Id : Int = id
|
def Id : Int = mapId
|
||||||
|
|
||||||
def Faction : PlanetSideEmpire.Value = faction
|
def Faction : PlanetSideEmpire.Value = faction
|
||||||
|
|
||||||
|
|
@ -32,25 +37,44 @@ class Building(private val id : Int, private val zone : Zone) extends PlanetSide
|
||||||
|
|
||||||
def Zone : Zone = zone
|
def Zone : Zone = zone
|
||||||
|
|
||||||
|
def ModelId : Int = modelId.getOrElse(Id)
|
||||||
|
|
||||||
|
def ModelId_=(id : Int) : Int = ModelId_=(Some(id))
|
||||||
|
|
||||||
|
def ModelId_=(id : Option[Int]) : Int = {
|
||||||
|
modelId = id
|
||||||
|
ModelId
|
||||||
|
}
|
||||||
|
|
||||||
|
def BuildingType : StructureType.Value = buildingType
|
||||||
|
|
||||||
def Definition: ObjectDefinition = Building.BuildingDefinition
|
def Definition: ObjectDefinition = Building.BuildingDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
object Building {
|
object Building {
|
||||||
final val NoBuilding : Building = new Building(0, Zone.Nowhere) {
|
final val NoBuilding : Building = new Building(0, Zone.Nowhere, StructureType.Platform) {
|
||||||
override def Faction_=(faction : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
override def Faction_=(faction : PlanetSideEmpire.Value) : PlanetSideEmpire.Value = PlanetSideEmpire.NEUTRAL
|
||||||
override def Amenities_=(obj : Amenity) : List[Amenity] = Nil
|
override def Amenities_=(obj : Amenity) : List[Amenity] = Nil
|
||||||
}
|
}
|
||||||
|
|
||||||
final val BuildingDefinition : ObjectDefinition = new ObjectDefinition(0) { Name = "building" }
|
final val BuildingDefinition : ObjectDefinition = new ObjectDefinition(0) { Name = "building" }
|
||||||
|
|
||||||
def apply(id : Int, zone : Zone) : Building = {
|
def apply(id : Int, zone : Zone, buildingType : StructureType.Value) : Building = {
|
||||||
new Building(id, zone)
|
new Building(id, zone, buildingType)
|
||||||
}
|
}
|
||||||
|
|
||||||
def Structure(id : Int, zone : Zone, context : ActorContext) : Building = {
|
def Structure(buildingType : StructureType.Value, location : Vector3)(id : Int, zone : Zone, context : ActorContext) : Building = {
|
||||||
import akka.actor.Props
|
import akka.actor.Props
|
||||||
val obj = new Building(id, zone)
|
val obj = new Building(id, zone, buildingType)
|
||||||
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$id-building")
|
obj.Position = location
|
||||||
|
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$id-$buildingType-building")
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
def Structure(buildingType : StructureType.Value)(id : Int, zone : Zone, context : ActorContext) : Building = {
|
||||||
|
import akka.actor.Props
|
||||||
|
val obj = new Building(id, zone, buildingType)
|
||||||
|
obj.Actor = context.actorOf(Props(classOf[BuildingControl], obj), s"$id-$buildingType-building")
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.serverobject.structures
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `Enumeration` of the kinds of building structures found in the game.
|
||||||
|
* This is merely a kludge for more a future, more complicated internal object that handles base operations.
|
||||||
|
*/
|
||||||
|
object StructureType extends Enumeration {
|
||||||
|
type Type = Value
|
||||||
|
|
||||||
|
val
|
||||||
|
Bridge,
|
||||||
|
Building, //generic
|
||||||
|
Bunker,
|
||||||
|
Facility,
|
||||||
|
Platform, //outdoor amenities like the spawn pads in sanctuary
|
||||||
|
Tower,
|
||||||
|
WarpGate
|
||||||
|
= Value
|
||||||
|
}
|
||||||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.serverobject.structures
|
||||||
import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
|
|
||||||
class WarpGate(id : Int, zone : Zone) extends Building(id, zone) {
|
class WarpGate(id : Int, zone : Zone) extends Building(id, zone, StructureType.WarpGate) {
|
||||||
//TODO stuff later
|
//TODO stuff later
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -339,8 +339,8 @@ object EquipmentTerminalDefinition {
|
||||||
import net.psforever.objects.Loadout._
|
import net.psforever.objects.Loadout._
|
||||||
entry match {
|
entry match {
|
||||||
case obj : ShorthandTool =>
|
case obj : ShorthandTool =>
|
||||||
val ammo : List[AmmoBoxDefinition] = obj.ammo.map(fmode => { fmode.ammo.adef })
|
val ammo : List[AmmoBoxDefinition] = obj.ammo.map(fmode => { fmode.ammo.definition })
|
||||||
val tool = Tool(obj.tdef)
|
val tool = Tool(obj.definition)
|
||||||
//makes Tools where an ammo slot may have one of its alternate ammo types
|
//makes Tools where an ammo slot may have one of its alternate ammo types
|
||||||
(0 until tool.MaxAmmoSlot).foreach(index => {
|
(0 until tool.MaxAmmoSlot).foreach(index => {
|
||||||
val slot = tool.AmmoSlots(index)
|
val slot = tool.AmmoSlots(index)
|
||||||
|
|
@ -350,16 +350,16 @@ object EquipmentTerminalDefinition {
|
||||||
tool
|
tool
|
||||||
|
|
||||||
case obj : ShorthandAmmoBox =>
|
case obj : ShorthandAmmoBox =>
|
||||||
MakeAmmoBox(obj.adef, Some(obj.capacity))
|
MakeAmmoBox(obj.definition, Some(obj.capacity))
|
||||||
|
|
||||||
case obj : ShorthandConstructionItem =>
|
case obj : ShorthandConstructionItem =>
|
||||||
MakeConstructionItem(obj.cdef)
|
MakeConstructionItem(obj.definition)
|
||||||
|
|
||||||
case obj : ShorthandSimpleItem =>
|
case obj : ShorthandSimpleItem =>
|
||||||
MakeSimpleItem(obj.sdef)
|
MakeSimpleItem(obj.definition)
|
||||||
|
|
||||||
case obj : ShorthandKit =>
|
case obj : ShorthandKit =>
|
||||||
MakeKit(obj.kdef)
|
MakeKit(obj.definition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,11 @@ class MatrixTerminalDefinition(object_id : Int) extends TerminalDefinition(objec
|
||||||
else if(object_id == 519) {
|
else if(object_id == 519) {
|
||||||
"matrix_terminalc"
|
"matrix_terminalc"
|
||||||
}
|
}
|
||||||
|
else if(object_id == 812) {
|
||||||
|
"spawn_terminal"
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
throw new IllegalArgumentException("terminal must be object id 517-519")
|
throw new IllegalArgumentException("terminal must be object id 517-519 or 812")
|
||||||
}
|
}
|
||||||
|
|
||||||
override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
override def Buy(player : Player, msg : ItemTransactionMessage) : Terminal.Exchange = Terminal.NoDeal()
|
||||||
|
|
|
||||||
|
|
@ -1,34 +1,58 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.serverobject.tube
|
package net.psforever.objects.serverobject.tube
|
||||||
|
|
||||||
import net.psforever.objects.definition.ObjectDefinition
|
import net.psforever.objects.GlobalDefinitions
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
|
|
||||||
class SpawnTube(tubeDef : ObjectDefinition) extends Amenity {
|
/**
|
||||||
def Definition : ObjectDefinition = tubeDef
|
* An owned server object that is used as a placeholder for the position and direction
|
||||||
|
* that infantry will be arranged upon spawning into the game world.
|
||||||
|
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||||
|
*/
|
||||||
|
class SpawnTube(tDef : SpawnTubeDefinition) extends Amenity {
|
||||||
|
def Definition : SpawnTubeDefinition = tDef
|
||||||
}
|
}
|
||||||
|
|
||||||
object SpawnTube {
|
object SpawnTube {
|
||||||
def apply(tubeDef : ObjectDefinition) : SpawnTube = {
|
/**
|
||||||
new SpawnTube(tubeDef)
|
* Overloaded constructor.
|
||||||
|
* @param tDef the spawn tube's definition entry
|
||||||
|
* @return a `SpawnTube` object
|
||||||
|
*/
|
||||||
|
def apply(tDef : SpawnTubeDefinition) : SpawnTube = {
|
||||||
|
new SpawnTube(tDef)
|
||||||
}
|
}
|
||||||
|
|
||||||
// import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
// import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
// /**
|
/**
|
||||||
// * Instantiate an configure a `SpawnTube` object
|
* Instantiate an configure a `SpawnTube` object
|
||||||
// * @param pos the position (used to determine spawn point)
|
* @param pos the position (used to determine spawn point)
|
||||||
// * @param orient the orientation (used to indicate spawn direction)
|
* @param orient the orientation (used to indicate spawn direction)
|
||||||
// * @param id the unique id that will be assigned to this entity
|
* @param id the unique id that will be assigned to this entity
|
||||||
// * @param context a context to allow the object to properly set up `ActorSystem` functionality
|
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
||||||
// * @return the `SpawnTube` object
|
* @return the `SpawnTube` object
|
||||||
// */
|
*/
|
||||||
// def Constructor(pos : Vector3, orient : Vector3)(id : Int, context : ActorContext) : SpawnTube = {
|
def Constructor(pos : Vector3, orient : Vector3)(id : Int, context : ActorContext) : SpawnTube = {
|
||||||
// import net.psforever.objects.GlobalDefinitions
|
Constructor(GlobalDefinitions.respawn_tube, pos, orient)(id, context)
|
||||||
//
|
}
|
||||||
// val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
|
|
||||||
// obj.Position = pos
|
/**
|
||||||
// obj.Orientation = orient
|
* Instantiate an configure a `SpawnTube` object with the given definition
|
||||||
// obj
|
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||||
// }
|
* @param pos the position (used to determine spawn point)
|
||||||
|
* @param orient the orientation (used to indicate spawn direction)
|
||||||
|
* @param id the unique id that will be assigned to this entity
|
||||||
|
* @param context a context to allow the object to properly set up `ActorSystem` functionality
|
||||||
|
* @return the `SpawnTube` object
|
||||||
|
*/
|
||||||
|
def Constructor(tdef : SpawnTubeDefinition, pos : Vector3, orient : Vector3)(id : Int, context : ActorContext) : SpawnTube = {
|
||||||
|
import akka.actor.Props
|
||||||
|
|
||||||
|
val obj = SpawnTube(tdef)
|
||||||
|
obj.Position = pos
|
||||||
|
obj.Orientation = orient
|
||||||
|
obj.Actor = context.actorOf(Props(classOf[SpawnTubeControl], obj), s"${tdef.Name}_$id")
|
||||||
|
obj
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,24 @@ import net.psforever.objects.definition.ObjectDefinition
|
||||||
import net.psforever.objects.definition.converter.SpawnTubeConverter
|
import net.psforever.objects.definition.converter.SpawnTubeConverter
|
||||||
import net.psforever.objects.serverobject.structures.Amenity
|
import net.psforever.objects.serverobject.structures.Amenity
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition for any `VehicleSpawnPad`.
|
||||||
|
* Currently, all tubes identify as object id 49 - `ams_respawn_tube` - configured manually.
|
||||||
|
* @see `GlobalDefinitions.ams_respawn_tube`
|
||||||
|
*/
|
||||||
class SpawnTubeDefinition(object_id : Int) extends ObjectDefinition(object_id) {
|
class SpawnTubeDefinition(object_id : Int) extends ObjectDefinition(object_id) {
|
||||||
|
Name = if(object_id == 49) {
|
||||||
|
"ams_respawn_tube"
|
||||||
|
}
|
||||||
|
else if(object_id == 732) {
|
||||||
|
"respawn_tube"
|
||||||
|
}
|
||||||
|
else if(object_id == 733) {
|
||||||
|
"respawn_tube_tower"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException("terminal must be object id 49, 732, or 733")
|
||||||
|
}
|
||||||
Packet = new SpawnTubeConverter
|
Packet = new SpawnTubeConverter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
package net.psforever.objects.zones
|
package net.psforever.objects.zones
|
||||||
|
|
||||||
import akka.actor.{Actor, Props}
|
import akka.actor.{Actor, Props}
|
||||||
import net.psforever.objects.Player
|
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
|
||||||
|
|
@ -42,16 +41,25 @@ class InterstellarCluster(zones : List[Zone]) extends Actor {
|
||||||
def receive : Receive = {
|
def receive : Receive = {
|
||||||
case InterstellarCluster.GetWorld(zoneId) =>
|
case InterstellarCluster.GetWorld(zoneId) =>
|
||||||
log.info(s"Asked to find $zoneId")
|
log.info(s"Asked to find $zoneId")
|
||||||
findWorldInCluster(zones.iterator, zoneId) match {
|
recursiveFindWorldInCluster(zones.iterator, _.Id == zoneId) match {
|
||||||
case Some(continent) =>
|
case Some(continent) =>
|
||||||
sender ! InterstellarCluster.GiveWorld(zoneId, continent)
|
sender ! InterstellarCluster.GiveWorld(zoneId, continent)
|
||||||
case None =>
|
case None =>
|
||||||
log.error(s"Requested zone $zoneId could not be found")
|
log.error(s"Requested zone $zoneId could not be found")
|
||||||
}
|
}
|
||||||
|
|
||||||
case InterstellarCluster.RequestClientInitialization(tplayer) =>
|
case InterstellarCluster.RequestClientInitialization() =>
|
||||||
zones.foreach(zone => { sender ! Zone.ClientInitialization(zone.ClientInitialization()) })
|
zones.foreach(zone => { sender ! Zone.ClientInitialization(zone.ClientInitialization()) })
|
||||||
sender ! InterstellarCluster.ClientInitializationComplete(tplayer) //will be processed after all Zones
|
sender ! InterstellarCluster.ClientInitializationComplete() //will be processed after all Zones
|
||||||
|
|
||||||
|
case msg @ Zone.Lattice.RequestSpawnPoint(zone_number, _, _) =>
|
||||||
|
recursiveFindWorldInCluster(zones.iterator, _.Number == zone_number) match {
|
||||||
|
case Some(zone) =>
|
||||||
|
zone.Actor forward msg
|
||||||
|
|
||||||
|
case None => //zone_number does not exist
|
||||||
|
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, None)
|
||||||
|
}
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
@ -59,20 +67,20 @@ class InterstellarCluster(zones : List[Zone]) extends Actor {
|
||||||
/**
|
/**
|
||||||
* Search through the `List` of `Zone` entities and find the one with the matching designation.
|
* Search through the `List` of `Zone` entities and find the one with the matching designation.
|
||||||
* @param iter an `Iterator` of `Zone` entities
|
* @param iter an `Iterator` of `Zone` entities
|
||||||
* @param zoneId the name of the `Zone`
|
* @param predicate a condition to check against to determine when the appropriate `Zone` is discovered
|
||||||
* @return the discovered `Zone`
|
* @return the discovered `Zone`
|
||||||
*/
|
*/
|
||||||
@tailrec private def findWorldInCluster(iter : Iterator[Zone], zoneId : String) : Option[Zone] = {
|
@tailrec private def recursiveFindWorldInCluster(iter : Iterator[Zone], predicate : Zone=>Boolean) : Option[Zone] = {
|
||||||
if(!iter.hasNext) {
|
if(!iter.hasNext) {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val cont = iter.next
|
val cont = iter.next
|
||||||
if(cont.Id == zoneId) {
|
if(predicate.apply(cont)) {
|
||||||
Some(cont)
|
Some(cont)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
findWorldInCluster(iter, zoneId)
|
recursiveFindWorldInCluster(iter, predicate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -95,17 +103,41 @@ object InterstellarCluster {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Signal to the cluster that a new client needs to be initialized for all listed `Zone` destinations.
|
* Signal to the cluster that a new client needs to be initialized for all listed `Zone` destinations.
|
||||||
* @param tplayer the `Player` belonging to the client;
|
|
||||||
* may be superfluous
|
|
||||||
* @see `Zone`
|
* @see `Zone`
|
||||||
*/
|
*/
|
||||||
final case class RequestClientInitialization(tplayer : Player)
|
final case class RequestClientInitialization()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return signal intended to inform the original sender that all `Zone`s have finished being initialized.
|
* Return signal intended to inform the original sender that all `Zone`s have finished being initialized.
|
||||||
* @param tplayer the `Player` belonging to the client;
|
|
||||||
* may be superfluous
|
|
||||||
* @see `WorldSessionActor`
|
* @see `WorldSessionActor`
|
||||||
*/
|
*/
|
||||||
final case class ClientInitializationComplete(tplayer : Player)
|
final case class ClientInitializationComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// List[Building] --> List[List[(Amenity, Building)]] --> List[(SpawnTube*, Building)]
|
||||||
|
zone.LocalLattice.Buildings.values
|
||||||
|
.filter(_.Faction == player.Faction)
|
||||||
|
.map(building => { building.Amenities.map { _ -> building } })
|
||||||
|
.flatMap( _.filter({ case(amenity, _) => amenity.isInstanceOf[SpawnTube] }) )
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
zone.Buildings.values.filter(building => {
|
||||||
|
(
|
||||||
|
if(spawn_zone == 6) { Set(StructureType.Tower) }
|
||||||
|
else if(spawn_zone == 7) { Set(StructureType.Facility, StructureType.Building) }
|
||||||
|
else { Set.empty[StructureType.Value] }
|
||||||
|
).contains(building.BuildingType) &&
|
||||||
|
building.Amenities.exists(_.isInstanceOf[SpawnTube]) &&
|
||||||
|
building.Faction == player.Faction &&
|
||||||
|
building.Position != Vector3.Zero
|
||||||
|
})
|
||||||
|
.toSeq
|
||||||
|
.sortBy(building => {
|
||||||
|
Vector3.DistanceSquared(player.Position, building.Position) < Vector3.DistanceSquared(player.Position, building.Position)
|
||||||
|
})
|
||||||
|
.map(building => { building.Amenities.map { _ -> building } })
|
||||||
|
.flatMap( _.filter({ case(amenity, _) => amenity.isInstanceOf[SpawnTube] }) )
|
||||||
|
).headOption
|
||||||
|
*/
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,19 @@ package net.psforever.objects.zones
|
||||||
|
|
||||||
import akka.actor.{ActorContext, ActorRef, Props}
|
import akka.actor.{ActorContext, ActorRef, Props}
|
||||||
import akka.routing.RandomPool
|
import akka.routing.RandomPool
|
||||||
import net.psforever.objects.{PlanetSideGameObject, Player, Vehicle}
|
import net.psforever.objects.{Avatar, PlanetSideGameObject, Player, Vehicle}
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.guid.NumberPoolHub
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
import net.psforever.objects.guid.actor.UniqueNumberSystem
|
import net.psforever.objects.guid.actor.UniqueNumberSystem
|
||||||
import net.psforever.objects.guid.selector.RandomSelector
|
import net.psforever.objects.guid.selector.RandomSelector
|
||||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||||
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
||||||
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
|
import scala.collection.concurrent.TrieMap
|
||||||
import scala.collection.mutable.ListBuffer
|
import scala.collection.mutable.ListBuffer
|
||||||
import scala.collection.immutable.{Map => PairMap}
|
import scala.collection.immutable.{Map => PairMap}
|
||||||
|
|
||||||
|
|
@ -44,8 +46,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
private var accessor : ActorRef = ActorRef.noSender
|
private var accessor : ActorRef = ActorRef.noSender
|
||||||
/** The basic support structure for the globally unique number system used by this `Zone`. */
|
/** The basic support structure for the globally unique number system used by this `Zone`. */
|
||||||
private var guid : NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(65536))
|
private var guid : NumberPoolHub = new NumberPoolHub(new LimitedNumberSource(65536))
|
||||||
guid.AddPool("environment", (0 to 2000).toList)
|
guid.AddPool("environment", (0 to 3000).toList) //TODO tailer ro suit requirements of zone
|
||||||
guid.AddPool("dynamic", (2001 to 10000).toList).Selector = new RandomSelector //TODO unlump pools later; do not make too big
|
guid.AddPool("dynamic", (3001 to 10000).toList).Selector = new RandomSelector //TODO unlump pools later; do not make too big
|
||||||
/** A synchronized `List` of items (`Equipment`) dropped by players on the ground and can be collected again. */
|
/** A synchronized `List` of items (`Equipment`) dropped by players on the ground and can be collected again. */
|
||||||
private val equipmentOnGround : ListBuffer[Equipment] = ListBuffer[Equipment]()
|
private val equipmentOnGround : ListBuffer[Equipment] = ListBuffer[Equipment]()
|
||||||
/** Used by the `Zone` to coordinate `Equipment` dropping and collection requests. */
|
/** Used by the `Zone` to coordinate `Equipment` dropping and collection requests. */
|
||||||
|
|
@ -54,8 +56,16 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
private var vehicles : List[Vehicle] = List[Vehicle]()
|
private var vehicles : List[Vehicle] = List[Vehicle]()
|
||||||
/** */
|
/** */
|
||||||
private var transport : ActorRef = ActorRef.noSender
|
private var transport : ActorRef = ActorRef.noSender
|
||||||
|
/** */
|
||||||
|
private val players : TrieMap[Avatar, Option[Player]] = TrieMap[Avatar, Option[Player]]()
|
||||||
|
/** */
|
||||||
|
private val corpses : ListBuffer[Player] = ListBuffer[Player]()
|
||||||
|
/** */
|
||||||
|
private var population : ActorRef = ActorRef.noSender
|
||||||
|
|
||||||
private var buildings : PairMap[Int, Building] = PairMap.empty[Int, Building]
|
private var buildings : PairMap[Int, Building] = PairMap.empty[Int, Building]
|
||||||
|
/** key - spawn zone id, value - buildings belonging to spawn zone */
|
||||||
|
private var spawnGroups : Map[Building, List[SpawnTube]] = PairMap[Building, List[SpawnTube]]()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Establish the basic accessible conditions necessary for a functional `Zone`.<br>
|
* Establish the basic accessible conditions necessary for a functional `Zone`.<br>
|
||||||
|
|
@ -66,7 +76,12 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
* First, the `Actor`-driven aspect of the globally unique identifier system for this `Zone` is finalized.
|
* First, the `Actor`-driven aspect of the globally unique identifier system for this `Zone` is finalized.
|
||||||
* Second, all supporting `Actor` agents are created, e.g., `ground`.
|
* Second, all supporting `Actor` agents are created, e.g., `ground`.
|
||||||
* Third, the `ZoneMap` server objects are loaded and constructed within that aforementioned system.
|
* Third, the `ZoneMap` server objects are loaded and constructed within that aforementioned system.
|
||||||
* To avoid being called more than once, there is a test whether the `accessor` for the globally unique identifier system has been changed.
|
* To avoid being called more than once, there is a test whether the `accessor` for the globally unique identifier system has been changed.<br>
|
||||||
|
* <br>
|
||||||
|
* Execution of this operation should be fail-safe.
|
||||||
|
* The chances of failure should be mitigated or skipped.
|
||||||
|
* An testing routine should be run after the fact on the results of the process.
|
||||||
|
* @see `ZoneActor.ZoneSetupCheck`
|
||||||
* @param context a reference to an `ActorContext` necessary for `Props`
|
* @param context a reference to an `ActorContext` necessary for `Props`
|
||||||
*/
|
*/
|
||||||
def Init(implicit context : ActorContext) : Unit = {
|
def Init(implicit context : ActorContext) : Unit = {
|
||||||
|
|
@ -75,12 +90,12 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
accessor = context.actorOf(RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystem.AllocateNumberPoolActors(guid))), s"$Id-uns")
|
accessor = context.actorOf(RandomPool(25).props(Props(classOf[UniqueNumberSystem], guid, UniqueNumberSystem.AllocateNumberPoolActors(guid))), s"$Id-uns")
|
||||||
ground = context.actorOf(Props(classOf[ZoneGroundActor], equipmentOnGround), s"$Id-ground")
|
ground = context.actorOf(Props(classOf[ZoneGroundActor], equipmentOnGround), s"$Id-ground")
|
||||||
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this), s"$Id-vehicles")
|
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this), s"$Id-vehicles")
|
||||||
|
population = context.actorOf(Props(classOf[ZonePopulationActor], this, players, corpses), s"$Id-players")
|
||||||
|
|
||||||
Map.LocalObjects.foreach({ builderObject =>
|
Map.LocalObjects.foreach({ builderObject => builderObject.Build })
|
||||||
builderObject.Build
|
|
||||||
})
|
|
||||||
MakeBuildings(context)
|
MakeBuildings(context)
|
||||||
AssignAmenities()
|
AssignAmenities()
|
||||||
|
CreateSpawnGroups()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,6 +191,12 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
|
|
||||||
def Vehicles : List[Vehicle] = vehicles
|
def Vehicles : List[Vehicle] = vehicles
|
||||||
|
|
||||||
|
def Players : List[Avatar] = players.keys.toList
|
||||||
|
|
||||||
|
def LivePlayers : List[Player] = players.values.collect( { case Some(tplayer) => tplayer }).toList
|
||||||
|
|
||||||
|
def Corpses : List[Player] = corpses.toList
|
||||||
|
|
||||||
def AddVehicle(vehicle : Vehicle) : List[Vehicle] = {
|
def AddVehicle(vehicle : Vehicle) : List[Vehicle] = {
|
||||||
vehicles = vehicles :+ vehicle
|
vehicles = vehicles :+ vehicle
|
||||||
Vehicles
|
Vehicles
|
||||||
|
|
@ -217,6 +238,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
|
|
||||||
def Transport : ActorRef = transport
|
def Transport : ActorRef = transport
|
||||||
|
|
||||||
|
def Population : ActorRef = population
|
||||||
|
|
||||||
def Buildings : Map[Int, Building] = buildings
|
def Buildings : Map[Int, Building] = buildings
|
||||||
|
|
||||||
def Building(id : Int) : Option[Building] = {
|
def Building(id : Int) : Option[Building] = {
|
||||||
|
|
@ -235,26 +258,55 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private def CreateSpawnGroups() : Unit = {
|
||||||
|
buildings.values
|
||||||
|
.filterNot { _.Position == Vector3.Zero }
|
||||||
|
.map(building => { building -> building.Amenities.collect { case(obj : SpawnTube) => obj } })
|
||||||
|
.filter( { case((_, spawns)) => spawns.nonEmpty })
|
||||||
|
.foreach { SpawnGroups }
|
||||||
|
}
|
||||||
|
|
||||||
|
def SpawnGroups() : Map[Building, List[SpawnTube]] = spawnGroups
|
||||||
|
|
||||||
|
def SpawnGroups(building : Building) : List[SpawnTube] = SpawnGroups(building.Id)
|
||||||
|
|
||||||
|
def SpawnGroups(buildingId : Int) : List[SpawnTube] = {
|
||||||
|
spawnGroups.find({ case((building, _)) => building.Id == buildingId }) match {
|
||||||
|
case Some((_, list)) =>
|
||||||
|
list
|
||||||
|
case None =>
|
||||||
|
List.empty[SpawnTube]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def SpawnGroups(spawns : (Building, List[SpawnTube])) : Map[Building, List[SpawnTube]] = {
|
||||||
|
val (building, tubes) = spawns
|
||||||
|
val entry : Map[Building, List[SpawnTube]] = PairMap(building -> tubes)
|
||||||
|
spawnGroups = spawnGroups ++ entry
|
||||||
|
entry
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provide bulk correspondence on all map entities that can be composed into packet messages and reported to a client.
|
* Provide bulk correspondence on all map entities that can be composed into packet messages and reported to a client.
|
||||||
* These messages are sent in this fashion at the time of joining the server:<br>
|
* These messages are sent in this fashion at the time of joining the server:<br>
|
||||||
* - `BroadcastWarpgateUpdateMessage`<br>
|
|
||||||
* - `BuildingInfoUpdateMessage`<br>
|
* - `BuildingInfoUpdateMessage`<br>
|
||||||
|
* - `DensityLevelUpdateMessage`<br>
|
||||||
|
* - `BroadcastWarpgateUpdateMessage`<br>
|
||||||
* - `CaptureFlagUpdateMessage`<br>
|
* - `CaptureFlagUpdateMessage`<br>
|
||||||
* - `ContinentalLockUpdateMessage`<br>
|
* - `ContinentalLockUpdateMessage`<br>
|
||||||
* - `DensityLevelUpdateMessage`<br>
|
|
||||||
* - `ModuleLimitsMessage`<br>
|
* - `ModuleLimitsMessage`<br>
|
||||||
* - `VanuModuleUpdateMessage`<br>
|
* - `VanuModuleUpdateMessage`<br>
|
||||||
* - `ZoneForcedCavernConnectionMessage`<br>
|
* - `ZoneForcedCavernConnectionMessage`<br>
|
||||||
* - `ZoneInfoMessage`<br>
|
* - `ZoneInfoMessage`<br>
|
||||||
* - `ZoneLockInfoMessage`<br>
|
* - `ZoneLockInfoMessage`<br>
|
||||||
* - `ZonePopulationUpdateMessage`
|
* - `ZonePopulationUpdateMessage`
|
||||||
* @return a `List` of `GamePacket` messages
|
* @return the `Zone` object
|
||||||
*/
|
*/
|
||||||
def ClientInitialization() : Zone = this
|
def ClientInitialization() : Zone = this
|
||||||
}
|
}
|
||||||
|
|
||||||
object Zone {
|
object Zone {
|
||||||
|
/** Default value, non-zone area. */
|
||||||
final val Nowhere : Zone = new Zone("nowhere", new ZoneMap("nowhere"), 99)
|
final val Nowhere : Zone = new Zone("nowhere", new ZoneMap("nowhere"), 99)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -263,6 +315,97 @@ object Zone {
|
||||||
*/
|
*/
|
||||||
final case class Init()
|
final case class Init()
|
||||||
|
|
||||||
|
object Population {
|
||||||
|
/**
|
||||||
|
* Message that introduces a user, by their `Avatar`, into a `Zone`.
|
||||||
|
* That user will be counted as part of that zone's population.
|
||||||
|
* The `avatar` may associate `Player` objects with itself in the future.
|
||||||
|
* @param avatar the `Avatar` object
|
||||||
|
*/
|
||||||
|
final case class Join(avatar : Avatar)
|
||||||
|
/**
|
||||||
|
* Message that excuses a user, by their `Avatar`, into a `Zone`.
|
||||||
|
* That user will not longer be counted as part of that zone's population.
|
||||||
|
* @see `PlayerHasLeft`
|
||||||
|
* @param avatar the `Avatar` object
|
||||||
|
*/
|
||||||
|
final case class Leave(avatar : Avatar)
|
||||||
|
/**
|
||||||
|
* Message that instructs the zone to disassociate a `Player` from this `Actor`.
|
||||||
|
* @see `PlayerAlreadySpawned`<br>
|
||||||
|
* `PlayerCanNotSpawn`
|
||||||
|
* @param avatar the `Avatar` object
|
||||||
|
* @param player the `Player` object
|
||||||
|
*/
|
||||||
|
final case class Spawn(avatar : Avatar, player : Player)
|
||||||
|
/**
|
||||||
|
* Message that instructs the zone to disassociate a `Player` from this `Actor`.
|
||||||
|
* @see `PlayerHasLeft`
|
||||||
|
* @param avatar the `Avatar` object
|
||||||
|
*/
|
||||||
|
final case class Release(avatar : Avatar)
|
||||||
|
/**
|
||||||
|
* Message that acts in reply to `Leave(avatar)` or `Release(avatar)`.
|
||||||
|
* In the former case, the avatar will have successfully left the zone, and `player` may be defined.
|
||||||
|
* In the latter case, the avatar did not initially `Join` the zone, and `player` is `None`.
|
||||||
|
* This message should not be considered a failure or a success case.
|
||||||
|
* @see `Release`<br>
|
||||||
|
* `Leave`
|
||||||
|
* @param zone the `Zone` object
|
||||||
|
* @param player the `Player` object
|
||||||
|
*/
|
||||||
|
final case class PlayerHasLeft(zone : Zone, player : Option[Player]) //Leave(avatar), but still has a player
|
||||||
|
/**
|
||||||
|
* Message that acts in reply to `Spawn(avatar, player)`, but the avatar already has a player.
|
||||||
|
* @param player the `Player` object
|
||||||
|
*/
|
||||||
|
final case class PlayerAlreadySpawned(zone : Zone, player : Player)
|
||||||
|
/**
|
||||||
|
* Message that acts in reply to `Spawn(avatar, player)`, but the avatar did not initially `Join` this zone.
|
||||||
|
* @param zone the `Zone` object
|
||||||
|
* @param player the `Player` object
|
||||||
|
*/
|
||||||
|
final case class PlayerCanNotSpawn(zone : Zone, player : Player)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Corpse {
|
||||||
|
/**
|
||||||
|
* Message that reports to the zone of a freshly dead player.
|
||||||
|
* @param player the dead `Player`
|
||||||
|
*/
|
||||||
|
final case class Add(player : Player)
|
||||||
|
/**
|
||||||
|
* Message that tells the zone to no longer mind the dead player.
|
||||||
|
* @param player the dead `Player`
|
||||||
|
*/
|
||||||
|
final case class Remove(player : Player)
|
||||||
|
}
|
||||||
|
|
||||||
|
object Lattice {
|
||||||
|
/**
|
||||||
|
* Message requesting that the current zone determine where a `player` can spawn.
|
||||||
|
* @param zone_number this zone's numeric identifier
|
||||||
|
* @param player the `Player` object
|
||||||
|
* @param spawn_group the category of spawn points the request wants searched
|
||||||
|
*/
|
||||||
|
final case class RequestSpawnPoint(zone_number : Int, player : Player, spawn_group : Int)
|
||||||
|
/**
|
||||||
|
* Message that returns a discovered spawn point to a request source.
|
||||||
|
* @param zone_id the zone's text identifier
|
||||||
|
* @param building the `Building` in which the spawnpoint is located
|
||||||
|
* @param spawn_tube the spawn point holding object
|
||||||
|
*/
|
||||||
|
final case class SpawnPoint(zone_id : String, building : Building, spawn_tube : SpawnTube)
|
||||||
|
/**
|
||||||
|
* Message that informs a request source that a spawn point could not be discovered with the previous criteria.
|
||||||
|
* @param zone_number this zone's numeric identifier
|
||||||
|
* @param spawn_group the spawn point holding object;
|
||||||
|
* if `None`, then the previous `zone_number` could not be found;
|
||||||
|
* otherwise, no spawn points could be found in the zone
|
||||||
|
*/
|
||||||
|
final case class NoValidSpawnPoint(zone_number : Int, spawn_group : Option[Int])
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Message to relinguish an item and place in on the ground.
|
* Message to relinguish an item and place in on the ground.
|
||||||
* @param item the piece of `Equipment`
|
* @param item the piece of `Equipment`
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,12 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package net.psforever.objects.zones
|
package net.psforever.objects.zones
|
||||||
|
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
import akka.actor.Actor
|
import akka.actor.Actor
|
||||||
import net.psforever.objects.PlanetSideGameObject
|
import net.psforever.objects.PlanetSideGameObject
|
||||||
|
import net.psforever.objects.serverobject.structures.StructureType
|
||||||
|
import net.psforever.types.Vector3
|
||||||
import org.log4s.Logger
|
import org.log4s.Logger
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -12,29 +16,108 @@ import org.log4s.Logger
|
||||||
class ZoneActor(zone : Zone) extends Actor {
|
class ZoneActor(zone : Zone) extends Actor {
|
||||||
private[this] val log = org.log4s.getLogger
|
private[this] val log = org.log4s.getLogger
|
||||||
|
|
||||||
def receive : Receive = {
|
def receive : Receive = Init
|
||||||
|
|
||||||
|
def Init : Receive = {
|
||||||
case Zone.Init() =>
|
case Zone.Init() =>
|
||||||
zone.Init
|
zone.Init
|
||||||
ZoneSetupCheck()
|
ZoneSetupCheck()
|
||||||
|
context.become(Processing)
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
def Processing : Receive = {
|
||||||
|
//frwd to Population Actor
|
||||||
|
case msg @ Zone.Population.Join =>
|
||||||
|
zone.Population forward msg
|
||||||
|
|
||||||
|
case msg @ Zone.Population.Leave =>
|
||||||
|
zone.Population forward msg
|
||||||
|
|
||||||
|
case msg @ Zone.Population.Spawn =>
|
||||||
|
zone.Population forward msg
|
||||||
|
|
||||||
|
case msg @ Zone.Population.Release =>
|
||||||
|
zone.Population forward msg
|
||||||
|
|
||||||
|
case msg @ Zone.Corpse.Add =>
|
||||||
|
zone.Population forward msg
|
||||||
|
|
||||||
|
case msg @ Zone.Corpse.Remove =>
|
||||||
|
zone.Population forward msg
|
||||||
|
|
||||||
|
//frwd to Ground Actor
|
||||||
|
case msg @ Zone.DropItemOnGround =>
|
||||||
|
zone.Ground forward msg
|
||||||
|
|
||||||
|
case msg @ Zone.GetItemOnGround =>
|
||||||
|
zone.Ground forward msg
|
||||||
|
|
||||||
|
//frwd to Vehicle Actor
|
||||||
|
case msg @ Zone.SpawnVehicle =>
|
||||||
|
zone.Transport forward msg
|
||||||
|
|
||||||
|
case msg @ Zone.DespawnVehicle =>
|
||||||
|
zone.Transport forward msg
|
||||||
|
|
||||||
|
//own
|
||||||
|
case Zone.Lattice.RequestSpawnPoint(zone_number, player, spawn_group) =>
|
||||||
|
if(zone_number == zone.Number) {
|
||||||
|
val buildingTypeSet = if(spawn_group == 6) {
|
||||||
|
Set(StructureType.Tower)
|
||||||
|
}
|
||||||
|
else if(spawn_group == 7) {
|
||||||
|
Set(StructureType.Facility, StructureType.Building)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Set.empty[StructureType.Value]
|
||||||
|
}
|
||||||
|
val playerPosition = player.Position.xy
|
||||||
|
zone.SpawnGroups()
|
||||||
|
.filter({ case((building, _)) =>
|
||||||
|
building.Faction == player.Faction && buildingTypeSet.contains(building.BuildingType)
|
||||||
|
})
|
||||||
|
.toSeq
|
||||||
|
.sortBy({ case ((building, _)) =>
|
||||||
|
Vector3.DistanceSquared(playerPosition, building.Position.xy)
|
||||||
|
})
|
||||||
|
.headOption match {
|
||||||
|
case Some((building, List(tube))) =>
|
||||||
|
sender ! Zone.Lattice.SpawnPoint(zone.Id, building, tube)
|
||||||
|
|
||||||
|
case Some((building, tubes)) =>
|
||||||
|
sender ! Zone.Lattice.SpawnPoint(zone.Id, building, scala.util.Random.shuffle(tubes).head)
|
||||||
|
|
||||||
|
case None =>
|
||||||
|
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, Some(spawn_group))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { //wrong zone_number
|
||||||
|
sender ! Zone.Lattice.NoValidSpawnPoint(zone_number, None)
|
||||||
|
}
|
||||||
|
|
||||||
case msg =>
|
case msg =>
|
||||||
log.warn(s"Received unexpected message - $msg")
|
log.warn(s"Received unexpected message - $msg")
|
||||||
}
|
}
|
||||||
|
|
||||||
def ZoneSetupCheck(): Unit = {
|
def ZoneSetupCheck() : Int = {
|
||||||
import ZoneActor._
|
import ZoneActor._
|
||||||
def guid(id : Int) = zone.GUID(id)
|
|
||||||
val map = zone.Map
|
val map = zone.Map
|
||||||
|
def guid(id : Int) = zone.GUID(id)
|
||||||
val slog = org.log4s.getLogger(s"zone/${zone.Id}/sanity")
|
val slog = org.log4s.getLogger(s"zone/${zone.Id}/sanity")
|
||||||
val validateObject : (Int, (PlanetSideGameObject)=>Boolean, String) => Boolean = ValidateObject(guid, slog)
|
val errors = new AtomicInteger(0)
|
||||||
|
val validateObject : (Int, (PlanetSideGameObject)=>Boolean, String) => Boolean = ValidateObject(guid, slog, errors)
|
||||||
|
|
||||||
//check base to object associations
|
//check base to object associations
|
||||||
map.ObjectToBuilding.foreach({ case((object_guid, base_id)) =>
|
map.ObjectToBuilding.foreach({ case((object_guid, building_id)) =>
|
||||||
if(zone.Building(base_id).isEmpty) {
|
if(zone.Building(building_id).isEmpty) {
|
||||||
slog.error(s"expected a building at id #$base_id")
|
slog.error(s"expected a building at id #$building_id")
|
||||||
|
errors.incrementAndGet()
|
||||||
}
|
}
|
||||||
if(guid(object_guid).isEmpty) {
|
if(guid(object_guid).isEmpty) {
|
||||||
slog.error(s"expected object id $object_guid to exist, but it did not")
|
slog.error(s"expected object id $object_guid to exist, but it did not")
|
||||||
|
errors.incrementAndGet()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -55,11 +138,11 @@ class ZoneActor(zone : Zone) extends Actor {
|
||||||
validateObject(mech_guid, ImplantMechCheck, "implant terminal mech")
|
validateObject(mech_guid, ImplantMechCheck, "implant terminal mech")
|
||||||
validateObject(interface_guid, TerminalCheck, "implant terminal interface")
|
validateObject(interface_guid, TerminalCheck, "implant terminal interface")
|
||||||
})
|
})
|
||||||
|
errors.intValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ZoneActor {
|
object ZoneActor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recover an object from a collection and perform any number of validating tests upon it.
|
* Recover an object from a collection and perform any number of validating tests upon it.
|
||||||
* If the object fails any tests, log an error.
|
* If the object fails any tests, log an error.
|
||||||
|
|
@ -73,11 +156,12 @@ object ZoneActor {
|
||||||
* @return `true` if the object was discovered and validates correctly;
|
* @return `true` if the object was discovered and validates correctly;
|
||||||
* `false` if the object failed any tests
|
* `false` if the object failed any tests
|
||||||
*/
|
*/
|
||||||
def ValidateObject(guid : (Int)=>Option[PlanetSideGameObject], elog : Logger)
|
def ValidateObject(guid : (Int)=>Option[PlanetSideGameObject], elog : Logger, errorCounter : AtomicInteger)
|
||||||
(object_guid : Int, test : (PlanetSideGameObject)=>Boolean, description : String) : Boolean = {
|
(object_guid : Int, test : (PlanetSideGameObject)=>Boolean, description : String) : Boolean = {
|
||||||
try {
|
try {
|
||||||
if(!test(guid(object_guid).get)) {
|
if(!test(guid(object_guid).get)) {
|
||||||
elog.error(s"expected id $object_guid to be a $description, but it was not")
|
elog.error(s"expected id $object_guid to be a $description, but it was not")
|
||||||
|
errorCounter.incrementAndGet()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -85,8 +169,9 @@ object ZoneActor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
case _ : Exception =>
|
case e : Exception =>
|
||||||
elog.error(s"expected a $description at id $object_guid but no object is initialized")
|
elog.error(s"expected a $description at id $object_guid but no object is initialized - $e")
|
||||||
|
errorCounter.incrementAndGet()
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package net.psforever.objects.zones
|
package net.psforever.objects.zones
|
||||||
|
|
||||||
import net.psforever.objects.serverobject.structures.FoundationBuilder
|
import net.psforever.objects.serverobject.structures.FoundationBuilder
|
||||||
import net.psforever.objects.serverobject.ServerObjectBuilder
|
import net.psforever.objects.serverobject.{PlanetSideServerObject, ServerObjectBuilder}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The fixed instantiation and relation of a series of server objects.<br>
|
* The fixed instantiation and relation of a series of server objects.<br>
|
||||||
|
|
@ -44,10 +44,15 @@ class ZoneMap(private val name : String) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append the builder for a server object to the list of builders known to this `ZoneMap`.
|
* Append the builder for a server object to the list of builders known to this `ZoneMap`.
|
||||||
* @param obj the builder for a server object
|
* @param id the unique id that will be assigned to this entity
|
||||||
|
* @param constructor the logic that initializes the emitted entity
|
||||||
|
* @return the current number of builders
|
||||||
*/
|
*/
|
||||||
def LocalObject(obj : ServerObjectBuilder[_]) : Unit = {
|
def LocalObject[A <: PlanetSideServerObject](id : Int, constructor : ServerObjectBuilder.ConstructorType[A]) : Int = {
|
||||||
localObjects = localObjects :+ obj
|
if(id > 0) {
|
||||||
|
localObjects = localObjects :+ ServerObjectBuilder[A](id, constructor)
|
||||||
|
}
|
||||||
|
localObjects.size
|
||||||
}
|
}
|
||||||
|
|
||||||
def LocalBuildings : Map[Int, FoundationBuilder] = buildings
|
def LocalBuildings : Map[Int, FoundationBuilder] = buildings
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,184 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package net.psforever.objects.zones
|
||||||
|
|
||||||
|
import akka.actor.Actor
|
||||||
|
import net.psforever.objects.{Avatar, Player}
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import scala.collection.concurrent.TrieMap
|
||||||
|
import scala.collection.mutable.ListBuffer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A support `Actor` that sequences adding and removing `Avatar` and `Player` objects to mappings and lists.
|
||||||
|
* The former mapping is considered to represent every user connect to the `zone` (`as Avatar` objects)
|
||||||
|
* and their current representation (as `Player` objects).
|
||||||
|
* The latter list keeps track of a group of former user representations.
|
||||||
|
* @param zone the `Zone` object
|
||||||
|
* @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||||
|
* @param corpseList a list of `Player` objects
|
||||||
|
*/
|
||||||
|
class ZonePopulationActor(zone : Zone, playerMap : TrieMap[Avatar, Option[Player]], corpseList : ListBuffer[Player]) extends Actor {
|
||||||
|
import ZonePopulationActor._
|
||||||
|
|
||||||
|
def receive : Receive = {
|
||||||
|
case Zone.Population.Join(avatar) =>
|
||||||
|
PopulationJoin(avatar, playerMap)
|
||||||
|
|
||||||
|
case Zone.Population.Leave(avatar) =>
|
||||||
|
PopulationLeave(avatar, playerMap) match {
|
||||||
|
case None => ;
|
||||||
|
case player @ Some(_) =>
|
||||||
|
sender ! Zone.Population.PlayerHasLeft(zone, player)
|
||||||
|
}
|
||||||
|
|
||||||
|
case Zone.Population.Spawn(avatar, player) =>
|
||||||
|
PopulationSpawn(avatar, player, playerMap) match {
|
||||||
|
case Some(tplayer) =>
|
||||||
|
if(tplayer ne player) {
|
||||||
|
sender ! Zone.Population.PlayerAlreadySpawned(zone, player)
|
||||||
|
}
|
||||||
|
case None =>
|
||||||
|
sender ! Zone.Population.PlayerCanNotSpawn(zone, player)
|
||||||
|
}
|
||||||
|
|
||||||
|
case Zone.Population.Release(avatar) =>
|
||||||
|
PopulationRelease(avatar, playerMap) match {
|
||||||
|
case Some(_) => ;
|
||||||
|
case None =>
|
||||||
|
sender ! Zone.Population.PlayerHasLeft(zone, None)
|
||||||
|
}
|
||||||
|
|
||||||
|
case Zone.Corpse.Add(player) =>
|
||||||
|
CorpseAdd(player, corpseList)
|
||||||
|
|
||||||
|
case Zone.Corpse.Remove(player) =>
|
||||||
|
CorpseRemove(player, corpseList)
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ZonePopulationActor {
|
||||||
|
/**
|
||||||
|
* Add an `avatar` as the key of an `Avatar` to `Player` object pair in the given collection.
|
||||||
|
* @param avatar an `Avatar` object
|
||||||
|
* @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||||
|
* @return true, if the mapping is for a new key;
|
||||||
|
* false, if the key already exists
|
||||||
|
*/
|
||||||
|
def PopulationJoin(avatar : Avatar, playerMap : TrieMap[Avatar, Option[Player]]) : Boolean = {
|
||||||
|
playerMap.get(avatar) match {
|
||||||
|
case Some(_) =>
|
||||||
|
false
|
||||||
|
case None =>
|
||||||
|
playerMap += avatar -> None
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Remove an `avatar` from the key of an `Avatar` to `Player` object pair in the given collection.
|
||||||
|
* If a `Player` object is associated at the time, return it safely.
|
||||||
|
* @param avatar an `Avatar` object
|
||||||
|
* @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||||
|
* @return any `Player` object that was associated at the time the `avatar` was removed
|
||||||
|
*/
|
||||||
|
def PopulationLeave(avatar : Avatar, playerMap : TrieMap[Avatar, Option[Player]]) : Option[Player] = {
|
||||||
|
playerMap.remove(avatar) match {
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
case Some(tplayer) =>
|
||||||
|
tplayer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associate a `Player` object as a value to an existing `Avatar` object that will be its key.
|
||||||
|
* Do not overwrite players that are already associated.
|
||||||
|
* @param avatar an `Avatar` object
|
||||||
|
* @param player a `Player` object
|
||||||
|
* @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||||
|
* @return the `Player` object that is associated with the `Avatar` key
|
||||||
|
*/
|
||||||
|
def PopulationSpawn(avatar : Avatar, player : Player, playerMap : TrieMap[Avatar, Option[Player]]) : Option[Player] = {
|
||||||
|
playerMap.get(avatar) match {
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
case Some(tplayer) =>
|
||||||
|
tplayer match {
|
||||||
|
case Some(aplayer) =>
|
||||||
|
Some(aplayer)
|
||||||
|
case None =>
|
||||||
|
playerMap(avatar) = Some(player)
|
||||||
|
Some(player)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disassociate a `Player` object from an existing `Avatar` object that was be its key.
|
||||||
|
* @param avatar an `Avatar` object
|
||||||
|
* @param playerMap the mapping of `Avatar` objects to `Player` objects
|
||||||
|
* @return any `Player` object that is associated at the time
|
||||||
|
*/
|
||||||
|
def PopulationRelease(avatar : Avatar, playerMap : TrieMap[Avatar, Option[Player]]) : Option[Player] = {
|
||||||
|
playerMap.get(avatar) match {
|
||||||
|
case None =>
|
||||||
|
None
|
||||||
|
case Some(tplayer) =>
|
||||||
|
playerMap(avatar) = None
|
||||||
|
tplayer
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the given `player` passes a condition check, add it to the list.
|
||||||
|
* @param player a `Player` object
|
||||||
|
* @param corpseList a list of `Player` objects
|
||||||
|
* @return true, if the `player` was added to the list;
|
||||||
|
* false, otherwise
|
||||||
|
*/
|
||||||
|
def CorpseAdd(player : Player, corpseList : ListBuffer[Player]) : Boolean = {
|
||||||
|
if(player.isBackpack) {
|
||||||
|
corpseList += player
|
||||||
|
true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given `player` from the list.
|
||||||
|
* @param player a `Player` object
|
||||||
|
* @param corpseList a list of `Player` objects
|
||||||
|
*/
|
||||||
|
def CorpseRemove(player : Player, corpseList : ListBuffer[Player]) : Unit = {
|
||||||
|
recursiveFindCorpse(corpseList.iterator, player) match {
|
||||||
|
case None => ;
|
||||||
|
case Some(index) =>
|
||||||
|
corpseList.remove(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A recursive function that finds and removes a specific player from a list of players.
|
||||||
|
* @param iter an `Iterator` of `Player` objects
|
||||||
|
* @param player the target `Player`
|
||||||
|
* @param index the index of the discovered `Player` object
|
||||||
|
* @return the index of the `Player` object in the list to be removed;
|
||||||
|
* `None`, otherwise
|
||||||
|
*/
|
||||||
|
@tailrec final def recursiveFindCorpse(iter : Iterator[Player], player : Player, index : Int = 0) : Option[Int] = {
|
||||||
|
if(!iter.hasNext) {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(iter.next == player) {
|
||||||
|
Some(index)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recursiveFindCorpse(iter, player, index + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,15 +2,19 @@
|
||||||
package net.psforever.packet.game
|
package net.psforever.packet.game
|
||||||
|
|
||||||
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
import scodec.Codec
|
import scodec.Attempt.{Failure, Successful}
|
||||||
|
import scodec.{Codec, Err}
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An `Enumeration` of the various states a `Player` may possess in the cycle of nanite life and death.
|
||||||
|
*/
|
||||||
object DeadState extends Enumeration {
|
object DeadState extends Enumeration {
|
||||||
type Type = Value
|
type Type = Value
|
||||||
|
|
||||||
val
|
val
|
||||||
Nothing,
|
Alive,
|
||||||
Dead,
|
Dead,
|
||||||
Release,
|
Release,
|
||||||
RespawnTime
|
RespawnTime
|
||||||
|
|
@ -20,19 +24,41 @@ object DeadState extends Enumeration {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* na
|
* Dispatched by the server to manipulate the client's management of the `Player` object owned by the user as his "avatar."<br>
|
||||||
* @param state avatar's relationship with the world
|
* <br>
|
||||||
|
* The cycle of a player is generally `Alive` to `Dead` and `Dead` to `Release` and `Release` to `RespawnTimer` to `Alive`.
|
||||||
|
* When deconstructing oneself, the user makes a jump between `Alive` and `Release`;
|
||||||
|
* and, he may make a further jump from `Release` to `Alive` depending on spawning choices.
|
||||||
|
* Being `Alive` is the most common state.
|
||||||
|
* (Despite what anyone says.)
|
||||||
|
* Being `Dead` is just a technical requirement to initialize the revive timer.
|
||||||
|
* The player should be sufficiently "dead" by having his health points decreased to zero.
|
||||||
|
* If the timer is reduced to zero, the player is sent back to their faction-appropriate sanctuary continent.<br>
|
||||||
|
* <br>
|
||||||
|
* `Release` causes a "dead" player to have its character model converted into a backpack or a form of pastry.
|
||||||
|
* This cancels the revival timer - the player may no longer be revived - and brings the user to the deployment map.
|
||||||
|
* From the deployment map, the user may select a place where they may respawn a new character.
|
||||||
|
* The options available form this spawn are not only related to the faction affinity of the bases compared to the user's player(s)
|
||||||
|
* but also to the field `faction` as is provided in the packet.
|
||||||
|
* If the player is converted to a state of `Release` while being alive, the deployment map is still displayed.
|
||||||
|
* Their character model is not replaced by a backpack or pastry.<br>
|
||||||
|
* <br>
|
||||||
|
* `RespawnTimer` is like `Dead` as it is just a formal distinction to cause the client to display a timer.
|
||||||
|
* The state indicates that the player is being resurrected at a previously-selected location in the state `Alive`.
|
||||||
|
* @param state avatar's mortal relationship with the world;
|
||||||
|
* the following timers are applicable during `Death` and `RespawnTimer`;
|
||||||
|
* `faction` is applicable mainly during `Release`
|
||||||
* @param timer_max total length of respawn countdown, in milliseconds
|
* @param timer_max total length of respawn countdown, in milliseconds
|
||||||
* @param timer initial length of the respawn timer, in milliseconds
|
* @param timer initial length of the respawn timer, in milliseconds
|
||||||
* @param pos last position
|
* @param pos player's last position
|
||||||
* @param unk4 na
|
* @param faction spawn points available for this faction on redeployment map
|
||||||
* @param unk5 na
|
* @param unk5 na
|
||||||
*/
|
*/
|
||||||
final case class AvatarDeadStateMessage(state : DeadState.Value,
|
final case class AvatarDeadStateMessage(state : DeadState.Value,
|
||||||
timer_max : Long,
|
timer_max : Long,
|
||||||
timer : Long,
|
timer : Long,
|
||||||
pos : Vector3,
|
pos : Vector3,
|
||||||
unk4 : Long,
|
faction : PlanetSideEmpire.Value,
|
||||||
unk5 : Boolean)
|
unk5 : Boolean)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = AvatarDeadStateMessage
|
type Packet = AvatarDeadStateMessage
|
||||||
|
|
@ -41,12 +67,32 @@ final case class AvatarDeadStateMessage(state : DeadState.Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
object AvatarDeadStateMessage extends Marshallable[AvatarDeadStateMessage] {
|
object AvatarDeadStateMessage extends Marshallable[AvatarDeadStateMessage] {
|
||||||
|
/**
|
||||||
|
* allocate all values from the `PlanetSideEmpire` `Enumeration`
|
||||||
|
*/
|
||||||
|
private val factionLongValues = PlanetSideEmpire.values map { _.id.toLong }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Codec` for converting between the limited `PlanetSideEmpire` `Enumeration` and a `Long` value.
|
||||||
|
*/
|
||||||
|
private val factionLongCodec = uint32L.exmap[PlanetSideEmpire.Value] (
|
||||||
|
fv =>
|
||||||
|
if(factionLongValues.contains(fv)) {
|
||||||
|
Successful(PlanetSideEmpire(fv.toInt))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Failure(Err(s"$fv is not mapped to a PlanetSideEmpire value"))
|
||||||
|
},
|
||||||
|
f =>
|
||||||
|
Successful(f.id.toLong)
|
||||||
|
)
|
||||||
|
|
||||||
implicit val codec : Codec[AvatarDeadStateMessage] = (
|
implicit val codec : Codec[AvatarDeadStateMessage] = (
|
||||||
("state" | DeadState.codec) ::
|
("state" | DeadState.codec) ::
|
||||||
("timer_max" | uint32L) ::
|
("timer_max" | uint32L) ::
|
||||||
("timer" | uint32L) ::
|
("timer" | uint32L) ::
|
||||||
("pos" | Vector3.codec_pos) ::
|
("pos" | Vector3.codec_pos) ::
|
||||||
("unk4" | uint32L) ::
|
("unk4" | factionLongCodec) ::
|
||||||
("unk5" | bool)
|
("unk5" | bool)
|
||||||
).as[AvatarDeadStateMessage]
|
).as[AvatarDeadStateMessage]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,8 @@ import scodec.codecs._
|
||||||
* @param unk3 na
|
* @param unk3 na
|
||||||
*/
|
*/
|
||||||
final case class DisconnectMessage(msg : String,
|
final case class DisconnectMessage(msg : String,
|
||||||
unk2 : String = "",
|
unk2 : String,
|
||||||
unk3 : String = "")
|
unk3 : String)
|
||||||
extends PlanetSideGamePacket {
|
extends PlanetSideGamePacket {
|
||||||
type Packet = DisconnectMessage
|
type Packet = DisconnectMessage
|
||||||
def opcode = GamePacketOpcode.DisconnectMessage
|
def opcode = GamePacketOpcode.DisconnectMessage
|
||||||
|
|
@ -29,6 +29,15 @@ final case class DisconnectMessage(msg : String,
|
||||||
}
|
}
|
||||||
|
|
||||||
object DisconnectMessage extends Marshallable[DisconnectMessage] {
|
object DisconnectMessage extends Marshallable[DisconnectMessage] {
|
||||||
|
/**
|
||||||
|
* Overloaded constructor that focuses only on the visible disconnection message
|
||||||
|
* @param msg the displayed message
|
||||||
|
* @return a `DisconnectMessage` object
|
||||||
|
*/
|
||||||
|
def apply(msg : String) : DisconnectMessage = {
|
||||||
|
new DisconnectMessage(msg, "", "")
|
||||||
|
}
|
||||||
|
|
||||||
implicit val codec : Codec[DisconnectMessage] = (
|
implicit val codec : Codec[DisconnectMessage] = (
|
||||||
("msg" | PacketHelpers.encodedString) ::
|
("msg" | PacketHelpers.encodedString) ::
|
||||||
("unk2" | PacketHelpers.encodedString) ::
|
("unk2" | PacketHelpers.encodedString) ::
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,18 @@ import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacke
|
||||||
import scodec.Codec
|
import scodec.Codec
|
||||||
import scodec.codecs._
|
import scodec.codecs._
|
||||||
|
|
||||||
|
/**
|
||||||
|
* na
|
||||||
|
* @param unk1 when defined, na;
|
||||||
|
* non-zero when selecting the sanctuary option from a non-sanctuary continent deployment map
|
||||||
|
* @param unk2 when defined, indicates type of spawn point by destination;
|
||||||
|
* 0 is unknown (may refer to all available spawns regardless of last position);
|
||||||
|
* 6 is towers;
|
||||||
|
* 7 is facilities
|
||||||
|
* @param unk3 na
|
||||||
|
* @param unk4 na
|
||||||
|
* @param unk5 when defined, the continent number
|
||||||
|
*/
|
||||||
final case class SpawnRequestMessage(unk1 : Int,
|
final case class SpawnRequestMessage(unk1 : Int,
|
||||||
unk2 : Long,
|
unk2 : Long,
|
||||||
unk3 : Int,
|
unk3 : Int,
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ final case class Vector3(x : Float,
|
||||||
y : Float,
|
y : Float,
|
||||||
z : Float) {
|
z : Float) {
|
||||||
/**
|
/**
|
||||||
* Operator override for vector addition, treating `Vector3` objects as actual mathematical vectors.
|
* Operator for vector addition, treating `Vector3` objects as actual mathematical vectors.
|
||||||
* The application of this overload is "vector1 + vector2."
|
* The application of this definition is "vector1 + vector2."
|
||||||
* @param vec the other `Vector3` object
|
* @param vec the other `Vector3` object
|
||||||
* @return a new `Vector3` object with the summed values
|
* @return a new `Vector3` object with the summed values
|
||||||
*/
|
*/
|
||||||
|
|
@ -19,8 +19,8 @@ final case class Vector3(x : Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Operator override for vector subtraction, treating `Vector3` objects as actual mathematical vectors.
|
* Operator for vector subtraction, treating `Vector3` objects as actual mathematical vectors.
|
||||||
* The application of this overload is "vector1 - vector2."
|
* The application of this definition is "vector1 - vector2."
|
||||||
* @param vec the other `Vector3` object
|
* @param vec the other `Vector3` object
|
||||||
* @return a new `Vector3` object with the difference values
|
* @return a new `Vector3` object with the difference values
|
||||||
*/
|
*/
|
||||||
|
|
@ -29,7 +29,7 @@ final case class Vector3(x : Float,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Operator override for vector scaling, treating `Vector3` objects as actual mathematical vectors.
|
* Operator for vector scaling, treating `Vector3` objects as actual mathematical vectors.
|
||||||
* The application of this overload is "vector * scalar" exclusively.
|
* The application of this overload is "vector * scalar" exclusively.
|
||||||
* "scalar * vector" is invalid.
|
* "scalar * vector" is invalid.
|
||||||
* @param scalar the value to multiply this vector
|
* @param scalar the value to multiply this vector
|
||||||
|
|
@ -38,6 +38,14 @@ final case class Vector3(x : Float,
|
||||||
def *(scalar : Float) : Vector3 = {
|
def *(scalar : Float) : Vector3 = {
|
||||||
Vector3(x*scalar, y*scalar, z*scalar)
|
Vector3(x*scalar, y*scalar, z*scalar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operator for returning the ground-planar coordinates
|
||||||
|
* and ignoring the perpendicular distance from the world floor.
|
||||||
|
* The application of this definition is "vector.xy" or "vector xy."
|
||||||
|
* @return a new `Vector3` object with only two of the components of the original
|
||||||
|
*/
|
||||||
|
def xy : Vector3 = Vector3(x, y, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
object Vector3 {
|
object Vector3 {
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,11 @@ class Vector3Test extends Specification {
|
||||||
vec * 3f mustEqual Vector3(3.8999999f, -7.7999997f, 11.700001f)
|
vec * 3f mustEqual Vector3(3.8999999f, -7.7999997f, 11.700001f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"separate into x-component and y-component only" in {
|
||||||
|
val obj = Vector3(1.1f, 2.2f, 3.3f)
|
||||||
|
obj.xy mustEqual Vector3(1.1f, 2.2f, 0f)
|
||||||
|
}
|
||||||
|
|
||||||
"calculate the unit vector (zero)" in {
|
"calculate the unit vector (zero)" in {
|
||||||
Vector3.Unit(Vector3.Zero) mustEqual Vector3(0,0,0)
|
Vector3.Unit(Vector3.Zero) mustEqual Vector3(0,0,0)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,12 @@ package game
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
import net.psforever.packet._
|
import net.psforever.packet._
|
||||||
import net.psforever.packet.game._
|
import net.psforever.packet.game._
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||||
import scodec.bits._
|
import scodec.bits._
|
||||||
|
|
||||||
class AvatarDeadStateMessageTest extends Specification {
|
class AvatarDeadStateMessageTest extends Specification {
|
||||||
val string = hex"ad3c1260801c12608009f99861fb0741e040000010"
|
val string = hex"ad3c1260801c12608009f99861fb0741e040000010"
|
||||||
|
val string_invalid = hex"ad3c1260801c12608009f99861fb0741e0400000F0"
|
||||||
|
|
||||||
"decode" in {
|
"decode" in {
|
||||||
PacketCoding.DecodePacket(string).require match {
|
PacketCoding.DecodePacket(string).require match {
|
||||||
|
|
@ -17,15 +18,19 @@ class AvatarDeadStateMessageTest extends Specification {
|
||||||
unk2 mustEqual 300000
|
unk2 mustEqual 300000
|
||||||
unk3 mustEqual 300000
|
unk3 mustEqual 300000
|
||||||
pos mustEqual Vector3(6552.617f,4602.375f,60.90625f)
|
pos mustEqual Vector3(6552.617f,4602.375f,60.90625f)
|
||||||
unk4 mustEqual 2
|
unk4 mustEqual PlanetSideEmpire.VS
|
||||||
unk5 mustEqual true
|
unk5 mustEqual true
|
||||||
case _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"decode (failure)" in {
|
||||||
|
PacketCoding.DecodePacket(string_invalid).isFailure mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
"encode" in {
|
"encode" in {
|
||||||
val msg = AvatarDeadStateMessage(DeadState.Dead, 300000, 300000, Vector3(6552.617f,4602.375f,60.90625f), 2, true)
|
val msg = AvatarDeadStateMessage(DeadState.Dead, 300000, 300000, Vector3(6552.617f,4602.375f,60.90625f), PlanetSideEmpire.VS, true)
|
||||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||||
|
|
||||||
pkt mustEqual string
|
pkt mustEqual string
|
||||||
|
|
|
||||||
|
|
@ -26,4 +26,8 @@ class DisconnectMessageTest extends Specification {
|
||||||
|
|
||||||
pkt mustEqual string
|
pkt mustEqual string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"comparison" in {
|
||||||
|
DisconnectMessage("First") mustEqual DisconnectMessage("First", "", "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
397
common/src/test/scala/objects/AvatarTest.scala
Normal file
397
common/src/test/scala/objects/AvatarTest.scala
Normal file
|
|
@ -0,0 +1,397 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package objects
|
||||||
|
|
||||||
|
import net.psforever.objects.GlobalDefinitions._
|
||||||
|
import net.psforever.objects._
|
||||||
|
import net.psforever.objects.definition.ImplantDefinition
|
||||||
|
import net.psforever.types.{CharacterGender, ImplantType, PlanetSideEmpire}
|
||||||
|
import org.specs2.mutable._
|
||||||
|
|
||||||
|
class AvatarTest extends Specification {
|
||||||
|
def CreatePlayer() : (Player, Avatar) = {
|
||||||
|
val avatar = Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1)
|
||||||
|
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("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
av.name mustEqual "Chord"
|
||||||
|
av.faction mustEqual PlanetSideEmpire.TR
|
||||||
|
av.sex mustEqual CharacterGender.Male
|
||||||
|
av.head mustEqual 0
|
||||||
|
av.voice mustEqual 5
|
||||||
|
av.BEP mustEqual 0
|
||||||
|
av.CEP mustEqual 0
|
||||||
|
av.Certifications mustEqual Set.empty
|
||||||
|
av.Definition.ObjectId mustEqual 121
|
||||||
|
}
|
||||||
|
|
||||||
|
"can maintain cumulative battle experience point values" in {
|
||||||
|
val av = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
av.BEP mustEqual 0
|
||||||
|
av.BEP = 100
|
||||||
|
av.BEP mustEqual 100
|
||||||
|
av.BEP = 700
|
||||||
|
av.BEP mustEqual 700
|
||||||
|
}
|
||||||
|
|
||||||
|
"can maintain battle experience point values up to a maximum (Long.MaxValue)" in {
|
||||||
|
val av = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
av.BEP mustEqual 0
|
||||||
|
av.BEP = 4294967295L
|
||||||
|
av.BEP mustEqual 4294967295L
|
||||||
|
}
|
||||||
|
|
||||||
|
"can not maintain battle experience point values below zero" in {
|
||||||
|
val av = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
av.BEP mustEqual 0
|
||||||
|
av.BEP = -1
|
||||||
|
av.BEP mustEqual 0
|
||||||
|
av.BEP = 100
|
||||||
|
av.BEP mustEqual 100
|
||||||
|
av.BEP = -1
|
||||||
|
av.BEP mustEqual 0
|
||||||
|
}
|
||||||
|
|
||||||
|
"can maintain cumulative command experience point values" in {
|
||||||
|
val av = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
av.CEP mustEqual 0
|
||||||
|
av.CEP = 100
|
||||||
|
av.CEP mustEqual 100
|
||||||
|
av.CEP = 700
|
||||||
|
av.CEP mustEqual 700
|
||||||
|
}
|
||||||
|
|
||||||
|
"can maintain command experience point values up to a maximum (Long.MaxValue)" in {
|
||||||
|
val av = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
av.CEP mustEqual 0
|
||||||
|
av.CEP = 4294967295L
|
||||||
|
av.CEP mustEqual 4294967295L
|
||||||
|
}
|
||||||
|
|
||||||
|
"can not maintain command experience point values below zero" in {
|
||||||
|
val av = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
av.CEP mustEqual 0
|
||||||
|
av.CEP = -1
|
||||||
|
av.CEP mustEqual 0
|
||||||
|
av.CEP = 100
|
||||||
|
av.CEP mustEqual 100
|
||||||
|
av.CEP = -1
|
||||||
|
av.CEP mustEqual 0
|
||||||
|
}
|
||||||
|
|
||||||
|
"can tell the difference between avatars" in {
|
||||||
|
(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual true
|
||||||
|
|
||||||
|
(Avatar("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
Avatar("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual false
|
||||||
|
|
||||||
|
(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
Avatar("Chord", PlanetSideEmpire.NC, CharacterGender.Male, 0, 5)) mustEqual false
|
||||||
|
|
||||||
|
(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Female, 0, 5)) mustEqual false
|
||||||
|
|
||||||
|
(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 1, 5)) mustEqual false
|
||||||
|
|
||||||
|
(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 6)) mustEqual false
|
||||||
|
}
|
||||||
|
|
||||||
|
//refer to ImplantTest.scala for more tests
|
||||||
|
"maximum of three implant slots" in {
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants.length mustEqual 3
|
||||||
|
obj.Implants(0).Unlocked mustEqual false
|
||||||
|
obj.Implants(0).Initialized mustEqual false
|
||||||
|
obj.Implants(0).Active mustEqual false
|
||||||
|
obj.Implants(0).Implant mustEqual ImplantType.None
|
||||||
|
obj.Implant(0) mustEqual ImplantType.None
|
||||||
|
obj.Implants(0).Installed mustEqual None
|
||||||
|
obj.Implants(1).Unlocked mustEqual false
|
||||||
|
obj.Implants(1).Initialized mustEqual false
|
||||||
|
obj.Implants(1).Active mustEqual false
|
||||||
|
obj.Implants(1).Implant mustEqual ImplantType.None
|
||||||
|
obj.Implant(1) mustEqual ImplantType.None
|
||||||
|
obj.Implants(1).Installed mustEqual None
|
||||||
|
obj.Implants(2).Unlocked mustEqual false
|
||||||
|
obj.Implants(2).Initialized mustEqual false
|
||||||
|
obj.Implants(2).Active mustEqual false
|
||||||
|
obj.Implants(2).Implant mustEqual ImplantType.None
|
||||||
|
obj.Implant(2) mustEqual ImplantType.None
|
||||||
|
obj.Implants(2).Installed mustEqual None
|
||||||
|
|
||||||
|
obj.Implant(3) mustEqual ImplantType.None //invalid slots beyond the third always reports as ImplantType.None
|
||||||
|
}
|
||||||
|
|
||||||
|
"can install an implant" in {
|
||||||
|
val testplant : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.InstallImplant(testplant) mustEqual Some(0)
|
||||||
|
obj.Implants.find({p => p.Implant == ImplantType(1)}) match { //find the installed implant
|
||||||
|
case Some(slot) =>
|
||||||
|
slot.Installed mustEqual Some(testplant)
|
||||||
|
case _ =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
ok
|
||||||
|
}
|
||||||
|
|
||||||
|
"can install implants in sequential slots" in {
|
||||||
|
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val testplant2 : ImplantDefinition = ImplantDefinition(2)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.Implants(1).Unlocked = true
|
||||||
|
|
||||||
|
obj.InstallImplant(testplant1) mustEqual Some(0)
|
||||||
|
obj.InstallImplant(testplant2) mustEqual Some(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
"can not install the same type of implant twice" in {
|
||||||
|
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val testplant2 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.Implants(1).Unlocked = true
|
||||||
|
|
||||||
|
obj.InstallImplant(testplant1) mustEqual Some(0)
|
||||||
|
obj.InstallImplant(testplant2) mustEqual None
|
||||||
|
}
|
||||||
|
|
||||||
|
"can not install more implants than slots available (two unlocked)" in {
|
||||||
|
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val testplant2 : ImplantDefinition = ImplantDefinition(2)
|
||||||
|
val testplant3 : ImplantDefinition = ImplantDefinition(3)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.Implants(1).Unlocked = true
|
||||||
|
|
||||||
|
obj.InstallImplant(testplant1) mustEqual Some(0)
|
||||||
|
obj.InstallImplant(testplant2) mustEqual Some(1)
|
||||||
|
obj.InstallImplant(testplant3) mustEqual None
|
||||||
|
}
|
||||||
|
|
||||||
|
"can not install more implants than slots available (four implants)" in {
|
||||||
|
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val testplant2 : ImplantDefinition = ImplantDefinition(2)
|
||||||
|
val testplant3 : ImplantDefinition = ImplantDefinition(3)
|
||||||
|
val testplant4 : ImplantDefinition = ImplantDefinition(4)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.Implants(1).Unlocked = true
|
||||||
|
obj.Implants(2).Unlocked = true
|
||||||
|
|
||||||
|
obj.InstallImplant(testplant1) mustEqual Some(0)
|
||||||
|
obj.InstallImplant(testplant2) mustEqual Some(1)
|
||||||
|
obj.InstallImplant(testplant3) mustEqual Some(2)
|
||||||
|
obj.InstallImplant(testplant4) mustEqual None
|
||||||
|
}
|
||||||
|
|
||||||
|
"can uninstall an implant" in {
|
||||||
|
val testplant : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.InstallImplant(testplant) mustEqual Some(0)
|
||||||
|
obj.Implants(0).Installed mustEqual Some(testplant)
|
||||||
|
|
||||||
|
obj.UninstallImplant(testplant.Type) mustEqual Some(0)
|
||||||
|
obj.Implants(0).Installed mustEqual None
|
||||||
|
}
|
||||||
|
|
||||||
|
"can uninstall just a specific implant" in {
|
||||||
|
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val testplant2 : ImplantDefinition = ImplantDefinition(2)
|
||||||
|
val testplant3 : ImplantDefinition = ImplantDefinition(3)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.Implants(1).Unlocked = true
|
||||||
|
obj.Implants(2).Unlocked = true
|
||||||
|
obj.InstallImplant(testplant1) mustEqual Some(0)
|
||||||
|
obj.InstallImplant(testplant2) mustEqual Some(1)
|
||||||
|
obj.InstallImplant(testplant3) mustEqual Some(2)
|
||||||
|
|
||||||
|
obj.Implant(0) mustEqual testplant1.Type
|
||||||
|
obj.Implant(1) mustEqual testplant2.Type
|
||||||
|
obj.Implant(2) mustEqual testplant3.Type
|
||||||
|
obj.UninstallImplant(testplant2.Type) mustEqual Some(1)
|
||||||
|
obj.Implant(0) mustEqual testplant1.Type
|
||||||
|
obj.Implant(1) mustEqual ImplantType.None
|
||||||
|
obj.Implant(2) mustEqual testplant3.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
"can install implants to any available slot" in {
|
||||||
|
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val testplant2 : ImplantDefinition = ImplantDefinition(2)
|
||||||
|
val testplant3 : ImplantDefinition = ImplantDefinition(3)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.Implants(1).Unlocked = true
|
||||||
|
obj.Implants(2).Unlocked = true
|
||||||
|
obj.InstallImplant(testplant1) mustEqual Some(0)
|
||||||
|
obj.InstallImplant(testplant2) mustEqual Some(1)
|
||||||
|
obj.InstallImplant(testplant3) mustEqual Some(2)
|
||||||
|
obj.UninstallImplant(testplant2.Type) mustEqual Some(1)
|
||||||
|
obj.Implant(0) mustEqual testplant1.Type
|
||||||
|
obj.Implant(1) mustEqual ImplantType.None
|
||||||
|
obj.Implant(2) mustEqual testplant3.Type
|
||||||
|
|
||||||
|
val testplant4 : ImplantDefinition = ImplantDefinition(4)
|
||||||
|
obj.InstallImplant(testplant4) mustEqual Some(1)
|
||||||
|
obj.Implant(0) mustEqual testplant1.Type
|
||||||
|
obj.Implant(1) mustEqual testplant4.Type
|
||||||
|
obj.Implant(2) mustEqual testplant3.Type
|
||||||
|
}
|
||||||
|
|
||||||
|
"can reset implants to uninitialized state" in {
|
||||||
|
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
||||||
|
val testplant2 : ImplantDefinition = ImplantDefinition(2)
|
||||||
|
val obj = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Implants(0).Unlocked = true
|
||||||
|
obj.Implants(1).Unlocked = true
|
||||||
|
obj.InstallImplant(testplant1) mustEqual Some(0)
|
||||||
|
obj.InstallImplant(testplant2) mustEqual Some(1)
|
||||||
|
obj.Implants(0).Initialized = true
|
||||||
|
obj.Implants(0).Active = true
|
||||||
|
obj.Implants(1).Initialized = true
|
||||||
|
|
||||||
|
obj.Implants(0).Initialized mustEqual true
|
||||||
|
obj.Implants(0).Active mustEqual true
|
||||||
|
obj.Implants(1).Initialized mustEqual true
|
||||||
|
obj.ResetAllImplants()
|
||||||
|
obj.Implants(0).Initialized mustEqual false
|
||||||
|
obj.Implants(0).Active mustEqual false
|
||||||
|
obj.Implants(1).Initialized mustEqual false
|
||||||
|
}
|
||||||
|
|
||||||
|
"does not have any loadout specifications by default" in {
|
||||||
|
val (_, avatar) = CreatePlayer()
|
||||||
|
(0 to 9).foreach { avatar.LoadLoadout(_) mustEqual None }
|
||||||
|
ok
|
||||||
|
}
|
||||||
|
|
||||||
|
"save player's current inventory as a loadout" in {
|
||||||
|
val (obj, avatar) = CreatePlayer()
|
||||||
|
obj.Slot(0).Equipment.get.asInstanceOf[Tool].Magazine = 1 //non-standard but legal
|
||||||
|
obj.Slot(2).Equipment.get.asInstanceOf[Tool].AmmoSlot.Magazine = 100 //non-standard (and out of range, real=25)
|
||||||
|
avatar.SaveLoadout(obj, "test", 0)
|
||||||
|
|
||||||
|
avatar.LoadLoadout(0) match {
|
||||||
|
case Some(items) =>
|
||||||
|
items.Label mustEqual "test"
|
||||||
|
items.ExoSuit mustEqual obj.ExoSuit
|
||||||
|
items.Subtype mustEqual 0
|
||||||
|
|
||||||
|
items.VisibleSlots.length mustEqual 3
|
||||||
|
val holsters = items.VisibleSlots.sortBy(_.index)
|
||||||
|
holsters.head.index mustEqual 0
|
||||||
|
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual beamer
|
||||||
|
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].ammo.head.ammo.capacity mustEqual 1 //we changed this
|
||||||
|
holsters(1).index mustEqual 2
|
||||||
|
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual suppressor
|
||||||
|
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].ammo.head.ammo.capacity mustEqual 100 //we changed this
|
||||||
|
holsters(2).index mustEqual 4
|
||||||
|
holsters(2).item.asInstanceOf[Loadout.ShorthandTool].definition mustEqual forceblade
|
||||||
|
|
||||||
|
items.Inventory.length mustEqual 6
|
||||||
|
val inventory = items.Inventory.sortBy(_.index)
|
||||||
|
inventory.head.index mustEqual 6
|
||||||
|
inventory.head.item.asInstanceOf[Loadout.ShorthandAmmoBox].definition mustEqual bullet_9mm
|
||||||
|
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.ShorthandAmmoBox].definition mustEqual bullet_9mm_AP
|
||||||
|
inventory(4).index mustEqual 36
|
||||||
|
inventory(4).item.asInstanceOf[Loadout.ShorthandAmmoBox].definition mustEqual energy_cell
|
||||||
|
inventory(5).index mustEqual 39
|
||||||
|
inventory(5).item.asInstanceOf[Loadout.ShorthandSimpleItem].definition mustEqual remote_electronics_kit
|
||||||
|
case None =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"save player's current inventory as a loadout, only found in the called-out slot number" in {
|
||||||
|
val (obj, avatar) = CreatePlayer()
|
||||||
|
avatar.SaveLoadout(obj, "test", 0)
|
||||||
|
|
||||||
|
avatar.LoadLoadout(1).isDefined mustEqual false
|
||||||
|
avatar.LoadLoadout(0).isDefined mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"try to save player's current inventory as a loadout, but will not save to an invalid slot" in {
|
||||||
|
val (obj, avatar) = CreatePlayer()
|
||||||
|
avatar.SaveLoadout(obj, "test", 10)
|
||||||
|
|
||||||
|
avatar.LoadLoadout(10) mustEqual None
|
||||||
|
}
|
||||||
|
|
||||||
|
"save player's current inventory as a loadout, without inventory contents" in {
|
||||||
|
val (obj, avatar) = CreatePlayer()
|
||||||
|
obj.Inventory.Clear()
|
||||||
|
avatar.SaveLoadout(obj, "test", 0)
|
||||||
|
|
||||||
|
avatar.LoadLoadout(0) match {
|
||||||
|
case Some(items) =>
|
||||||
|
items.Label mustEqual "test"
|
||||||
|
items.ExoSuit mustEqual obj.ExoSuit
|
||||||
|
items.Subtype mustEqual 0
|
||||||
|
items.VisibleSlots.length mustEqual 3
|
||||||
|
items.Inventory.length mustEqual 0 //empty
|
||||||
|
case None =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"save player's current inventory as a loadout, without visible slot contents" in {
|
||||||
|
val (obj, avatar) = CreatePlayer()
|
||||||
|
obj.Slot(0).Equipment = None
|
||||||
|
obj.Slot(2).Equipment = None
|
||||||
|
obj.Slot(4).Equipment = None
|
||||||
|
avatar.SaveLoadout(obj, "test", 0)
|
||||||
|
|
||||||
|
avatar.LoadLoadout(0) match {
|
||||||
|
case Some(items) =>
|
||||||
|
items.Label mustEqual "test"
|
||||||
|
items.ExoSuit mustEqual obj.ExoSuit
|
||||||
|
items.Subtype mustEqual 0
|
||||||
|
items.VisibleSlots.length mustEqual 0 //empty
|
||||||
|
items.Inventory.length mustEqual 6
|
||||||
|
case None =>
|
||||||
|
ko
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"save, load, delete; rapidly" in {
|
||||||
|
val (obj, avatar) = CreatePlayer()
|
||||||
|
avatar.SaveLoadout(obj, "test", 0)
|
||||||
|
|
||||||
|
avatar.LoadLoadout(0).isDefined mustEqual true
|
||||||
|
avatar.DeleteLoadout(0)
|
||||||
|
avatar.LoadLoadout(0) mustEqual None
|
||||||
|
}
|
||||||
|
|
||||||
|
"the fifth slot is the locker wrapped in an EquipmentSlot" in {
|
||||||
|
val (_, avatar) = CreatePlayer()
|
||||||
|
avatar.FifthSlot.Equipment.contains(avatar.Locker)
|
||||||
|
}
|
||||||
|
|
||||||
|
"toString" in {
|
||||||
|
Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5).toString mustEqual "TR Chord"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,7 +6,7 @@ import net.psforever.objects.GlobalDefinitions
|
||||||
import net.psforever.objects.definition.ObjectDefinition
|
import net.psforever.objects.definition.ObjectDefinition
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
|
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
|
||||||
import net.psforever.objects.serverobject.structures.{Amenity, Building, BuildingControl, WarpGate}
|
import net.psforever.objects.serverobject.structures._
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
@ -27,7 +27,7 @@ class AmenityTest extends Specification {
|
||||||
|
|
||||||
"can be owned by a building" in {
|
"can be owned by a building" in {
|
||||||
val ao = new AmenityObject()
|
val ao = new AmenityObject()
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
|
|
||||||
ao.Owner = bldg
|
ao.Owner = bldg
|
||||||
ao.Owner mustEqual bldg
|
ao.Owner mustEqual bldg
|
||||||
|
|
@ -51,7 +51,7 @@ class AmenityTest extends Specification {
|
||||||
"confer faction allegiance through ownership" in {
|
"confer faction allegiance through ownership" in {
|
||||||
//see FactionAffinityTest
|
//see FactionAffinityTest
|
||||||
val ao = new AmenityObject()
|
val ao = new AmenityObject()
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
ao.Owner = bldg
|
ao.Owner = bldg
|
||||||
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
||||||
ao.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
ao.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
||||||
|
|
@ -66,7 +66,7 @@ class AmenityTest extends Specification {
|
||||||
class BuildingTest extends Specification {
|
class BuildingTest extends Specification {
|
||||||
"Building" should {
|
"Building" should {
|
||||||
"construct" in {
|
"construct" in {
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
bldg.Id mustEqual 10
|
bldg.Id mustEqual 10
|
||||||
bldg.Actor mustEqual ActorRef.noSender
|
bldg.Actor mustEqual ActorRef.noSender
|
||||||
bldg.Amenities mustEqual Nil
|
bldg.Amenities mustEqual Nil
|
||||||
|
|
@ -75,7 +75,7 @@ class BuildingTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"change faction affinity" in {
|
"change faction affinity" in {
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
bldg.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
||||||
|
|
||||||
bldg.Faction = PlanetSideEmpire.TR
|
bldg.Faction = PlanetSideEmpire.TR
|
||||||
|
|
@ -83,7 +83,7 @@ class BuildingTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"keep track of amenities" in {
|
"keep track of amenities" in {
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
val door1 = Door(GlobalDefinitions.door)
|
val door1 = Door(GlobalDefinitions.door)
|
||||||
val door2 = Door(GlobalDefinitions.door)
|
val door2 = Door(GlobalDefinitions.door)
|
||||||
|
|
||||||
|
|
@ -114,7 +114,7 @@ class WarpGateTest extends Specification {
|
||||||
class BuildingControl1Test extends ActorTest {
|
class BuildingControl1Test extends ActorTest {
|
||||||
"Building Control" should {
|
"Building Control" should {
|
||||||
"construct" in {
|
"construct" in {
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||||
assert(bldg.Actor != ActorRef.noSender)
|
assert(bldg.Actor != ActorRef.noSender)
|
||||||
}
|
}
|
||||||
|
|
@ -124,7 +124,7 @@ class BuildingControl1Test extends ActorTest {
|
||||||
class BuildingControl2Test extends ActorTest {
|
class BuildingControl2Test extends ActorTest {
|
||||||
"Building Control" should {
|
"Building Control" should {
|
||||||
"convert and assert faction affinity on convert request" in {
|
"convert and assert faction affinity on convert request" in {
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
bldg.Faction = PlanetSideEmpire.TR
|
bldg.Faction = PlanetSideEmpire.TR
|
||||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||||
|
|
@ -142,7 +142,7 @@ class BuildingControl2Test extends ActorTest {
|
||||||
class BuildingControl3Test extends ActorTest {
|
class BuildingControl3Test extends ActorTest {
|
||||||
"Building Control" should {
|
"Building Control" should {
|
||||||
"convert and assert faction affinity on convert request, and for each of its amenities" in {
|
"convert and assert faction affinity on convert request, and for each of its amenities" in {
|
||||||
val bldg = Building(10, Zone.Nowhere)
|
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||||
bldg.Faction = PlanetSideEmpire.TR
|
bldg.Faction = PlanetSideEmpire.TR
|
||||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "building-test")
|
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "building-test")
|
||||||
val door1 = Door(GlobalDefinitions.door)
|
val door1 = Door(GlobalDefinitions.door)
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,7 @@ class ConverterTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"Player" should {
|
"Player" should {
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
val obj : Player = {
|
val obj : Player = {
|
||||||
/*
|
/*
|
||||||
Create an AmmoBoxDefinition with which to build two AmmoBoxes
|
Create an AmmoBoxDefinition with which to build two AmmoBoxes
|
||||||
|
|
@ -171,7 +172,7 @@ class ConverterTest extends Specification {
|
||||||
val tool = Tool(tdef)
|
val tool = Tool(tdef)
|
||||||
tool.GUID = PlanetSideGUID(92)
|
tool.GUID = PlanetSideGUID(92)
|
||||||
tool.AmmoSlot.Box.GUID = PlanetSideGUID(90)
|
tool.AmmoSlot.Box.GUID = PlanetSideGUID(90)
|
||||||
val obj = Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = Player(avatar)
|
||||||
obj.GUID = PlanetSideGUID(93)
|
obj.GUID = PlanetSideGUID(93)
|
||||||
obj.Slot(2).Equipment = tool
|
obj.Slot(2).Equipment = tool
|
||||||
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(94)
|
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(94)
|
||||||
|
|
@ -182,7 +183,7 @@ class ConverterTest extends Specification {
|
||||||
val converter = new CharacterSelectConverter
|
val converter = new CharacterSelectConverter
|
||||||
|
|
||||||
"convert to packet (BR < 24)" in {
|
"convert to packet (BR < 24)" in {
|
||||||
obj.BEP = 0
|
avatar.BEP = 0
|
||||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
ok
|
ok
|
||||||
|
|
@ -198,7 +199,7 @@ class ConverterTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"convert to packet (BR >= 24)" in {
|
"convert to packet (BR >= 24)" in {
|
||||||
obj.BEP = 10000000
|
avatar.BEP = 10000000
|
||||||
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
obj.Definition.Packet.DetailedConstructorData(obj) match {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
ok
|
ok
|
||||||
|
|
@ -214,7 +215,7 @@ class ConverterTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"convert to simple packet (BR < 24)" in {
|
"convert to simple packet (BR < 24)" in {
|
||||||
obj.BEP = 0
|
avatar.BEP = 0
|
||||||
converter.DetailedConstructorData(obj) match {
|
converter.DetailedConstructorData(obj) match {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
ok
|
ok
|
||||||
|
|
@ -226,7 +227,7 @@ class ConverterTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"convert to simple packet (BR >= 24)" in {
|
"convert to simple packet (BR >= 24)" in {
|
||||||
obj.BEP = 10000000
|
avatar.BEP = 10000000
|
||||||
converter.DetailedConstructorData(obj) match {
|
converter.DetailedConstructorData(obj) match {
|
||||||
case Success(_) =>
|
case Success(_) =>
|
||||||
ok
|
ok
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
|
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{PlanetSideGUID, UseItemMessage}
|
import net.psforever.packet.game.{PlanetSideGUID, UseItemMessage}
|
||||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
||||||
|
|
@ -13,7 +13,7 @@ import org.specs2.mutable.Specification
|
||||||
import scala.concurrent.duration.Duration
|
import scala.concurrent.duration.Duration
|
||||||
|
|
||||||
class DoorTest extends Specification {
|
class DoorTest extends Specification {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
|
|
||||||
"Door" should {
|
"Door" should {
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
@ -121,8 +121,8 @@ object DoorControlTest {
|
||||||
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, Door) = {
|
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, Door) = {
|
||||||
val door = Door(GlobalDefinitions.door)
|
val door = Door(GlobalDefinitions.door)
|
||||||
door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door")
|
door.Actor = system.actorOf(Props(classOf[DoorControl], door), "door")
|
||||||
door.Owner = new Building(0, Zone.Nowhere)
|
door.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
door.Owner.Faction = faction
|
door.Owner.Faction = faction
|
||||||
(Player("test", faction, CharacterGender.Male, 0, 0), door)
|
(Player(Avatar("test", faction, CharacterGender.Male, 0, 0)), door)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import akka.actor.{Actor, ActorSystem, Props}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||||
import net.psforever.objects.serverobject.doors.Door
|
import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
@ -42,7 +42,7 @@ class FactionAffinityTest extends Specification {
|
||||||
|
|
||||||
"inherits affinity from owner 2" in {
|
"inherits affinity from owner 2" in {
|
||||||
val obj = new Door(GlobalDefinitions.door)
|
val obj = new Door(GlobalDefinitions.door)
|
||||||
val bldg = new Building(1, Zone.Nowhere)
|
val bldg = new Building(1, Zone.Nowhere, StructureType.Building)
|
||||||
obj.Owner = bldg
|
obj.Owner = bldg
|
||||||
obj.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
obj.Faction mustEqual PlanetSideEmpire.NEUTRAL
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@ package objects
|
||||||
|
|
||||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||||
import net.psforever.objects.serverobject.CommonMessages
|
import net.psforever.objects.serverobject.CommonMessages
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.serverobject.locks.{IFFLock, IFFLockControl}
|
import net.psforever.objects.serverobject.locks.{IFFLock, IFFLockControl}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
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.zones.Zone
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
||||||
|
|
@ -68,8 +67,8 @@ object IFFLockControlTest {
|
||||||
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, IFFLock) = {
|
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, IFFLock) = {
|
||||||
val lock = IFFLock(GlobalDefinitions.lock_external)
|
val lock = IFFLock(GlobalDefinitions.lock_external)
|
||||||
lock.Actor = system.actorOf(Props(classOf[IFFLockControl], lock), "lock-control")
|
lock.Actor = system.actorOf(Props(classOf[IFFLockControl], lock), "lock-control")
|
||||||
lock.Owner = new Building(0, Zone.Nowhere)
|
lock.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
lock.Owner.Faction = faction
|
lock.Owner.Faction = faction
|
||||||
(Player("test", faction, CharacterGender.Male, 0, 0), lock)
|
(Player(Avatar("test", faction, CharacterGender.Male, 0, 0)), lock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,193 +4,87 @@ package objects
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire}
|
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire}
|
||||||
import net.psforever.objects.GlobalDefinitions._
|
import net.psforever.objects.GlobalDefinitions._
|
||||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize}
|
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
class LoadoutTest extends Specification {
|
class LoadoutTest extends Specification {
|
||||||
|
val avatar = Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1)
|
||||||
|
|
||||||
def CreatePlayer() : Player = {
|
def CreatePlayer() : Player = {
|
||||||
val
|
new Player(avatar) {
|
||||||
player = Player("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 41, 1)
|
Slot(0).Equipment = Tool(beamer)
|
||||||
player.Slot(0).Equipment = Tool(beamer)
|
Slot(2).Equipment = Tool(suppressor)
|
||||||
player.Slot(2).Equipment = Tool(suppressor)
|
Slot(4).Equipment = Tool(forceblade)
|
||||||
player.Slot(4).Equipment = Tool(forceblade)
|
Slot(6).Equipment = ConstructionItem(ace)
|
||||||
player.Slot(6).Equipment = AmmoBox(bullet_9mm)
|
Slot(9).Equipment = AmmoBox(bullet_9mm)
|
||||||
player.Slot(9).Equipment = AmmoBox(bullet_9mm)
|
Slot(12).Equipment = AmmoBox(bullet_9mm)
|
||||||
player.Slot(12).Equipment = AmmoBox(bullet_9mm)
|
Slot(33).Equipment = Kit(medkit)
|
||||||
player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
|
Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
||||||
player.Slot(36).Equipment = AmmoBox(energy_cell)
|
}
|
||||||
player.Slot(39).Equipment = SimpleItem(remote_electronics_kit)
|
|
||||||
player
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"Player Loadout" should {
|
"test sample player" in {
|
||||||
"test sample player" in {
|
val player = CreatePlayer()
|
||||||
val obj : Player = CreatePlayer()
|
player.Holsters()(0).Equipment.get.Definition mustEqual beamer
|
||||||
obj.Holsters()(0).Equipment.get.Definition mustEqual beamer
|
player.Holsters()(2).Equipment.get.Definition mustEqual suppressor
|
||||||
obj.Holsters()(2).Equipment.get.Definition mustEqual suppressor
|
player.Holsters()(4).Equipment.get.Definition mustEqual forceblade
|
||||||
obj.Holsters()(4).Equipment.get.Definition mustEqual forceblade
|
player.Slot(6).Equipment.get.Definition mustEqual ace
|
||||||
obj.Slot(6).Equipment.get.Definition mustEqual bullet_9mm
|
player.Slot(9).Equipment.get.Definition mustEqual bullet_9mm
|
||||||
obj.Slot(9).Equipment.get.Definition mustEqual bullet_9mm
|
player.Slot(12).Equipment.get.Definition mustEqual bullet_9mm
|
||||||
obj.Slot(12).Equipment.get.Definition mustEqual bullet_9mm
|
player.Slot(33).Equipment.get.Definition mustEqual medkit
|
||||||
obj.Slot(33).Equipment.get.Definition mustEqual bullet_9mm_AP
|
player.Slot(39).Equipment.get.Definition mustEqual remote_electronics_kit
|
||||||
obj.Slot(36).Equipment.get.Definition mustEqual energy_cell
|
}
|
||||||
obj.Slot(39).Equipment.get.Definition mustEqual remote_electronics_kit
|
|
||||||
}
|
|
||||||
|
|
||||||
"do not load, if never saved" in {
|
"create a loadout that contains a player's inventory" in {
|
||||||
CreatePlayer().LoadLoadout(0) mustEqual None
|
val player = CreatePlayer()
|
||||||
}
|
val obj = Loadout.Create(player, "test")
|
||||||
|
|
||||||
"save but incorrect load" in {
|
obj.Label mustEqual "test"
|
||||||
val obj : Player = CreatePlayer()
|
obj.ExoSuit mustEqual obj.ExoSuit
|
||||||
obj.SaveLoadout("test", 0)
|
obj.Subtype mustEqual 0
|
||||||
|
|
||||||
obj.LoadLoadout(1) mustEqual None
|
obj.VisibleSlots.length mustEqual 3
|
||||||
}
|
val holsters = obj.VisibleSlots.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
|
||||||
|
|
||||||
"save and load" in {
|
obj.Inventory.length mustEqual 5
|
||||||
val obj : Player = CreatePlayer()
|
val inventory = obj.Inventory.sortBy(_.index)
|
||||||
obj.Slot(0).Equipment.get.asInstanceOf[Tool].Magazine = 1 //non-standard but legal
|
inventory.head.index mustEqual 6
|
||||||
obj.Slot(2).Equipment.get.asInstanceOf[Tool].AmmoSlot.Magazine = 100 //non-standard (and out of range, real=25)
|
inventory.head.item.asInstanceOf[Loadout.ShorthandConstructionItem].definition mustEqual ace
|
||||||
obj.SaveLoadout("test", 0)
|
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
|
||||||
|
}
|
||||||
|
|
||||||
obj.LoadLoadout(0) match {
|
"distinguish MAX subtype information" in {
|
||||||
case Some(items) =>
|
val player = CreatePlayer()
|
||||||
items.Label mustEqual "test"
|
val slot = player.Slot(0)
|
||||||
items.ExoSuit mustEqual obj.ExoSuit
|
slot.Equipment = None //only an unequipped slot can have its Equipment Size changed (Rifle -> Max)
|
||||||
items.Subtype mustEqual 0
|
Player.SuitSetup(player, ExoSuitType.MAX)
|
||||||
|
|
||||||
items.VisibleSlots.length mustEqual 3
|
val ldout1 = Loadout.Create(player, "weaponless")
|
||||||
val holsters = items.VisibleSlots.sortBy(_.index)
|
slot.Equipment = None
|
||||||
holsters.head.index mustEqual 0
|
slot.Equipment = Tool(trhev_dualcycler)
|
||||||
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].tdef mustEqual beamer
|
val ldout2 = Loadout.Create(player, "cycler")
|
||||||
holsters.head.item.asInstanceOf[Loadout.ShorthandTool].ammo.head.ammo.capacity mustEqual 1
|
slot.Equipment = None
|
||||||
holsters(1).index mustEqual 2
|
slot.Equipment = Tool(trhev_pounder)
|
||||||
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].tdef mustEqual suppressor
|
val ldout3 = Loadout.Create(player, "pounder")
|
||||||
holsters(1).item.asInstanceOf[Loadout.ShorthandTool].ammo.head.ammo.capacity mustEqual 100
|
slot.Equipment = None
|
||||||
holsters(2).index mustEqual 4
|
slot.Equipment = Tool(trhev_burster)
|
||||||
holsters(2).item.asInstanceOf[Loadout.ShorthandTool].tdef mustEqual forceblade
|
val ldout4 = Loadout.Create(player, "burster")
|
||||||
|
|
||||||
items.Inventory.length mustEqual 6
|
ldout1.Subtype mustEqual 0
|
||||||
val inventory = items.Inventory.sortBy(_.index)
|
ldout2.Subtype mustEqual 1
|
||||||
inventory.head.index mustEqual 6
|
ldout3.Subtype mustEqual 2
|
||||||
inventory.head.item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm
|
ldout4.Subtype mustEqual 3
|
||||||
inventory(1).index mustEqual 9
|
|
||||||
inventory(1).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm
|
|
||||||
inventory(2).index mustEqual 12
|
|
||||||
inventory(2).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm
|
|
||||||
inventory(3).index mustEqual 33
|
|
||||||
inventory(3).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual bullet_9mm_AP
|
|
||||||
inventory(4).index mustEqual 36
|
|
||||||
inventory(4).item.asInstanceOf[Loadout.ShorthandAmmoBox].adef mustEqual energy_cell
|
|
||||||
inventory(5).index mustEqual 39
|
|
||||||
inventory(5).item.asInstanceOf[Loadout.ShorthandSimpleItem].sdef mustEqual remote_electronics_kit
|
|
||||||
case None =>
|
|
||||||
ko
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"save without inventory contents" in {
|
|
||||||
val obj : Player = CreatePlayer()
|
|
||||||
obj.Inventory.Clear()
|
|
||||||
obj.SaveLoadout("test", 0)
|
|
||||||
|
|
||||||
obj.LoadLoadout(0) match {
|
|
||||||
case Some(items) =>
|
|
||||||
items.Label mustEqual "test"
|
|
||||||
items.ExoSuit mustEqual obj.ExoSuit
|
|
||||||
items.Subtype mustEqual 0
|
|
||||||
items.VisibleSlots.length mustEqual 3
|
|
||||||
items.Inventory.length mustEqual 0 //empty
|
|
||||||
case None =>
|
|
||||||
ko
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"save without visible slot contents" in {
|
|
||||||
val obj : Player = CreatePlayer()
|
|
||||||
obj.Slot(0).Equipment = None
|
|
||||||
obj.Slot(2).Equipment = None
|
|
||||||
obj.Slot(4).Equipment = None
|
|
||||||
obj.SaveLoadout("test", 0)
|
|
||||||
|
|
||||||
obj.LoadLoadout(0) match {
|
|
||||||
case Some(items) =>
|
|
||||||
items.Label mustEqual "test"
|
|
||||||
items.ExoSuit mustEqual obj.ExoSuit
|
|
||||||
items.Subtype mustEqual 0
|
|
||||||
items.VisibleSlots.length mustEqual 0 //empty
|
|
||||||
items.Inventory.length mustEqual 6
|
|
||||||
case None =>
|
|
||||||
ko
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"save (a construction item) and load" in {
|
|
||||||
val obj : Player = CreatePlayer()
|
|
||||||
obj.Inventory.Clear()
|
|
||||||
obj.Slot(6).Equipment = ConstructionItem(advanced_ace)
|
|
||||||
obj.SaveLoadout("test", 0)
|
|
||||||
|
|
||||||
obj.LoadLoadout(0) match {
|
|
||||||
case Some(items) =>
|
|
||||||
items.Inventory.length mustEqual 1
|
|
||||||
items.Inventory.head.index mustEqual 6
|
|
||||||
items.Inventory.head.item.asInstanceOf[Loadout.ShorthandConstructionItem].cdef mustEqual advanced_ace
|
|
||||||
case None =>
|
|
||||||
ko
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"save (a kit) and load" in {
|
|
||||||
val obj : Player = CreatePlayer()
|
|
||||||
obj.Inventory.Clear()
|
|
||||||
obj.Slot(6).Equipment = Kit(medkit)
|
|
||||||
obj.SaveLoadout("test", 0)
|
|
||||||
|
|
||||||
obj.LoadLoadout(0) match {
|
|
||||||
case Some(items) =>
|
|
||||||
items.Inventory.length mustEqual 1
|
|
||||||
items.Inventory.head.index mustEqual 6
|
|
||||||
items.Inventory.head.item.asInstanceOf[Loadout.ShorthandKit].kdef mustEqual medkit
|
|
||||||
case None =>
|
|
||||||
ko
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
"save, load, delete" in {
|
|
||||||
val obj : Player = CreatePlayer()
|
|
||||||
obj.SaveLoadout("test", 0)
|
|
||||||
|
|
||||||
obj.LoadLoadout(0) match {
|
|
||||||
case None =>
|
|
||||||
ko
|
|
||||||
case Some(_) => ; //good; keep going
|
|
||||||
}
|
|
||||||
obj.DeleteLoadout(0)
|
|
||||||
obj.LoadLoadout(0) mustEqual None
|
|
||||||
}
|
|
||||||
|
|
||||||
"distinguish MAX subtype information" in {
|
|
||||||
val obj : Player = CreatePlayer()
|
|
||||||
val slot = obj.Slot(0)
|
|
||||||
slot.Equipment = None //only an unequipped slot can have its Equipment Size changed (Rifle -> Max)
|
|
||||||
Player.SuitSetup(obj, ExoSuitType.MAX)
|
|
||||||
obj.SaveLoadout("generic", 0) //weaponless
|
|
||||||
slot.Equipment = None
|
|
||||||
slot.Equipment = Tool(trhev_dualcycler)
|
|
||||||
obj.SaveLoadout("cycler", 1)
|
|
||||||
slot.Equipment = None
|
|
||||||
slot.Equipment = Tool(trhev_pounder)
|
|
||||||
obj.SaveLoadout("pounder", 2)
|
|
||||||
slot.Equipment = None
|
|
||||||
slot.Equipment = Tool(trhev_burster)
|
|
||||||
obj.SaveLoadout("burster", 3)
|
|
||||||
|
|
||||||
obj.LoadLoadout(0).get.Subtype mustEqual 0
|
|
||||||
obj.LoadLoadout(1).get.Subtype mustEqual 1
|
|
||||||
obj.LoadLoadout(2).get.Subtype mustEqual 2
|
|
||||||
obj.LoadLoadout(3).get.Subtype mustEqual 3
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.{Actor, ActorRef, Props}
|
import akka.actor.{Actor, ActorRef, Props}
|
||||||
import net.psforever.objects.Player
|
import net.psforever.objects.{Avatar, Player}
|
||||||
import net.psforever.objects.definition.{ObjectDefinition, SeatDefinition}
|
import net.psforever.objects.definition.{ObjectDefinition, SeatDefinition}
|
||||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||||
|
|
@ -25,7 +25,7 @@ class MountableControl1Test extends ActorTest() {
|
||||||
class MountableControl2Test extends ActorTest() {
|
class MountableControl2Test extends ActorTest() {
|
||||||
"MountableControl" should {
|
"MountableControl" should {
|
||||||
"let a player mount" in {
|
"let a player mount" in {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val obj = new MountableTest.MountableTestObject
|
val obj = new MountableTest.MountableTestObject
|
||||||
obj.Actor = system.actorOf(Props(classOf[MountableTest.MountableTestControl], obj), "mountable")
|
obj.Actor = system.actorOf(Props(classOf[MountableTest.MountableTestControl], obj), "mountable")
|
||||||
val msg = Mountable.TryMount(player, 0)
|
val msg = Mountable.TryMount(player, 0)
|
||||||
|
|
@ -46,8 +46,8 @@ class MountableControl2Test extends ActorTest() {
|
||||||
class MountableControl3Test extends ActorTest() {
|
class MountableControl3Test extends ActorTest() {
|
||||||
"MountableControl" should {
|
"MountableControl" should {
|
||||||
"block a player from mounting" in {
|
"block a player from mounting" in {
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(Avatar("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(Avatar("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val obj = new MountableTest.MountableTestObject
|
val obj = new MountableTest.MountableTestObject
|
||||||
obj.Actor = system.actorOf(Props(classOf[MountableTest.MountableTestControl], obj), "mountable")
|
obj.Actor = system.actorOf(Props(classOf[MountableTest.MountableTestControl], obj), "mountable")
|
||||||
obj.Actor ! Mountable.TryMount(player1, 0)
|
obj.Actor ! Mountable.TryMount(player1, 0)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
|
import net.psforever.objects.GlobalDefinitions._
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.definition.{ImplantDefinition, SimpleItemDefinition}
|
import net.psforever.objects.definition.{ImplantDefinition, SimpleItemDefinition}
|
||||||
import net.psforever.objects.equipment.EquipmentSize
|
import net.psforever.objects.equipment.EquipmentSize
|
||||||
|
|
@ -8,38 +9,53 @@ import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types.{CharacterGender, ExoSuitType, ImplantType, PlanetSideEmpire}
|
import net.psforever.types.{CharacterGender, ExoSuitType, ImplantType, PlanetSideEmpire}
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
|
import scala.util.Success
|
||||||
|
|
||||||
class PlayerTest extends Specification {
|
class PlayerTest extends Specification {
|
||||||
|
def TestPlayer(name : String, faction : PlanetSideEmpire.Value, sex : CharacterGender.Value, head : Int, voice : Int) : Player = {
|
||||||
|
new Player(Avatar(name, faction, sex, head, voice))
|
||||||
|
}
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.isAlive mustEqual false
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
"different players" in {
|
"different players" in {
|
||||||
(Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
(TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual true
|
TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual true
|
||||||
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
|
||||||
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual false
|
|
||||||
(Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
|
||||||
Player("Chord", PlanetSideEmpire.NC, CharacterGender.Male, 0, 5)) mustEqual false
|
|
||||||
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
|
||||||
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Female, 0, 5)) mustEqual false
|
|
||||||
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
|
||||||
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 1, 5)) mustEqual false
|
|
||||||
(Player("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
|
||||||
Player("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 6)) mustEqual false
|
|
||||||
}
|
|
||||||
|
|
||||||
"become a backpack" in {
|
(TestPlayer("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
TestPlayer("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)) mustEqual false
|
||||||
obj.isAlive mustEqual false
|
|
||||||
obj.isBackpack mustEqual false
|
(TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
obj.Release
|
TestPlayer("Chord", PlanetSideEmpire.NC, CharacterGender.Male, 0, 5)) mustEqual false
|
||||||
obj.isAlive mustEqual false
|
|
||||||
obj.isBackpack mustEqual true
|
(TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Female, 0, 5)) mustEqual false
|
||||||
|
|
||||||
|
(TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 1, 5)) mustEqual false
|
||||||
|
|
||||||
|
(TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5) ==
|
||||||
|
TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 6)) mustEqual false
|
||||||
}
|
}
|
||||||
|
|
||||||
"(re)spawn" in {
|
"(re)spawn" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.isAlive mustEqual false
|
obj.isAlive mustEqual false
|
||||||
obj.Health mustEqual 0
|
obj.Health mustEqual 0
|
||||||
obj.Stamina mustEqual 0
|
obj.Stamina mustEqual 0
|
||||||
|
|
@ -54,32 +70,24 @@ class PlayerTest extends Specification {
|
||||||
obj.Armor mustEqual 50
|
obj.Armor mustEqual 50
|
||||||
}
|
}
|
||||||
|
|
||||||
"set new maximum values (health, stamina)" in {
|
"will not (re)spawn if not dead" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.MaxHealth mustEqual 100
|
|
||||||
obj.MaxStamina mustEqual 100
|
|
||||||
obj.MaxHealth = 123
|
|
||||||
obj.MaxStamina = 456
|
|
||||||
obj.Spawn
|
obj.Spawn
|
||||||
obj.Health mustEqual 123
|
obj.Health mustEqual 100
|
||||||
obj.Stamina mustEqual 456
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
"init (Standard Exo-Suit)" in {
|
"can die" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
"die" in {
|
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
|
||||||
obj.Spawn
|
obj.Spawn
|
||||||
obj.Armor = 35 //50 -> 35
|
obj.Armor = 35 //50 -> 35
|
||||||
obj.isAlive mustEqual true
|
obj.isAlive mustEqual true
|
||||||
|
|
@ -93,9 +101,80 @@ class PlayerTest extends Specification {
|
||||||
obj.Armor mustEqual 35
|
obj.Armor mustEqual 35
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"can not become a backpack if alive" in {
|
||||||
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
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, 5)
|
||||||
|
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, 5)
|
||||||
|
obj.MaxHealth mustEqual 100
|
||||||
|
obj.MaxStamina mustEqual 100
|
||||||
|
obj.MaxHealth = 123
|
||||||
|
obj.MaxStamina = 456
|
||||||
|
obj.Spawn
|
||||||
|
obj.Health mustEqual 123
|
||||||
|
obj.Stamina mustEqual 456
|
||||||
|
}
|
||||||
|
|
||||||
|
"set new values (health, armor, stamina) but only when alive" in {
|
||||||
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
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, 5)
|
||||||
|
obj.VisibleSlots mustEqual Set(0,1,2,3,4)
|
||||||
|
obj.ExoSuit = ExoSuitType.MAX
|
||||||
|
obj.VisibleSlots mustEqual Set(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
"init (Standard Exo-Suit)" in {
|
||||||
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
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 {
|
"draw equipped holsters only" in {
|
||||||
val wep = SimpleItem(SimpleItemDefinition(149))
|
val wep = SimpleItem(SimpleItemDefinition(149))
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.Slot(1).Size = EquipmentSize.Pistol
|
obj.Slot(1).Size = EquipmentSize.Pistol
|
||||||
obj.Slot(1).Equipment = wep
|
obj.Slot(1).Equipment = wep
|
||||||
obj.DrawnSlot mustEqual Player.HandsDownSlot
|
obj.DrawnSlot mustEqual Player.HandsDownSlot
|
||||||
|
|
@ -108,7 +187,7 @@ class PlayerTest extends Specification {
|
||||||
"remember the last drawn holster" in {
|
"remember the last drawn holster" in {
|
||||||
val wep1 = SimpleItem(SimpleItemDefinition(149))
|
val wep1 = SimpleItem(SimpleItemDefinition(149))
|
||||||
val wep2 = SimpleItem(SimpleItemDefinition(149))
|
val wep2 = SimpleItem(SimpleItemDefinition(149))
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.Slot(0).Size = EquipmentSize.Pistol
|
obj.Slot(0).Size = EquipmentSize.Pistol
|
||||||
obj.Slot(0).Equipment = wep1
|
obj.Slot(0).Equipment = wep1
|
||||||
obj.Slot(1).Size = EquipmentSize.Pistol
|
obj.Slot(1).Size = EquipmentSize.Pistol
|
||||||
|
|
@ -147,7 +226,7 @@ class PlayerTest extends Specification {
|
||||||
|
|
||||||
"hold something in their free hand" in {
|
"hold something in their free hand" in {
|
||||||
val wep = SimpleItem(SimpleItemDefinition(149))
|
val wep = SimpleItem(SimpleItemDefinition(149))
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.Slot(Player.FreeHandSlot).Equipment = wep
|
obj.Slot(Player.FreeHandSlot).Equipment = wep
|
||||||
|
|
||||||
obj.Slot(Player.FreeHandSlot).Equipment.get.Definition.ObjectId mustEqual 149
|
obj.Slot(Player.FreeHandSlot).Equipment.get.Definition.ObjectId mustEqual 149
|
||||||
|
|
@ -155,15 +234,15 @@ class PlayerTest extends Specification {
|
||||||
|
|
||||||
"provide an invalid hand that can not hold anything" in {
|
"provide an invalid hand that can not hold anything" in {
|
||||||
val wep = SimpleItem(SimpleItemDefinition(149))
|
val wep = SimpleItem(SimpleItemDefinition(149))
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.Slot(-1).Equipment = wep
|
obj.Slot(-1).Equipment = wep
|
||||||
|
|
||||||
obj.Slot(-1).Equipment mustEqual None
|
obj.Slot(-1).Equipment mustEqual None
|
||||||
}
|
}
|
||||||
|
|
||||||
"search for the smallest available slot in which to satore equipment" in {
|
"search for the smallest available slot in which to store equipment" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.Inventory.Resize(3,3)
|
obj.Inventory.Resize(3,3) //fits one item
|
||||||
|
|
||||||
obj.Fit(Tool(GlobalDefinitions.beamer)) mustEqual Some(0)
|
obj.Fit(Tool(GlobalDefinitions.beamer)) mustEqual Some(0)
|
||||||
|
|
||||||
|
|
@ -176,46 +255,180 @@ class PlayerTest extends Specification {
|
||||||
obj.Slot(6).Equipment = ammo
|
obj.Slot(6).Equipment = ammo
|
||||||
obj.Fit(ammo2) mustEqual Some(Player.FreeHandSlot)
|
obj.Fit(ammo2) mustEqual Some(Player.FreeHandSlot)
|
||||||
obj.Slot(Player.FreeHandSlot).Equipment = ammo2
|
obj.Slot(Player.FreeHandSlot).Equipment = ammo2
|
||||||
obj.Fit(ammo2) mustEqual None
|
obj.Fit(ammo3) mustEqual None
|
||||||
}
|
}
|
||||||
|
|
||||||
"install an implant" in {
|
"can use their free hand to hold things" in {
|
||||||
val testplant : ImplantDefinition = ImplantDefinition(1)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val ammo = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||||
obj.Implants(0).Unlocked = true
|
obj.FreeHand.Equipment mustEqual None
|
||||||
obj.InstallImplant(testplant) mustEqual Some(0)
|
|
||||||
obj.Implants.find({p => p.Implant == ImplantType(1)}) match { //find the installed implant
|
obj.FreeHand.Equipment = ammo
|
||||||
case Some(slot) =>
|
obj.FreeHand.Equipment mustEqual Some(ammo)
|
||||||
slot.Installed mustEqual Some(testplant)
|
}
|
||||||
|
|
||||||
|
"can access the player's locker-space" in {
|
||||||
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
obj.Slot(5).Equipment.get.isInstanceOf[LockerContainer] mustEqual true
|
||||||
|
}
|
||||||
|
|
||||||
|
"can find equipment" in {
|
||||||
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
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.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)) mustEqual Some(0) //holsters
|
||||||
|
obj.Find(PlanetSideGUID(2)) mustEqual Some(4) //holsters, melee
|
||||||
|
obj.Find(PlanetSideGUID(3)) mustEqual Some(6) //inventory
|
||||||
|
obj.Find(PlanetSideGUID(4)) mustEqual Some(Player.LockerSlot) //locker-space
|
||||||
|
obj.Find(PlanetSideGUID(5)) mustEqual Some(Player.FreeHandSlot) //free hand
|
||||||
|
obj.Find(PlanetSideGUID(6)) mustEqual None //not here
|
||||||
|
}
|
||||||
|
|
||||||
|
"does equipment collision checking (are we already holding something there?)" in {
|
||||||
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
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 _ =>
|
case _ =>
|
||||||
ko
|
ko
|
||||||
}
|
} //holsters
|
||||||
ok
|
|
||||||
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
"can not install the same type of implant twice" in {
|
"battle experience point values of the avatar" in {
|
||||||
val testplant1 : ImplantDefinition = ImplantDefinition(1)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
val testplant2 : ImplantDefinition = ImplantDefinition(1)
|
val player = Player(avatar)
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
|
||||||
obj.Implants(0).Unlocked = true
|
player.BEP mustEqual avatar.BEP
|
||||||
obj.Implants(1).Unlocked = true
|
avatar.BEP = 1002
|
||||||
obj.InstallImplant(testplant1) mustEqual Some(0)
|
player.BEP mustEqual avatar.BEP
|
||||||
obj.InstallImplant(testplant2) mustEqual Some(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
"uninstall implants" in {
|
"command experience point values of the avatar" in {
|
||||||
val testplant : ImplantDefinition = ImplantDefinition(1)
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val player = Player(avatar)
|
||||||
obj.Implants(0).Unlocked = true
|
|
||||||
obj.InstallImplant(testplant) mustEqual Some(0)
|
|
||||||
obj.Implants(0).Installed mustEqual Some(testplant)
|
|
||||||
|
|
||||||
obj.UninstallImplant(testplant.Type)
|
player.CEP mustEqual avatar.CEP
|
||||||
obj.Implants(0).Installed mustEqual None
|
avatar.CEP = 1002
|
||||||
|
player.CEP mustEqual avatar.CEP
|
||||||
|
}
|
||||||
|
|
||||||
|
"can get a quick summary of implant slots (default)" in {
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player = Player(avatar)
|
||||||
|
|
||||||
|
player.Implants mustEqual Array.empty
|
||||||
|
}
|
||||||
|
|
||||||
|
"can get a quick summary of implant slots (two unlocked, one installed)" in {
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player = Player(avatar)
|
||||||
|
val temp = new ImplantDefinition(1)
|
||||||
|
avatar.Implants(0).Unlocked = true
|
||||||
|
avatar.InstallImplant(new ImplantDefinition(1))
|
||||||
|
avatar.Implants(1).Unlocked = true
|
||||||
|
avatar.InstallImplant(new ImplantDefinition(2))
|
||||||
|
avatar.UninstallImplant(temp.Type)
|
||||||
|
|
||||||
|
val list = player.Implants
|
||||||
|
//slot 0
|
||||||
|
val (implant1, init1, active1) = list(0)
|
||||||
|
implant1 mustEqual ImplantType.None
|
||||||
|
init1 mustEqual -1
|
||||||
|
active1 mustEqual false
|
||||||
|
//slot 1
|
||||||
|
val (implant2, init2, active2) = list(1)
|
||||||
|
implant2 mustEqual ImplantType(2)
|
||||||
|
init2 mustEqual 0
|
||||||
|
active2 mustEqual false
|
||||||
|
}
|
||||||
|
|
||||||
|
"can get a quick summary of implant slots (all unlocked, first two installed)" in {
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player = Player(avatar)
|
||||||
|
avatar.Implants(0).Unlocked = true
|
||||||
|
avatar.InstallImplant(new ImplantDefinition(1))
|
||||||
|
avatar.Implants(0).Initialized = true
|
||||||
|
avatar.Implants(0).Active = true
|
||||||
|
avatar.Implants(1).Unlocked = true
|
||||||
|
avatar.InstallImplant(new ImplantDefinition(2))
|
||||||
|
avatar.Implants(1).Initialized = true
|
||||||
|
avatar.Implants(1).Active = false
|
||||||
|
avatar.Implants(2).Unlocked = true
|
||||||
|
|
||||||
|
val list = player.Implants
|
||||||
|
//slot 0
|
||||||
|
val (implant1, init1, active1) = list(0)
|
||||||
|
implant1 mustEqual ImplantType(1)
|
||||||
|
init1 mustEqual 0
|
||||||
|
active1 mustEqual true
|
||||||
|
//slot 1
|
||||||
|
val (implant2, init2, active2) = list(1)
|
||||||
|
implant2 mustEqual ImplantType(2)
|
||||||
|
init2 mustEqual 0
|
||||||
|
active2 mustEqual false
|
||||||
|
//slot 2
|
||||||
|
val (implant3, init3, active3) = list(2)
|
||||||
|
implant3 mustEqual ImplantType.None
|
||||||
|
init3 mustEqual -1
|
||||||
|
active3 mustEqual false
|
||||||
}
|
}
|
||||||
|
|
||||||
"seat in a vehicle" in {
|
"seat in a vehicle" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.VehicleSeated mustEqual None
|
obj.VehicleSeated mustEqual None
|
||||||
obj.VehicleSeated = PlanetSideGUID(65)
|
obj.VehicleSeated = PlanetSideGUID(65)
|
||||||
obj.VehicleSeated mustEqual Some(PlanetSideGUID(65))
|
obj.VehicleSeated mustEqual Some(PlanetSideGUID(65))
|
||||||
|
|
@ -224,7 +437,7 @@ class PlayerTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"own in a vehicle" in {
|
"own in a vehicle" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.VehicleOwned mustEqual None
|
obj.VehicleOwned mustEqual None
|
||||||
obj.VehicleOwned = PlanetSideGUID(65)
|
obj.VehicleOwned = PlanetSideGUID(65)
|
||||||
obj.VehicleOwned mustEqual Some(PlanetSideGUID(65))
|
obj.VehicleOwned mustEqual Some(PlanetSideGUID(65))
|
||||||
|
|
@ -233,27 +446,18 @@ class PlayerTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"remember what zone he is in" in {
|
"remember what zone he is in" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.Continent mustEqual "home2"
|
obj.Continent mustEqual "home2"
|
||||||
obj.Continent = "ugd01"
|
obj.Continent = "ugd01"
|
||||||
obj.Continent mustEqual "ugd01"
|
obj.Continent mustEqual "ugd01"
|
||||||
}
|
}
|
||||||
|
|
||||||
"administrate" in {
|
"toString" in {
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
val obj = TestPlayer("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
obj.Admin mustEqual false
|
obj.toString mustEqual "TR Chord 0/100 0/50"
|
||||||
Player.Administrate(obj, true)
|
|
||||||
obj.Admin mustEqual true
|
|
||||||
Player.Administrate(obj, false)
|
|
||||||
obj.Admin mustEqual false
|
|
||||||
}
|
|
||||||
|
|
||||||
"spectate" in {
|
obj.GUID = PlanetSideGUID(455)
|
||||||
val obj = new Player("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
obj.Continent = "z3"
|
||||||
obj.Spectator mustEqual false
|
obj.toString mustEqual "TR Chord z3-455 0/100 0/50"
|
||||||
Player.Spectate(obj, true)
|
|
||||||
obj.Spectator mustEqual true
|
|
||||||
Player.Spectate(obj, false)
|
|
||||||
obj.Spectator mustEqual false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import akka.actor.{Actor, ActorContext, Props}
|
||||||
import net.psforever.objects.guid.NumberPoolHub
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.objects.serverobject.ServerObjectBuilder
|
import net.psforever.objects.serverobject.ServerObjectBuilder
|
||||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, WarpGate}
|
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType, WarpGate}
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ import scala.concurrent.duration.Duration
|
||||||
class BuildingBuilderTest extends ActorTest {
|
class BuildingBuilderTest extends ActorTest {
|
||||||
"Building object" should {
|
"Building object" should {
|
||||||
"build" in {
|
"build" in {
|
||||||
val structure : (Int,Zone,ActorContext)=>Building = Building.Structure
|
val structure : (Int,Zone,ActorContext)=>Building = Building.Structure(StructureType.Building)
|
||||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, 10, Zone.Nowhere), "building")
|
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuildingTestActor], structure, 10, Zone.Nowhere), "building")
|
||||||
actor ! "!"
|
actor ! "!"
|
||||||
|
|
||||||
|
|
@ -169,6 +169,26 @@ class LockerObjectBuilderTest extends ActorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SpawnTubeObjectBuilderTest extends ActorTest {
|
||||||
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
|
"LockerObjectBuilder" 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object ServerObjectBuilderTest {
|
object ServerObjectBuilderTest {
|
||||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||||
def NumberPoolHub : NumberPoolHub = {
|
def NumberPoolHub : NumberPoolHub = {
|
||||||
|
|
|
||||||
59
common/src/test/scala/objects/SpawnTubeTest.scala
Normal file
59
common/src/test/scala/objects/SpawnTubeTest.scala
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package objects
|
||||||
|
|
||||||
|
import akka.actor.{ActorRef, Props}
|
||||||
|
import net.psforever.objects.GlobalDefinitions
|
||||||
|
import net.psforever.objects.serverobject.tube.{SpawnTube, SpawnTubeControl, SpawnTubeDefinition}
|
||||||
|
import org.specs2.mutable.Specification
|
||||||
|
|
||||||
|
class SpawnTubeTest extends Specification {
|
||||||
|
"SpawnTubeDefinition" should {
|
||||||
|
"define (ams_respawn_tube)" in {
|
||||||
|
val obj = new SpawnTubeDefinition(49)
|
||||||
|
obj.ObjectId mustEqual 49
|
||||||
|
obj.Name mustEqual "ams_respawn_tube"
|
||||||
|
}
|
||||||
|
|
||||||
|
"define (respawn_tube)" in {
|
||||||
|
val obj = new SpawnTubeDefinition(732)
|
||||||
|
obj.ObjectId mustEqual 732
|
||||||
|
obj.Name mustEqual "respawn_tube"
|
||||||
|
}
|
||||||
|
|
||||||
|
"define (respawn_tube_tower)" in {
|
||||||
|
val obj = new SpawnTubeDefinition(733)
|
||||||
|
obj.ObjectId mustEqual 733
|
||||||
|
obj.Name mustEqual "respawn_tube_tower"
|
||||||
|
}
|
||||||
|
|
||||||
|
"define (invalid)" in {
|
||||||
|
var id : Int = (math.random * Int.MaxValue).toInt
|
||||||
|
if(id == 49 || id == 733) {
|
||||||
|
id += 1
|
||||||
|
}
|
||||||
|
else if(id == 732) {
|
||||||
|
id += 2
|
||||||
|
}
|
||||||
|
|
||||||
|
new SpawnTubeDefinition(id) must throwA[IllegalArgumentException]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
"SpawnTube" should {
|
||||||
|
"construct" in {
|
||||||
|
val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
|
||||||
|
obj.Actor mustEqual ActorRef.noSender
|
||||||
|
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 != ActorRef.noSender)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,10 +3,10 @@ package objects
|
||||||
|
|
||||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.vehicles.VehicleControl
|
import net.psforever.objects.vehicles.VehicleControl
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Vehicle}
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
@ -109,8 +109,8 @@ object VehicleSpawnPadControl {
|
||||||
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, VehicleSpawnPad) = {
|
def SetUpAgents(faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, VehicleSpawnPad) = {
|
||||||
val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
|
val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
|
||||||
pad.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], pad), "test-pad")
|
pad.Actor = system.actorOf(Props(classOf[VehicleSpawnControl], pad), "test-pad")
|
||||||
pad.Owner = new Building(0, Zone.Nowhere)
|
pad.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
pad.Owner.Faction = faction
|
pad.Owner.Faction = faction
|
||||||
(Player("test", faction, CharacterGender.Male, 0, 0), pad)
|
(Player(Avatar("test", faction, CharacterGender.Male, 0, 0)), pad)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,17 +2,18 @@
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.Props
|
import akka.actor.Props
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
|
import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.vehicles._
|
import net.psforever.objects.vehicles._
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire}
|
import net.psforever.types.ExoSuitType
|
||||||
import org.specs2.mutable._
|
import org.specs2.mutable._
|
||||||
|
|
||||||
import scala.concurrent.duration.Duration
|
import scala.concurrent.duration.Duration
|
||||||
|
|
||||||
class VehicleTest extends Specification {
|
class VehicleTest extends Specification {
|
||||||
|
import VehicleTest._
|
||||||
|
|
||||||
"SeatDefinition" should {
|
"SeatDefinition" should {
|
||||||
val seat = new SeatDefinition
|
val seat = new SeatDefinition
|
||||||
|
|
@ -73,7 +74,7 @@ class VehicleTest extends Specification {
|
||||||
val seat = new Seat(seat_def)
|
val seat = new Seat(seat_def)
|
||||||
seat.Occupant.isDefined mustEqual false
|
seat.Occupant.isDefined mustEqual false
|
||||||
|
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(avatar1)
|
||||||
player1.ExoSuit = ExoSuitType.MAX
|
player1.ExoSuit = ExoSuitType.MAX
|
||||||
seat.Occupant = player1
|
seat.Occupant = player1
|
||||||
seat.Occupant.isDefined mustEqual true
|
seat.Occupant.isDefined mustEqual true
|
||||||
|
|
@ -84,13 +85,13 @@ class VehicleTest extends Specification {
|
||||||
val seat = new Seat(seat_def)
|
val seat = new Seat(seat_def)
|
||||||
seat.Occupant.isDefined mustEqual false
|
seat.Occupant.isDefined mustEqual false
|
||||||
|
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(avatar1)
|
||||||
player1.ExoSuit = ExoSuitType.MAX
|
player1.ExoSuit = ExoSuitType.MAX
|
||||||
seat.Occupant = player1
|
seat.Occupant = player1
|
||||||
seat.Occupant.isDefined mustEqual true
|
seat.Occupant.isDefined mustEqual true
|
||||||
seat.Occupant.contains(player1) mustEqual true
|
seat.Occupant.contains(player1) mustEqual true
|
||||||
|
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(avatar1)
|
||||||
player2.ExoSuit = ExoSuitType.MAX
|
player2.ExoSuit = ExoSuitType.MAX
|
||||||
seat.Occupant = player2
|
seat.Occupant = player2
|
||||||
seat.Occupant.isDefined mustEqual true
|
seat.Occupant.isDefined mustEqual true
|
||||||
|
|
@ -101,13 +102,13 @@ class VehicleTest extends Specification {
|
||||||
val seat = new Seat(seat_def)
|
val seat = new Seat(seat_def)
|
||||||
seat.Occupant.isDefined mustEqual false
|
seat.Occupant.isDefined mustEqual false
|
||||||
|
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(avatar1)
|
||||||
player1.ExoSuit = ExoSuitType.MAX
|
player1.ExoSuit = ExoSuitType.MAX
|
||||||
seat.Occupant = player1
|
seat.Occupant = player1
|
||||||
seat.Occupant.isDefined mustEqual true
|
seat.Occupant.isDefined mustEqual true
|
||||||
seat.Occupant.contains(player1) mustEqual true
|
seat.Occupant.contains(player1) mustEqual true
|
||||||
|
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(avatar2)
|
||||||
player2.ExoSuit = ExoSuitType.MAX
|
player2.ExoSuit = ExoSuitType.MAX
|
||||||
seat.Occupant = player2
|
seat.Occupant = player2
|
||||||
seat.Occupant.isDefined mustEqual true
|
seat.Occupant.isDefined mustEqual true
|
||||||
|
|
@ -160,7 +161,7 @@ class VehicleTest extends Specification {
|
||||||
val fury_vehicle = Vehicle(GlobalDefinitions.fury)
|
val fury_vehicle = Vehicle(GlobalDefinitions.fury)
|
||||||
fury_vehicle.Owner.isDefined mustEqual false
|
fury_vehicle.Owner.isDefined mustEqual false
|
||||||
|
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(avatar1)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
player1.GUID = PlanetSideGUID(1)
|
||||||
fury_vehicle.Owner = player1
|
fury_vehicle.Owner = player1
|
||||||
fury_vehicle.Owner.isDefined mustEqual true
|
fury_vehicle.Owner.isDefined mustEqual true
|
||||||
|
|
@ -171,13 +172,13 @@ class VehicleTest extends Specification {
|
||||||
val fury_vehicle = Vehicle(GlobalDefinitions.fury)
|
val fury_vehicle = Vehicle(GlobalDefinitions.fury)
|
||||||
fury_vehicle.Owner.isDefined mustEqual false
|
fury_vehicle.Owner.isDefined mustEqual false
|
||||||
|
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(avatar1)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
player1.GUID = PlanetSideGUID(1)
|
||||||
fury_vehicle.Owner = player1
|
fury_vehicle.Owner = player1
|
||||||
fury_vehicle.Owner.isDefined mustEqual true
|
fury_vehicle.Owner.isDefined mustEqual true
|
||||||
fury_vehicle.Owner.contains(PlanetSideGUID(1)) mustEqual true
|
fury_vehicle.Owner.contains(PlanetSideGUID(1)) mustEqual true
|
||||||
|
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(avatar2)
|
||||||
player2.GUID = PlanetSideGUID(2)
|
player2.GUID = PlanetSideGUID(2)
|
||||||
fury_vehicle.Owner = player2
|
fury_vehicle.Owner = player2
|
||||||
fury_vehicle.Owner.isDefined mustEqual true
|
fury_vehicle.Owner.isDefined mustEqual true
|
||||||
|
|
@ -234,9 +235,9 @@ class VehicleTest extends Specification {
|
||||||
|
|
||||||
"can find a passenger in a seat" in {
|
"can find a passenger in a seat" in {
|
||||||
val harasser_vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
val harasser_vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(avatar1)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
player1.GUID = PlanetSideGUID(1)
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(avatar2)
|
||||||
player2.GUID = PlanetSideGUID(2)
|
player2.GUID = PlanetSideGUID(2)
|
||||||
harasser_vehicle.Seat(0).get.Occupant = player1 //don't worry about ownership for now
|
harasser_vehicle.Seat(0).get.Occupant = player1 //don't worry about ownership for now
|
||||||
harasser_vehicle.Seat(1).get.Occupant = player2
|
harasser_vehicle.Seat(1).get.Occupant = player2
|
||||||
|
|
@ -282,9 +283,9 @@ class VehicleTest extends Specification {
|
||||||
class VehicleControl1Test extends ActorTest {
|
class VehicleControl1Test extends ActorTest {
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"deactivate and stop handling mount messages" in {
|
"deactivate and stop handling mount messages" in {
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
player1.GUID = PlanetSideGUID(1)
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(VehicleTest.avatar2)
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
vehicle.GUID = PlanetSideGUID(3)
|
vehicle.GUID = PlanetSideGUID(3)
|
||||||
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
vehicle.Actor = system.actorOf(Props(classOf[VehicleControl], vehicle), "vehicle-test")
|
||||||
|
|
@ -303,9 +304,9 @@ class VehicleControl1Test extends ActorTest {
|
||||||
class VehicleControl2Test extends ActorTest {
|
class VehicleControl2Test extends ActorTest {
|
||||||
"Vehicle Control" should {
|
"Vehicle Control" should {
|
||||||
"reactivate and resume handling mount messages" in {
|
"reactivate and resume handling mount messages" in {
|
||||||
val player1 = Player("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player1 = Player(VehicleTest.avatar1)
|
||||||
player1.GUID = PlanetSideGUID(1)
|
player1.GUID = PlanetSideGUID(1)
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(VehicleTest.avatar2)
|
||||||
player2.GUID = PlanetSideGUID(2)
|
player2.GUID = PlanetSideGUID(2)
|
||||||
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
val vehicle = Vehicle(GlobalDefinitions.two_man_assault_buggy)
|
||||||
vehicle.GUID = PlanetSideGUID(3)
|
vehicle.GUID = PlanetSideGUID(3)
|
||||||
|
|
@ -324,3 +325,10 @@ class VehicleControl2Test extends ActorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object VehicleTest {
|
||||||
|
import net.psforever.objects.Avatar
|
||||||
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
||||||
|
val avatar1 = Avatar("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
||||||
|
val avatar2 = Avatar("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,24 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package objects
|
package objects
|
||||||
|
|
||||||
import akka.actor.{ActorContext, ActorRef}
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
|
import akka.actor.{Actor, ActorContext, ActorRef, Props}
|
||||||
import net.psforever.objects.entity.IdentifiableEntity
|
import net.psforever.objects.entity.IdentifiableEntity
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.objects.guid.NumberPoolHub
|
import net.psforever.objects.guid.NumberPoolHub
|
||||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder}
|
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType}
|
||||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
|
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||||
|
import net.psforever.objects._
|
||||||
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
||||||
|
import scala.concurrent.duration.Duration
|
||||||
|
|
||||||
class ZoneTest extends Specification {
|
class ZoneTest extends Specification {
|
||||||
def test(a: Int, b : Zone, c : ActorContext) : Building = { Building.NoBuilding }
|
def test(a: Int, b : Zone, c : ActorContext) : Building = { Building.NoBuilding }
|
||||||
|
|
||||||
|
|
@ -82,6 +90,8 @@ class ZoneTest extends Specification {
|
||||||
//zone also has a unique identifier system but it can't be accessed without its the Actor GUID being initialized
|
//zone also has a unique identifier system but it can't be accessed without its the Actor GUID being initialized
|
||||||
zone.EquipmentOnGround mustEqual List.empty[Equipment]
|
zone.EquipmentOnGround mustEqual List.empty[Equipment]
|
||||||
zone.Vehicles mustEqual List.empty[Vehicle]
|
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 {
|
"can have its unique identifier system changed if no objects were added to it" in {
|
||||||
|
|
@ -124,3 +134,422 @@ class ZoneTest extends Specification {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ZoneActorTest extends ActorTest {
|
||||||
|
"Zone" should {
|
||||||
|
"have an Actor" in {
|
||||||
|
val zone = new Zone("test", new ZoneMap("map6"), 1)
|
||||||
|
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-actor")
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
assert(zone.Actor != ActorRef.noSender)
|
||||||
|
}
|
||||||
|
|
||||||
|
"set up spawn groups based on buildings" in {
|
||||||
|
val map6 = new ZoneMap("map6") {
|
||||||
|
LocalBuilding(1, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1,1,1))))
|
||||||
|
LocalObject(1, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||||
|
LocalObject(2, Terminal.Constructor(GlobalDefinitions.dropship_vehicle_terminal))
|
||||||
|
LocalObject(3, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||||
|
ObjectToBuilding(1, 1)
|
||||||
|
ObjectToBuilding(2, 1)
|
||||||
|
ObjectToBuilding(3, 1)
|
||||||
|
|
||||||
|
LocalBuilding(2, FoundationBuilder(Building.Structure(StructureType.Building)))
|
||||||
|
LocalObject(7, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||||
|
ObjectToBuilding(7, 2)
|
||||||
|
|
||||||
|
LocalBuilding(3, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1,1,1))))
|
||||||
|
LocalObject(4, Terminal.Constructor(GlobalDefinitions.dropship_vehicle_terminal))
|
||||||
|
LocalObject(5, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||||
|
LocalObject(6, Terminal.Constructor(GlobalDefinitions.dropship_vehicle_terminal))
|
||||||
|
ObjectToBuilding(4, 3)
|
||||||
|
ObjectToBuilding(5, 3)
|
||||||
|
ObjectToBuilding(6, 3)
|
||||||
|
}
|
||||||
|
val zone = new Zone("test", map6, 1)
|
||||||
|
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-init")
|
||||||
|
zone.Actor ! Zone.Init()
|
||||||
|
expectNoMsg(Duration.create(300, "ms"))
|
||||||
|
|
||||||
|
val groups = zone.SpawnGroups()
|
||||||
|
assert(groups.size == 2)
|
||||||
|
zone.SpawnGroups().foreach({ case(building, tubes) =>
|
||||||
|
if(building.Id == 1) {
|
||||||
|
val building1 = zone.SpawnGroups(building)
|
||||||
|
assert(tubes.length == 2)
|
||||||
|
assert(tubes.head == building1.head)
|
||||||
|
assert(tubes.head.GUID == PlanetSideGUID(1))
|
||||||
|
assert(tubes(1) == building1(1))
|
||||||
|
assert(tubes(1).GUID == PlanetSideGUID(3))
|
||||||
|
}
|
||||||
|
else if(building.Id == 3) {
|
||||||
|
val building2 = zone.SpawnGroups(building)
|
||||||
|
assert(tubes.length == 1)
|
||||||
|
assert(tubes.head == building2.head)
|
||||||
|
assert(tubes.head.GUID == PlanetSideGUID(5))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
assert(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
"select spawn points based on the position of the player in reference to buildings" in {
|
||||||
|
val map6 = new ZoneMap("map6") {
|
||||||
|
LocalBuilding(1, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1,1,1))))
|
||||||
|
LocalObject(1, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||||
|
ObjectToBuilding(1, 1)
|
||||||
|
|
||||||
|
LocalBuilding(3, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(4,4,4))))
|
||||||
|
LocalObject(5, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||||
|
ObjectToBuilding(5, 3)
|
||||||
|
}
|
||||||
|
val zone = new Zone("test", map6, 1)
|
||||||
|
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-spawn")
|
||||||
|
zone.Actor ! Zone.Init()
|
||||||
|
expectNoMsg(Duration.create(300, "ms"))
|
||||||
|
val player = Player(Avatar("Chord", PlanetSideEmpire.NEUTRAL, CharacterGender.Male, 0, 5))
|
||||||
|
|
||||||
|
val bldg1 = zone.Building(1).get
|
||||||
|
val bldg3 = zone.Building(3).get
|
||||||
|
player.Position = Vector3(1,1,1) //closer to bldg1
|
||||||
|
zone.Actor ! Zone.Lattice.RequestSpawnPoint(1, player, 7)
|
||||||
|
val reply1 = receiveOne(Duration.create(200, "ms"))
|
||||||
|
assert(reply1.isInstanceOf[Zone.Lattice.SpawnPoint])
|
||||||
|
assert(reply1.asInstanceOf[Zone.Lattice.SpawnPoint].zone_id == "test")
|
||||||
|
assert(reply1.asInstanceOf[Zone.Lattice.SpawnPoint].building == bldg1)
|
||||||
|
assert(reply1.asInstanceOf[Zone.Lattice.SpawnPoint].spawn_tube.Owner == bldg1)
|
||||||
|
|
||||||
|
player.Position = Vector3(3,3,3) //closer to bldg3
|
||||||
|
zone.Actor ! Zone.Lattice.RequestSpawnPoint(1, player, 7)
|
||||||
|
val reply3 = receiveOne(Duration.create(200, "ms"))
|
||||||
|
assert(reply3.isInstanceOf[Zone.Lattice.SpawnPoint])
|
||||||
|
assert(reply3.asInstanceOf[Zone.Lattice.SpawnPoint].zone_id == "test")
|
||||||
|
assert(reply3.asInstanceOf[Zone.Lattice.SpawnPoint].building == bldg3)
|
||||||
|
assert(reply3.asInstanceOf[Zone.Lattice.SpawnPoint].spawn_tube.Owner == bldg3)
|
||||||
|
}
|
||||||
|
|
||||||
|
"will report if no spawn points have been found in a zone" in {
|
||||||
|
val map6 = new ZoneMap("map6") {
|
||||||
|
LocalBuilding(1, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1,1,1))))
|
||||||
|
|
||||||
|
LocalBuilding(3, FoundationBuilder(Building.Structure(StructureType.Tower, Vector3(4,4,4))))
|
||||||
|
LocalObject(5, SpawnTube.Constructor(Vector3.Zero, Vector3.Zero))
|
||||||
|
ObjectToBuilding(5, 3)
|
||||||
|
}
|
||||||
|
val zone = new Zone("test", map6, 1)
|
||||||
|
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "test-no-spawn")
|
||||||
|
zone.Actor ! Zone.Init()
|
||||||
|
expectNoMsg(Duration.create(300, "ms"))
|
||||||
|
val player = Player(Avatar("Chord", PlanetSideEmpire.NEUTRAL, CharacterGender.Male, 0, 5))
|
||||||
|
|
||||||
|
zone.Actor ! Zone.Lattice.RequestSpawnPoint(1, player, 7)
|
||||||
|
val reply = receiveOne(Duration.create(200, "ms"))
|
||||||
|
assert(reply.isInstanceOf[Zone.Lattice.NoValidSpawnPoint])
|
||||||
|
assert(reply.asInstanceOf[Zone.Lattice.NoValidSpawnPoint].zone_number == 1)
|
||||||
|
assert(reply.asInstanceOf[Zone.Lattice.NoValidSpawnPoint].spawn_group.contains(7))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZonePopulationTest extends ActorTest {
|
||||||
|
val testNum = new AtomicInteger(1)
|
||||||
|
def TestName : String = s"test${testNum.getAndIncrement()}"
|
||||||
|
|
||||||
|
"ZonePopulationActor" should {
|
||||||
|
"add new user to zones" in {
|
||||||
|
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
|
||||||
|
assert(zone.Players.isEmpty)
|
||||||
|
assert(zone.LivePlayers.isEmpty)
|
||||||
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
|
expectNoMsg(Duration.create(100, "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)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
|
||||||
|
assert(zone.Players.size == 1)
|
||||||
|
assert(zone.Players.head == avatar)
|
||||||
|
zone.Population ! Zone.Population.Leave(avatar)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
assert(zone.Players.isEmpty)
|
||||||
|
}
|
||||||
|
|
||||||
|
"associate user with a character" in {
|
||||||
|
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player = Player(avatar)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
|
expectNoMsg(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)
|
||||||
|
expectNoMsg(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)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player = Player(avatar)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
zone.Population ! Zone.Population.Spawn(avatar, player)
|
||||||
|
expectNoMsg(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)
|
||||||
|
expectNoMsg(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)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player = Player(avatar)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(500, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
zone.Population ! Zone.Population.Spawn(avatar, player)
|
||||||
|
expectNoMsg(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(100, "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)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player1 = Player(avatar)
|
||||||
|
val player2 = Player(avatar)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
zone.Population ! Zone.Population.Spawn(avatar, player1)
|
||||||
|
expectNoMsg(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)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
val player = Player(avatar)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
|
||||||
|
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)
|
||||||
|
val avatar = Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Population.Join(avatar)
|
||||||
|
expectNoMsg(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)
|
||||||
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
player.Release
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
zone.Population ! Zone.Corpse.Add(player)
|
||||||
|
expectNoMsg(Duration.create(100, "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)
|
||||||
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
player.Release
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Corpse.Add(player)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
|
||||||
|
assert(zone.Corpses.size == 1)
|
||||||
|
assert(zone.Corpses.head == player)
|
||||||
|
zone.Population ! Zone.Corpse.Remove(player)
|
||||||
|
expectNoMsg(Duration.create(100, "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)
|
||||||
|
val player1 = Player(Avatar("Chord1", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
player1.Release
|
||||||
|
val player2 = Player(Avatar("Chord2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
player2.Release
|
||||||
|
val player3 = Player(Avatar("Chord3", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
player3.Release
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), TestName) ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Population ! Zone.Corpse.Add(player1)
|
||||||
|
zone.Population ! Zone.Corpse.Add(player2)
|
||||||
|
zone.Population ! Zone.Corpse.Add(player3)
|
||||||
|
expectNoMsg(Duration.create(100, "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)
|
||||||
|
expectNoMsg(Duration.create(100, "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)
|
||||||
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
//player.Release !!important
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "testC") ! "!"
|
||||||
|
receiveOne(Duration.create(500, "ms")) //consume
|
||||||
|
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
zone.Population ! Zone.Corpse.Add(player)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ZoneGroundTest extends ActorTest {
|
||||||
|
val item = AmmoBox(GlobalDefinitions.bullet_9mm)
|
||||||
|
item.GUID = PlanetSideGUID(10)
|
||||||
|
|
||||||
|
"ZoneGroundActor" should {
|
||||||
|
"drop item on ground" in {
|
||||||
|
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "drop-item-test") ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
|
||||||
|
assert(zone.EquipmentOnGround.isEmpty)
|
||||||
|
assert(item.Position == Vector3.Zero)
|
||||||
|
assert(item.Orientation == Vector3.Zero)
|
||||||
|
zone.Ground ! Zone.DropItemOnGround(item, Vector3(1.1f, 2.2f, 3.3f), Vector3(4.4f, 5.5f, 6.6f))
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
|
||||||
|
assert(zone.EquipmentOnGround == List(item))
|
||||||
|
assert(item.Position == Vector3(1.1f, 2.2f, 3.3f))
|
||||||
|
assert(item.Orientation == Vector3(4.4f, 5.5f, 6.6f))
|
||||||
|
}
|
||||||
|
|
||||||
|
"get item from ground (success)" in {
|
||||||
|
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||||
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "get-item-test-good") ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Ground ! Zone.DropItemOnGround(item, Vector3.Zero, Vector3.Zero)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
|
||||||
|
assert(zone.EquipmentOnGround == List(item))
|
||||||
|
zone.Ground ! Zone.GetItemOnGround(player, PlanetSideGUID(10))
|
||||||
|
val reply = receiveOne(Duration.create(100, "ms"))
|
||||||
|
|
||||||
|
assert(zone.EquipmentOnGround.isEmpty)
|
||||||
|
assert(reply.isInstanceOf[Zone.ItemFromGround])
|
||||||
|
assert(reply.asInstanceOf[Zone.ItemFromGround].player == player)
|
||||||
|
assert(reply.asInstanceOf[Zone.ItemFromGround].item == item)
|
||||||
|
}
|
||||||
|
|
||||||
|
"get item from ground (failure)" in {
|
||||||
|
val zone = new Zone("test", new ZoneMap(""), 0)
|
||||||
|
val player = Player(Avatar("Chord", PlanetSideEmpire.TR, CharacterGender.Male, 0, 5))
|
||||||
|
system.actorOf(Props(classOf[ZoneTest.ZoneInitActor], zone), "get-item-test-fail") ! "!"
|
||||||
|
receiveOne(Duration.create(200, "ms")) //consume
|
||||||
|
zone.Ground ! Zone.DropItemOnGround(item, Vector3.Zero, Vector3.Zero)
|
||||||
|
expectNoMsg(Duration.create(100, "ms"))
|
||||||
|
|
||||||
|
assert(zone.EquipmentOnGround == List(item))
|
||||||
|
zone.Ground ! Zone.GetItemOnGround(player, PlanetSideGUID(11)) //wrong guid
|
||||||
|
expectNoMsg(Duration.create(500, "ms"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object ZoneTest {
|
||||||
|
class ZoneInitActor(zone : Zone) extends Actor {
|
||||||
|
def receive : Receive = {
|
||||||
|
case "!" =>
|
||||||
|
zone.Init(context)
|
||||||
|
sender ! "!"
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package objects.guidtask
|
package objects.guidtask
|
||||||
|
|
||||||
|
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
||||||
|
|
@ -10,7 +9,7 @@ import objects.ActorTest
|
||||||
class GUIDTaskRegister5Test extends ActorTest() {
|
class GUIDTaskRegister5Test extends ActorTest() {
|
||||||
"RegisterAvatar" in {
|
"RegisterAvatar" in {
|
||||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||||
val obj = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val obj_wep = Tool(GlobalDefinitions.beamer)
|
val obj_wep = Tool(GlobalDefinitions.beamer)
|
||||||
obj.Slot(0).Equipment = obj_wep
|
obj.Slot(0).Equipment = obj_wep
|
||||||
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
|
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package objects.guidtask
|
||||||
|
|
||||||
|
import net.psforever.objects._
|
||||||
|
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||||
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
||||||
|
import objects.ActorTest
|
||||||
|
|
||||||
|
class GUIDTaskRegister6Test extends ActorTest() {
|
||||||
|
"RegisterPlayer" in {
|
||||||
|
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||||
|
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
|
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[LockerContainer].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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -9,7 +9,7 @@ import objects.ActorTest
|
||||||
class GUIDTaskUnregister5Test extends ActorTest() {
|
class GUIDTaskUnregister5Test extends ActorTest() {
|
||||||
"UnregisterAvatar" in {
|
"UnregisterAvatar" in {
|
||||||
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||||
val obj = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val obj_wep = Tool(GlobalDefinitions.beamer)
|
val obj_wep = Tool(GlobalDefinitions.beamer)
|
||||||
obj.Slot(0).Equipment = obj_wep
|
obj.Slot(0).Equipment = obj_wep
|
||||||
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
|
val obj_wep_ammo = AmmoBox(GlobalDefinitions.energy_cell)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,44 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package objects.guidtask
|
||||||
|
|
||||||
|
import net.psforever.objects._
|
||||||
|
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||||
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire}
|
||||||
|
import objects.ActorTest
|
||||||
|
|
||||||
|
class GUIDTaskUnregister6Test extends ActorTest() {
|
||||||
|
"UnregisterPlayer" in {
|
||||||
|
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||||
|
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
|
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[LockerContainer].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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -275,6 +275,40 @@ class UniqueNumberSystemTest8 extends ActorTest() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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")
|
||||||
|
expectNoMsg(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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object UniqueNumberSystemTest {
|
object UniqueNumberSystemTest {
|
||||||
/**
|
/**
|
||||||
* @see `UniqueNumberSystem.AllocateNumberPoolActors(NumberPoolHub)(implicit ActorContext)`
|
* @see `UniqueNumberSystem.AllocateNumberPoolActors(NumberPoolHub)(implicit ActorContext)`
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
|
|
@ -12,9 +12,9 @@ import org.specs2.mutable.Specification
|
||||||
|
|
||||||
class AirVehicleTerminalTest extends Specification {
|
class AirVehicleTerminalTest extends Specification {
|
||||||
"Air_Vehicle_Terminal" should {
|
"Air_Vehicle_Terminal" should {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val terminal = Terminal(GlobalDefinitions.air_vehicle_terminal)
|
val terminal = Terminal(GlobalDefinitions.air_vehicle_terminal)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,19 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
||||||
class CertTerminalTest extends Specification {
|
class CertTerminalTest extends Specification {
|
||||||
"Cert_Terminal" should {
|
"Cert_Terminal" should {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val terminal = Terminal(GlobalDefinitions.cert_terminal)
|
val terminal = Terminal(GlobalDefinitions.cert_terminal)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
|
|
@ -12,9 +12,9 @@ import org.specs2.mutable.Specification
|
||||||
|
|
||||||
class DropshipVehicleTerminalTest extends Specification {
|
class DropshipVehicleTerminalTest extends Specification {
|
||||||
"Dropship_Vehicle_Terminal" should {
|
"Dropship_Vehicle_Terminal" should {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal)
|
val terminal = Terminal(GlobalDefinitions.dropship_vehicle_terminal)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
|
|
@ -12,9 +12,9 @@ import org.specs2.mutable.Specification
|
||||||
|
|
||||||
class GroundVehicleTerminalTest extends Specification {
|
class GroundVehicleTerminalTest extends Specification {
|
||||||
"Ground_Vehicle_Terminal" should {
|
"Ground_Vehicle_Terminal" should {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
|
val terminal = Terminal(GlobalDefinitions.ground_vehicle_terminal)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
|
|
@ -12,9 +12,9 @@ import org.specs2.mutable.Specification
|
||||||
|
|
||||||
class ImplantTerminalInterfaceTest extends Specification {
|
class ImplantTerminalInterfaceTest extends Specification {
|
||||||
"Implant_Terminal_Interface" should {
|
"Implant_Terminal_Interface" should {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
|
val terminal = Terminal(GlobalDefinitions.implant_terminal_interface)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
|
||||||
|
|
@ -5,8 +5,9 @@ import akka.actor.{ActorRef, ActorSystem, Props}
|
||||||
import net.psforever.objects.definition.SeatDefinition
|
import net.psforever.objects.definition.SeatDefinition
|
||||||
import net.psforever.objects.serverobject.mount.Mountable
|
import net.psforever.objects.serverobject.mount.Mountable
|
||||||
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
|
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
|
||||||
|
import net.psforever.objects.serverobject.structures.StructureType
|
||||||
import net.psforever.objects.vehicles.Seat
|
import net.psforever.objects.vehicles.Seat
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
||||||
import objects.ActorTest
|
import objects.ActorTest
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
@ -44,7 +45,7 @@ class ImplantTerminalMechTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"get passenger in a seat" in {
|
"get passenger in a seat" in {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
|
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
|
||||||
obj.PassengerInSeat(player) mustEqual None
|
obj.PassengerInSeat(player) mustEqual None
|
||||||
obj.Seats(0).Occupant = player
|
obj.Seats(0).Occupant = player
|
||||||
|
|
@ -89,7 +90,7 @@ class ImplantTerminalMechControl3Test extends ActorTest() {
|
||||||
"ImplantTerminalMechControl" should {
|
"ImplantTerminalMechControl" should {
|
||||||
"block a player from mounting" in {
|
"block a player from mounting" in {
|
||||||
val (player1, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
|
val (player1, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||||
val player2 = Player("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player2 = Player(Avatar("test2", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
|
|
||||||
mech.Actor ! Mountable.TryMount(player1, 0)
|
mech.Actor ! Mountable.TryMount(player1, 0)
|
||||||
receiveOne(Duration.create(100, "ms")) //consume reply
|
receiveOne(Duration.create(100, "ms")) //consume reply
|
||||||
|
|
@ -160,9 +161,9 @@ object ImplantTerminalMechTest {
|
||||||
|
|
||||||
val terminal = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
|
val terminal = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
|
||||||
terminal.Actor = system.actorOf(Props(classOf[ImplantTerminalMechControl], terminal), "mech")
|
terminal.Actor = system.actorOf(Props(classOf[ImplantTerminalMechControl], terminal), "mech")
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = faction
|
terminal.Owner.Faction = faction
|
||||||
terminal.GUID = PlanetSideGUID(1)
|
terminal.GUID = PlanetSideGUID(1)
|
||||||
(Player("test", faction, CharacterGender.Male, 0, 0), terminal)
|
(Player(Avatar("test", faction, CharacterGender.Male, 0, 0)), terminal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal}
|
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Vehicle}
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
@ -22,12 +22,18 @@ class MatrixTerminalTest extends Specification {
|
||||||
b.Name mustEqual "matrix_terminalb"
|
b.Name mustEqual "matrix_terminalb"
|
||||||
}
|
}
|
||||||
|
|
||||||
"define (b)" in {
|
"define (c)" in {
|
||||||
val b = new MatrixTerminalDefinition(519)
|
val b = new MatrixTerminalDefinition(519)
|
||||||
b.ObjectId mustEqual 519
|
b.ObjectId mustEqual 519
|
||||||
b.Name mustEqual "matrix_terminalc"
|
b.Name mustEqual "matrix_terminalc"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
"define (d)" in {
|
||||||
|
val b = new MatrixTerminalDefinition(812)
|
||||||
|
b.ObjectId mustEqual 812
|
||||||
|
b.Name mustEqual "spawn_terminal"
|
||||||
|
}
|
||||||
|
|
||||||
"define (invalid)" in {
|
"define (invalid)" in {
|
||||||
var id : Int = (math.random * Int.MaxValue).toInt
|
var id : Int = (math.random * Int.MaxValue).toInt
|
||||||
if(id == 517) {
|
if(id == 517) {
|
||||||
|
|
@ -36,7 +42,7 @@ class MatrixTerminalTest extends Specification {
|
||||||
else if(id == 518) {
|
else if(id == 518) {
|
||||||
id += 2
|
id += 2
|
||||||
}
|
}
|
||||||
else if(id == 519) {
|
else if(id == 519 | id == 812) {
|
||||||
id += 1
|
id += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +60,7 @@ class MatrixTerminalTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"player can not buy (anything)" in {
|
"player can not buy (anything)" in {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
|
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
|
||||||
|
|
||||||
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
|
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.serverobject.terminals.{OrderTerminalABDefinition, Terminal}
|
import net.psforever.objects.serverobject.terminals.{OrderTerminalABDefinition, Terminal}
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
@ -39,7 +39,7 @@ class OrderTerminalABTest extends Specification {
|
||||||
|
|
||||||
"Order_Terminal" should {
|
"Order_Terminal" should {
|
||||||
val terminal = Terminal(GlobalDefinitions.order_terminala)
|
val terminal = Terminal(GlobalDefinitions.order_terminala)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
@ -47,14 +47,14 @@ class OrderTerminalABTest extends Specification {
|
||||||
}
|
}
|
||||||
|
|
||||||
"player can buy different armor ('lite_armor')" in {
|
"player can buy different armor ('lite_armor')" in {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
|
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "lite_armor", 0, PlanetSideGUID(0))
|
||||||
|
|
||||||
terminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile)
|
terminal.Request(player, msg) mustEqual Terminal.BuyExosuit(ExoSuitType.Agile)
|
||||||
}
|
}
|
||||||
|
|
||||||
"player can buy max armor ('trhev_antiaircraft')" in {
|
"player can buy max armor ('trhev_antiaircraft')" in {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "trhev_antiaircraft", 0, PlanetSideGUID(0))
|
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 1, "trhev_antiaircraft", 0, PlanetSideGUID(0))
|
||||||
|
|
||||||
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
|
terminal.Request(player, msg) mustEqual Terminal.NoDeal()
|
||||||
|
|
@ -62,10 +62,11 @@ class OrderTerminalABTest extends Specification {
|
||||||
//TODO loudout tests
|
//TODO loudout tests
|
||||||
|
|
||||||
"player can not load max loadout" in {
|
"player can not load max loadout" in {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val avatar = Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
||||||
player.SaveLoadout("test1", 0)
|
val player = Player(avatar)
|
||||||
|
avatar.SaveLoadout(player, "test1", 0)
|
||||||
player.ExoSuit = ExoSuitType.MAX
|
player.ExoSuit = ExoSuitType.MAX
|
||||||
player.SaveLoadout("test2", 1)
|
avatar.SaveLoadout(player, "test2", 1)
|
||||||
|
|
||||||
val msg1 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.InfantryLoadout, 4, "", 0, PlanetSideGUID(0))
|
val msg1 = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.InfantryLoadout, 4, "", 0, PlanetSideGUID(0))
|
||||||
terminal.Request(player, msg1) mustEqual Terminal.InfantryLoadout(ExoSuitType.Standard, 0, Nil, Nil)
|
terminal.Request(player, msg1) mustEqual Terminal.InfantryLoadout(ExoSuitType.Standard, 0, Nil, Nil)
|
||||||
|
|
|
||||||
|
|
@ -2,19 +2,19 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.{AmmoBox, GlobalDefinitions, Player, Tool}
|
import net.psforever.objects.{AmmoBox, Avatar, GlobalDefinitions, Player, Tool}
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import org.specs2.mutable.Specification
|
import org.specs2.mutable.Specification
|
||||||
|
|
||||||
class OrderTerminalTest extends Specification {
|
class OrderTerminalTest extends Specification {
|
||||||
"Order_Terminal" should {
|
"Order_Terminal" should {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val terminal = Terminal(GlobalDefinitions.order_terminal)
|
val terminal = Terminal(GlobalDefinitions.order_terminal)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.{ActorSystem, Props}
|
import akka.actor.{ActorSystem, Props}
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl, TerminalDefinition}
|
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl, TerminalDefinition}
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
import net.psforever.types._
|
import net.psforever.types._
|
||||||
import objects.ActorTest
|
import objects.ActorTest
|
||||||
|
|
@ -122,8 +122,8 @@ object TerminalControlTest {
|
||||||
def SetUpAgents(tdef : TerminalDefinition, faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, Terminal) = {
|
def SetUpAgents(tdef : TerminalDefinition, faction : PlanetSideEmpire.Value)(implicit system : ActorSystem) : (Player, Terminal) = {
|
||||||
val terminal = Terminal(tdef)
|
val terminal = Terminal(tdef)
|
||||||
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-term")
|
terminal.Actor = system.actorOf(Props(classOf[TerminalControl], terminal), "test-term")
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = faction
|
terminal.Owner.Faction = faction
|
||||||
(Player("test", faction, CharacterGender.Male, 0, 0), terminal)
|
(Player(Avatar("test", faction, CharacterGender.Male, 0, 0)), terminal)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
package objects.terminal
|
package objects.terminal
|
||||||
|
|
||||||
import akka.actor.ActorRef
|
import akka.actor.ActorRef
|
||||||
import net.psforever.objects.serverobject.structures.Building
|
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||||
import net.psforever.objects.{GlobalDefinitions, Player}
|
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||||
|
|
@ -12,9 +12,9 @@ import org.specs2.mutable.Specification
|
||||||
|
|
||||||
class VehicleTerminalCombinedTest extends Specification {
|
class VehicleTerminalCombinedTest extends Specification {
|
||||||
"Ground_Vehicle_Terminal" should {
|
"Ground_Vehicle_Terminal" should {
|
||||||
val player = Player("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0)
|
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, 0))
|
||||||
val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined)
|
val terminal = Terminal(GlobalDefinitions.vehicle_terminal_combined)
|
||||||
terminal.Owner = new Building(0, Zone.Nowhere)
|
terminal.Owner = new Building(0, Zone.Nowhere, StructureType.Building)
|
||||||
terminal.Owner.Faction = PlanetSideEmpire.TR
|
terminal.Owner.Faction = PlanetSideEmpire.TR
|
||||||
|
|
||||||
"construct" in {
|
"construct" in {
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
import net.psforever.objects.zones.ZoneMap
|
import net.psforever.objects.zones.ZoneMap
|
||||||
import net.psforever.objects.GlobalDefinitions._
|
import net.psforever.objects.GlobalDefinitions._
|
||||||
import net.psforever.objects.serverobject.ServerObjectBuilder
|
|
||||||
import net.psforever.objects.serverobject.doors.Door
|
import net.psforever.objects.serverobject.doors.Door
|
||||||
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
|
||||||
import net.psforever.objects.serverobject.locks.IFFLock
|
import net.psforever.objects.serverobject.locks.IFFLock
|
||||||
import net.psforever.objects.serverobject.mblocker.Locker
|
import net.psforever.objects.serverobject.mblocker.Locker
|
||||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, WarpGate}
|
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType, WarpGate}
|
||||||
import net.psforever.objects.serverobject.terminals.Terminal
|
import net.psforever.objects.serverobject.terminals.Terminal
|
||||||
|
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||||
import net.psforever.types.Vector3
|
import net.psforever.types.Vector3
|
||||||
|
|
||||||
object Maps {
|
object Maps {
|
||||||
|
|
@ -23,16 +23,362 @@ object Maps {
|
||||||
val map5 = new ZoneMap("map05")
|
val map5 = new ZoneMap("map05")
|
||||||
|
|
||||||
val map6 = new ZoneMap("map06") {
|
val map6 = new ZoneMap("map06") {
|
||||||
//TODO TEST ceryshen
|
Building2()
|
||||||
LocalObject(ServerObjectBuilder(3353, Terminal.Constructor(ground_vehicle_terminal)))
|
Building38()
|
||||||
LocalObject(ServerObjectBuilder(500,
|
Building42()
|
||||||
VehicleSpawnPad.Constructor(Vector3(3962.0f, 4334.0f, 268.0f), Vector3(0f, 0f, 180.0f))
|
Building48()
|
||||||
)) //TODO guid not correct
|
Building49()
|
||||||
|
|
||||||
LocalBuilding(2, FoundationBuilder(Building.Structure))
|
def Building2() : Unit = {
|
||||||
ObjectToBuilding(3353, 2)
|
//Anguta
|
||||||
ObjectToBuilding(500, 2)
|
LocalBuilding(2, FoundationBuilder(Building.Structure(StructureType.Facility, Vector3(3974.2344f, 4287.914f, 0))))
|
||||||
TerminalToSpawnPad(3353, 500)
|
LocalObject(222, Door.Constructor) //air term building, bay door
|
||||||
|
LocalObject(370, Door.Constructor) //courtyard
|
||||||
|
LocalObject(371, Door.Constructor) //courtyard
|
||||||
|
LocalObject(372, Door.Constructor) //courtyard
|
||||||
|
LocalObject(373, Door.Constructor) //courtyard
|
||||||
|
LocalObject(375, Door.Constructor(Vector3(3924.0f, 4231.2656f, 271.82812f), Vector3(0, 0, 180))) //2nd level door, south
|
||||||
|
LocalObject(376, Door.Constructor(Vector3(3924.0f, 4240.2656f, 271.82812f), Vector3(0, 0, 0))) //2nd level door, north
|
||||||
|
LocalObject(383, Door.Constructor) //courtyard
|
||||||
|
LocalObject(384, Door.Constructor(Vector3(3939.6328f, 4232.547f, 279.26562f), Vector3(0, 0, 270))) //3rd floor door
|
||||||
|
LocalObject(385, Door.Constructor) //courtyard
|
||||||
|
LocalObject(387, Door.Constructor(Vector3(3951.9531f, 4260.008f, 271.82812f), Vector3(0, 0, 270))) //2nd level door, stairwell
|
||||||
|
LocalObject(391, Door.Constructor) //courtyard
|
||||||
|
LocalObject(393, Door.Constructor(Vector3(3997.8984f, 4344.3203f, 271.8125f), Vector3(0, 0, 0))) //air term building, upstairs door
|
||||||
|
LocalObject(394, Door.Constructor(Vector3(3999.9766f, 4314.3203f, 266.82812f), Vector3(0, 0, 270))) //air term building, f.door
|
||||||
|
LocalObject(396, Door.Constructor) //courtyard
|
||||||
|
LocalObject(398, Door.Constructor) //courtyard
|
||||||
|
LocalObject(399, Door.Constructor) //courtyard
|
||||||
|
LocalObject(402, Door.Constructor) //courtyard
|
||||||
|
LocalObject(403, Door.Constructor) //courtyard
|
||||||
|
LocalObject(404, Door.Constructor(Vector3(4060.0078f, 4319.9766f, 266.8125f), Vector3(0, 0, 0))) //b.door
|
||||||
|
LocalObject(603, Door.Constructor)
|
||||||
|
LocalObject(604, Door.Constructor)
|
||||||
|
LocalObject(605, Door.Constructor)
|
||||||
|
LocalObject(606, Door.Constructor)
|
||||||
|
LocalObject(607, Door.Constructor)
|
||||||
|
LocalObject(610, Door.Constructor)
|
||||||
|
LocalObject(611, Door.Constructor)
|
||||||
|
LocalObject(614, Door.Constructor)
|
||||||
|
LocalObject(619, Door.Constructor)
|
||||||
|
LocalObject(620, Door.Constructor(Vector3(3983.9531f, 4299.992f, 249.29688f), Vector3(0, 0, 90))) //generator room door
|
||||||
|
LocalObject(621, Door.Constructor)
|
||||||
|
LocalObject(622, Door.Constructor(Vector3(3988.0078f, 4248.0156f, 256.82812f), Vector3(0, 0, 180))) //spawn room door
|
||||||
|
LocalObject(623, Door.Constructor(Vector3(3988.0078f, 4271.9766f, 256.79688f), Vector3(0, 0, 0))) //spawn room door
|
||||||
|
LocalObject(630, Door.Constructor(Vector3(4000.0078f, 4252.0f, 249.29688f), Vector3(0, 0, 270))) //spawn room door
|
||||||
|
LocalObject(631, Door.Constructor) //spawn room door, kitchen
|
||||||
|
LocalObject(634, Door.Constructor) //air term building, interior
|
||||||
|
LocalObject(638, Door.Constructor(Vector3(4016.0078f, 4212.008f, 249.29688f), Vector3(0, 0, 270))) //cc door
|
||||||
|
LocalObject(642, Door.Constructor(Vector3(4023.9844f, 4212.008f, 249.32812f), Vector3(0, 0, 90))) //cc door, interior
|
||||||
|
LocalObject(643, Door.Constructor) //cc door, exterior
|
||||||
|
LocalObject(645, Door.Constructor) //b.door, interior
|
||||||
|
LocalObject(646, Door.Constructor) //b.door, interior
|
||||||
|
LocalObject(715, Door.Constructor(Vector3(3961.5938f ,4235.8125f, 266.84375f), Vector3(0, 0, 90))) //f.door
|
||||||
|
LocalObject(751, IFFLock.Constructor)
|
||||||
|
LocalObject(860, IFFLock.Constructor)
|
||||||
|
LocalObject(863, IFFLock.Constructor)
|
||||||
|
LocalObject(866, IFFLock.Constructor)
|
||||||
|
LocalObject(868, IFFLock.Constructor)
|
||||||
|
LocalObject(873, IFFLock.Constructor)
|
||||||
|
LocalObject(874, IFFLock.Constructor)
|
||||||
|
LocalObject(875, IFFLock.Constructor)
|
||||||
|
LocalObject(876, IFFLock.Constructor)
|
||||||
|
LocalObject(878, IFFLock.Constructor)
|
||||||
|
LocalObject(879, IFFLock.Constructor)
|
||||||
|
LocalObject(882, IFFLock.Constructor)
|
||||||
|
LocalObject(884, IFFLock.Constructor)
|
||||||
|
LocalObject(885, IFFLock.Constructor)
|
||||||
|
LocalObject(1177, Locker.Constructor)
|
||||||
|
LocalObject(1178, Locker.Constructor)
|
||||||
|
LocalObject(1179, Locker.Constructor)
|
||||||
|
LocalObject(1180, Locker.Constructor)
|
||||||
|
LocalObject(1181, Locker.Constructor)
|
||||||
|
LocalObject(1182, Locker.Constructor)
|
||||||
|
LocalObject(1183, Locker.Constructor)
|
||||||
|
LocalObject(1184, Locker.Constructor)
|
||||||
|
LocalObject(1185, Locker.Constructor)
|
||||||
|
LocalObject(1186, Locker.Constructor)
|
||||||
|
LocalObject(1187, Locker.Constructor)
|
||||||
|
LocalObject(1188, Locker.Constructor)
|
||||||
|
LocalObject(1564, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1568, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1569, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1570, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1571, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1576, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1577, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1578, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(2145, SpawnTube.Constructor(Vector3(3980.4062f, 4252.7656f, 257.5625f), Vector3(0, 0, 90)))
|
||||||
|
LocalObject(2146, SpawnTube.Constructor(Vector3(3980.4062f, 4259.992f, 257.5625f), Vector3(0, 0, 90)))
|
||||||
|
LocalObject(2147, SpawnTube.Constructor(Vector3(3980.4062f, 4267.3047f, 257.5625f), Vector3(0, 0, 90)))
|
||||||
|
LocalObject(2239, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2244, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2245, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2246, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2248, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2250, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2251, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2253, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2254, Terminal.Constructor(spawn_terminal))
|
||||||
|
LocalObject(2322, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(2323, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(2324, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(2419, Terminal.Constructor(ground_vehicle_terminal))
|
||||||
|
LocalObject(500,
|
||||||
|
VehicleSpawnPad.Constructor(Vector3(3962.0f, 4334.0f, 267.75f), Vector3(0f, 0f, 180.0f))
|
||||||
|
) //TODO guid not correct
|
||||||
|
LocalObject(224, Terminal.Constructor(dropship_vehicle_terminal))
|
||||||
|
LocalObject(501,
|
||||||
|
VehicleSpawnPad.Constructor(Vector3(4012.3594f, 4364.8047f, 271.90625f), Vector3(0f, 0f, 180.0f))
|
||||||
|
) //TODO guid not correct
|
||||||
|
ObjectToBuilding(222, 2)
|
||||||
|
ObjectToBuilding(224, 2)
|
||||||
|
ObjectToBuilding(370, 2)
|
||||||
|
ObjectToBuilding(371, 2)
|
||||||
|
ObjectToBuilding(372, 2)
|
||||||
|
ObjectToBuilding(373, 2)
|
||||||
|
ObjectToBuilding(375, 2)
|
||||||
|
ObjectToBuilding(376, 2)
|
||||||
|
ObjectToBuilding(383, 2)
|
||||||
|
ObjectToBuilding(384, 2)
|
||||||
|
ObjectToBuilding(385, 2)
|
||||||
|
ObjectToBuilding(387, 2)
|
||||||
|
ObjectToBuilding(391, 2)
|
||||||
|
ObjectToBuilding(393, 2)
|
||||||
|
ObjectToBuilding(394, 2)
|
||||||
|
ObjectToBuilding(396, 2)
|
||||||
|
ObjectToBuilding(398, 2)
|
||||||
|
ObjectToBuilding(399, 2)
|
||||||
|
ObjectToBuilding(402, 2)
|
||||||
|
ObjectToBuilding(403, 2)
|
||||||
|
ObjectToBuilding(404, 2)
|
||||||
|
ObjectToBuilding(603, 2)
|
||||||
|
ObjectToBuilding(604, 2)
|
||||||
|
ObjectToBuilding(605, 2)
|
||||||
|
ObjectToBuilding(606, 2)
|
||||||
|
ObjectToBuilding(607, 2)
|
||||||
|
ObjectToBuilding(610, 2)
|
||||||
|
ObjectToBuilding(611, 2)
|
||||||
|
ObjectToBuilding(614, 2)
|
||||||
|
ObjectToBuilding(619, 2)
|
||||||
|
ObjectToBuilding(620, 2)
|
||||||
|
ObjectToBuilding(621, 2)
|
||||||
|
ObjectToBuilding(622, 2)
|
||||||
|
ObjectToBuilding(623, 2)
|
||||||
|
ObjectToBuilding(630, 2)
|
||||||
|
ObjectToBuilding(631, 2)
|
||||||
|
ObjectToBuilding(634, 2)
|
||||||
|
ObjectToBuilding(638, 2)
|
||||||
|
ObjectToBuilding(642, 2)
|
||||||
|
ObjectToBuilding(643, 2)
|
||||||
|
ObjectToBuilding(645, 2)
|
||||||
|
ObjectToBuilding(646, 2)
|
||||||
|
ObjectToBuilding(715, 2)
|
||||||
|
ObjectToBuilding(751, 2)
|
||||||
|
ObjectToBuilding(860, 2)
|
||||||
|
ObjectToBuilding(863, 2)
|
||||||
|
ObjectToBuilding(866, 2)
|
||||||
|
ObjectToBuilding(868, 2)
|
||||||
|
ObjectToBuilding(873, 2)
|
||||||
|
ObjectToBuilding(874, 2)
|
||||||
|
ObjectToBuilding(875, 2)
|
||||||
|
ObjectToBuilding(876, 2)
|
||||||
|
ObjectToBuilding(878, 2)
|
||||||
|
ObjectToBuilding(879, 2)
|
||||||
|
ObjectToBuilding(882, 2)
|
||||||
|
ObjectToBuilding(884, 2)
|
||||||
|
ObjectToBuilding(885, 2)
|
||||||
|
ObjectToBuilding(1177, 2)
|
||||||
|
ObjectToBuilding(1178, 2)
|
||||||
|
ObjectToBuilding(1179, 2)
|
||||||
|
ObjectToBuilding(1180, 2)
|
||||||
|
ObjectToBuilding(1181, 2)
|
||||||
|
ObjectToBuilding(1182, 2)
|
||||||
|
ObjectToBuilding(1183, 2)
|
||||||
|
ObjectToBuilding(1184, 2)
|
||||||
|
ObjectToBuilding(1185, 2)
|
||||||
|
ObjectToBuilding(1186, 2)
|
||||||
|
ObjectToBuilding(1187, 2)
|
||||||
|
ObjectToBuilding(1188, 2)
|
||||||
|
ObjectToBuilding(1564, 2)
|
||||||
|
ObjectToBuilding(1568, 2)
|
||||||
|
ObjectToBuilding(1569, 2)
|
||||||
|
ObjectToBuilding(1570, 2)
|
||||||
|
ObjectToBuilding(1571, 2)
|
||||||
|
ObjectToBuilding(1576, 2)
|
||||||
|
ObjectToBuilding(1577, 2)
|
||||||
|
ObjectToBuilding(1578, 2)
|
||||||
|
ObjectToBuilding(2145, 2)
|
||||||
|
ObjectToBuilding(2146, 2)
|
||||||
|
ObjectToBuilding(2147, 2)
|
||||||
|
ObjectToBuilding(2239, 2)
|
||||||
|
ObjectToBuilding(2244, 2)
|
||||||
|
ObjectToBuilding(2245, 2)
|
||||||
|
ObjectToBuilding(2246, 2)
|
||||||
|
ObjectToBuilding(2248, 2)
|
||||||
|
ObjectToBuilding(2250, 2)
|
||||||
|
ObjectToBuilding(2251, 2)
|
||||||
|
ObjectToBuilding(2253, 2)
|
||||||
|
ObjectToBuilding(2254, 2)
|
||||||
|
ObjectToBuilding(2322, 2)
|
||||||
|
ObjectToBuilding(2323, 2)
|
||||||
|
ObjectToBuilding(2324, 2)
|
||||||
|
ObjectToBuilding(2419, 2)
|
||||||
|
ObjectToBuilding(500, 2)
|
||||||
|
ObjectToBuilding(501, 2)
|
||||||
|
DoorToLock(375, 863)
|
||||||
|
DoorToLock(376, 860)
|
||||||
|
DoorToLock(384, 866)
|
||||||
|
DoorToLock(387, 868)
|
||||||
|
DoorToLock(393, 876)
|
||||||
|
DoorToLock(394, 879)
|
||||||
|
DoorToLock(404, 885)
|
||||||
|
DoorToLock(620, 873)
|
||||||
|
DoorToLock(622, 876)
|
||||||
|
DoorToLock(623, 874)
|
||||||
|
DoorToLock(630, 878)
|
||||||
|
DoorToLock(638, 882)
|
||||||
|
DoorToLock(642, 884)
|
||||||
|
DoorToLock(715, 751)
|
||||||
|
TerminalToSpawnPad(224, 501)
|
||||||
|
TerminalToSpawnPad(2419, 500)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Building38() : Unit = {
|
||||||
|
//Anguta, West Bunker
|
||||||
|
LocalBuilding(38, FoundationBuilder(Building.Structure(StructureType.Bunker)))
|
||||||
|
LocalObject(362, Door.Constructor)
|
||||||
|
ObjectToBuilding(362, 38)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Building42() : Unit = {
|
||||||
|
//Anguta, East Bunker(s)
|
||||||
|
LocalBuilding(42, FoundationBuilder(Building.Structure(StructureType.Bunker)))
|
||||||
|
LocalObject(407, Door.Constructor)
|
||||||
|
LocalObject(408, Door.Constructor)
|
||||||
|
ObjectToBuilding(407, 42)
|
||||||
|
ObjectToBuilding(408, 42)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Building48() : Unit = {
|
||||||
|
//North Anguta Watchtower
|
||||||
|
LocalBuilding(48, FoundationBuilder(Building.Structure(StructureType.Tower, Vector3(3864.2266f, 4518.0234f, 0))))
|
||||||
|
LocalObject(364, Door.Constructor(Vector3(3871.9688f, 4509.992f, 269.65625f), Vector3(0f, 0f, 180f))) //s1
|
||||||
|
LocalObject(365, Door.Constructor(Vector3(3871.9688f, 4509.992f, 279.57812f), Vector3(0f, 0f, 180f))) //s2
|
||||||
|
LocalObject(366, Door.Constructor(Vector3(3871.9688f, 4509.992f, 299.57812f), Vector3(0f, 0f, 180f))) //s3
|
||||||
|
LocalObject(367, Door.Constructor(Vector3(3871.9688f, 4525.9844f, 269.65625f), Vector3(0f, 0f, 0f))) //n1
|
||||||
|
LocalObject(368, Door.Constructor(Vector3(3871.9688f, 4525.9844f, 279.57812f), Vector3(0f, 0f, 0f))) //n2
|
||||||
|
LocalObject(369, Door.Constructor(Vector3(3871.9688f, 4525.9844f, 299.57812f), Vector3(0f, 0f, 0f))) //n3
|
||||||
|
LocalObject(854, IFFLock.Constructor)
|
||||||
|
LocalObject(855, IFFLock.Constructor)
|
||||||
|
LocalObject(856, IFFLock.Constructor)
|
||||||
|
LocalObject(857, IFFLock.Constructor)
|
||||||
|
LocalObject(858, IFFLock.Constructor)
|
||||||
|
LocalObject(859, IFFLock.Constructor)
|
||||||
|
LocalObject(1140, Locker.Constructor)
|
||||||
|
LocalObject(1141, Locker.Constructor)
|
||||||
|
LocalObject(1142, Locker.Constructor)
|
||||||
|
LocalObject(1143, Locker.Constructor)
|
||||||
|
LocalObject(1144, Locker.Constructor)
|
||||||
|
LocalObject(1145, Locker.Constructor)
|
||||||
|
LocalObject(1146, Locker.Constructor)
|
||||||
|
LocalObject(1147, Locker.Constructor)
|
||||||
|
LocalObject(1561, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1562, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1563, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(2138, SpawnTube.Constructor(respawn_tube_tower, Vector3(3870.9688f, 4505.7266f, 259.875f), Vector3(0, 0, 90)))
|
||||||
|
LocalObject(2139, SpawnTube.Constructor(respawn_tube_tower, Vector3(3870.9688f, 4522.1562f, 259.875f), Vector3(0, 0, 90)))
|
||||||
|
LocalObject(2315, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(2316, Door.Constructor) //spawn tube door
|
||||||
|
ObjectToBuilding(364, 48)
|
||||||
|
ObjectToBuilding(365, 48)
|
||||||
|
ObjectToBuilding(366, 48)
|
||||||
|
ObjectToBuilding(367, 48)
|
||||||
|
ObjectToBuilding(368, 48)
|
||||||
|
ObjectToBuilding(369, 48)
|
||||||
|
ObjectToBuilding(854, 48)
|
||||||
|
ObjectToBuilding(855, 48)
|
||||||
|
ObjectToBuilding(856, 48)
|
||||||
|
ObjectToBuilding(857, 48)
|
||||||
|
ObjectToBuilding(858, 48)
|
||||||
|
ObjectToBuilding(859, 48)
|
||||||
|
ObjectToBuilding(1140, 48)
|
||||||
|
ObjectToBuilding(1141, 48)
|
||||||
|
ObjectToBuilding(1142, 48)
|
||||||
|
ObjectToBuilding(1143, 48)
|
||||||
|
ObjectToBuilding(1144, 48)
|
||||||
|
ObjectToBuilding(1145, 48)
|
||||||
|
ObjectToBuilding(1146, 48)
|
||||||
|
ObjectToBuilding(1147, 48)
|
||||||
|
ObjectToBuilding(1561, 48)
|
||||||
|
ObjectToBuilding(1562, 48)
|
||||||
|
ObjectToBuilding(1563, 48)
|
||||||
|
ObjectToBuilding(2138, 48)
|
||||||
|
ObjectToBuilding(2139, 48)
|
||||||
|
ObjectToBuilding(2315, 48)
|
||||||
|
ObjectToBuilding(2316, 48)
|
||||||
|
DoorToLock(364, 857)
|
||||||
|
DoorToLock(365, 858)
|
||||||
|
DoorToLock(366, 859)
|
||||||
|
DoorToLock(367, 854)
|
||||||
|
DoorToLock(368, 855)
|
||||||
|
DoorToLock(369, 856)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Building49() : Unit = {
|
||||||
|
//North Akna Air Tower
|
||||||
|
LocalBuilding(49, FoundationBuilder(Building.Structure(StructureType.Tower, Vector3(4358.3203f, 3989.5625f, 0))))
|
||||||
|
LocalObject(430, Door.Constructor(Vector3(4366.0156f, 3981.9922f, 237.96875f), Vector3(0f, 0f, 180f))) //s1
|
||||||
|
LocalObject(431, Door.Constructor(Vector3(4366.0156f, 3981.9922f, 257.89062f), Vector3(0f, 0f, 180f))) //s2
|
||||||
|
LocalObject(432, Door.Constructor(Vector3(4366.0156f, 3997.9297f, 237.96875f), Vector3(0f, 0f, 0f))) //n1
|
||||||
|
LocalObject(433, Door.Constructor(Vector3(4366.0156f, 3997.9297f, 257.89062f), Vector3(0f, 0f, 0f))) //n2
|
||||||
|
LocalObject(902, IFFLock.Constructor)
|
||||||
|
LocalObject(903, IFFLock.Constructor)
|
||||||
|
LocalObject(906, IFFLock.Constructor)
|
||||||
|
LocalObject(907, IFFLock.Constructor)
|
||||||
|
LocalObject(1217, Locker.Constructor)
|
||||||
|
LocalObject(1218, Locker.Constructor)
|
||||||
|
LocalObject(1219, Locker.Constructor)
|
||||||
|
LocalObject(1220, Locker.Constructor)
|
||||||
|
LocalObject(1225, Locker.Constructor)
|
||||||
|
LocalObject(1226, Locker.Constructor)
|
||||||
|
LocalObject(1227, Locker.Constructor)
|
||||||
|
LocalObject(1228, Locker.Constructor)
|
||||||
|
LocalObject(1591, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1592, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1593, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(2156, SpawnTube.Constructor(respawn_tube_tower, Vector3(4364.633f, 3994.125f, 228.1875f), Vector3(0, 0, 90)))
|
||||||
|
LocalObject(2157, SpawnTube.Constructor(respawn_tube_tower, Vector3(4364.633f, 3977.7266f, 228.1875f), Vector3(0, 0, 90)))
|
||||||
|
LocalObject(2333, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(2334, Door.Constructor) //spawn tube door
|
||||||
|
ObjectToBuilding(430, 49)
|
||||||
|
ObjectToBuilding(431, 49)
|
||||||
|
ObjectToBuilding(432, 49)
|
||||||
|
ObjectToBuilding(433, 49)
|
||||||
|
ObjectToBuilding(902, 49)
|
||||||
|
ObjectToBuilding(903, 49)
|
||||||
|
ObjectToBuilding(906, 49)
|
||||||
|
ObjectToBuilding(907, 49)
|
||||||
|
ObjectToBuilding(1217, 49)
|
||||||
|
ObjectToBuilding(1218, 49)
|
||||||
|
ObjectToBuilding(1219, 49)
|
||||||
|
ObjectToBuilding(1220, 49)
|
||||||
|
ObjectToBuilding(1225, 49)
|
||||||
|
ObjectToBuilding(1226, 49)
|
||||||
|
ObjectToBuilding(1227, 49)
|
||||||
|
ObjectToBuilding(1228, 49)
|
||||||
|
ObjectToBuilding(1591, 49)
|
||||||
|
ObjectToBuilding(1592, 49)
|
||||||
|
ObjectToBuilding(1593, 49)
|
||||||
|
ObjectToBuilding(2156, 49)
|
||||||
|
ObjectToBuilding(2157, 49)
|
||||||
|
ObjectToBuilding(2333, 49)
|
||||||
|
ObjectToBuilding(2334, 49)
|
||||||
|
DoorToLock(430, 906)
|
||||||
|
DoorToLock(431, 907)
|
||||||
|
DoorToLock(432, 902)
|
||||||
|
DoorToLock(433, 903)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val map7 = new ZoneMap("map07")
|
val map7 = new ZoneMap("map07")
|
||||||
|
|
@ -48,154 +394,241 @@ object Maps {
|
||||||
val map12 = new ZoneMap("map12")
|
val map12 = new ZoneMap("map12")
|
||||||
|
|
||||||
val map13 = new ZoneMap("map13") {
|
val map13 = new ZoneMap("map13") {
|
||||||
LocalBuilding(1, FoundationBuilder(WarpGate.Structure))
|
Building1()
|
||||||
LocalBuilding(2, FoundationBuilder(WarpGate.Structure))
|
Building2()
|
||||||
LocalBuilding(3, FoundationBuilder(WarpGate.Structure))
|
Building3()
|
||||||
|
Building29()
|
||||||
|
Building42()
|
||||||
|
Building51()
|
||||||
|
Building77()
|
||||||
|
|
||||||
LocalObject(ServerObjectBuilder(372, Door.Constructor))
|
def Building1() : Unit = {
|
||||||
LocalObject(ServerObjectBuilder(373, Door.Constructor))
|
//warpgate?
|
||||||
|
LocalBuilding(1, FoundationBuilder(WarpGate.Structure))
|
||||||
|
}
|
||||||
|
|
||||||
LocalObject(ServerObjectBuilder(520, ImplantTerminalMech.Constructor)) //Hart B
|
def Building3() : Unit = {
|
||||||
LocalObject(ServerObjectBuilder(853, Terminal.Constructor(order_terminal)))
|
//warpgate?
|
||||||
LocalObject(ServerObjectBuilder(855, Terminal.Constructor(order_terminal)))
|
LocalBuilding(3, FoundationBuilder(WarpGate.Structure))
|
||||||
LocalObject(ServerObjectBuilder(860, Terminal.Constructor(order_terminal)))
|
}
|
||||||
LocalObject(ServerObjectBuilder(1081, Terminal.Constructor(implant_terminal_interface))) //tube 520
|
|
||||||
TerminalToInterface(520, 1081)
|
|
||||||
|
|
||||||
LocalBuilding(2, FoundationBuilder(Building.Structure)) //HART building C
|
// LocalBuilding(2, FoundationBuilder(WarpGate.Structure)) //TODO might be wrong?
|
||||||
LocalObject(ServerObjectBuilder(186, Terminal.Constructor(cert_terminal)))
|
|
||||||
LocalObject(ServerObjectBuilder(187, Terminal.Constructor(cert_terminal)))
|
|
||||||
LocalObject(ServerObjectBuilder(188, Terminal.Constructor(cert_terminal)))
|
|
||||||
LocalObject(ServerObjectBuilder(362, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(370, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(371, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(374, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(375, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(394, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(395, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(396, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(397, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(398, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(462, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(463, Door.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(522, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(523, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(524, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(525, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(526, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(527, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(528, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(529, ImplantTerminalMech.Constructor)) //Hart C
|
|
||||||
LocalObject(ServerObjectBuilder(686, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(687, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(688, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(689, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(690, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(691, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(692, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(693, Locker.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(842, Terminal.Constructor(order_terminal)))
|
|
||||||
LocalObject(ServerObjectBuilder(843, Terminal.Constructor(order_terminal)))
|
|
||||||
LocalObject(ServerObjectBuilder(844, Terminal.Constructor(order_terminal)))
|
|
||||||
LocalObject(ServerObjectBuilder(845, Terminal.Constructor(order_terminal)))
|
|
||||||
LocalObject(ServerObjectBuilder(1082, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
LocalObject(ServerObjectBuilder(1083, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
LocalObject(ServerObjectBuilder(1084, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
LocalObject(ServerObjectBuilder(1085, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
LocalObject(ServerObjectBuilder(1086, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
LocalObject(ServerObjectBuilder(1087, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
LocalObject(ServerObjectBuilder(1088, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
LocalObject(ServerObjectBuilder(1089, Terminal.Constructor(implant_terminal_interface))) //TODO guid not correct
|
|
||||||
ObjectToBuilding(186, 2)
|
|
||||||
ObjectToBuilding(187, 2)
|
|
||||||
ObjectToBuilding(188, 2)
|
|
||||||
ObjectToBuilding(522, 2)
|
|
||||||
ObjectToBuilding(523, 2)
|
|
||||||
ObjectToBuilding(524, 2)
|
|
||||||
ObjectToBuilding(525, 2)
|
|
||||||
ObjectToBuilding(526, 2)
|
|
||||||
ObjectToBuilding(527, 2)
|
|
||||||
ObjectToBuilding(528, 2)
|
|
||||||
ObjectToBuilding(529, 2)
|
|
||||||
ObjectToBuilding(686, 2)
|
|
||||||
ObjectToBuilding(687, 2)
|
|
||||||
ObjectToBuilding(688, 2)
|
|
||||||
ObjectToBuilding(689, 2)
|
|
||||||
ObjectToBuilding(690, 2)
|
|
||||||
ObjectToBuilding(691, 2)
|
|
||||||
ObjectToBuilding(692, 2)
|
|
||||||
ObjectToBuilding(693, 2)
|
|
||||||
ObjectToBuilding(842, 2)
|
|
||||||
ObjectToBuilding(843, 2)
|
|
||||||
ObjectToBuilding(844, 2)
|
|
||||||
ObjectToBuilding(845, 2)
|
|
||||||
ObjectToBuilding(1082, 2)
|
|
||||||
ObjectToBuilding(1083, 2)
|
|
||||||
ObjectToBuilding(1084, 2)
|
|
||||||
ObjectToBuilding(1085, 2)
|
|
||||||
ObjectToBuilding(1086, 2)
|
|
||||||
ObjectToBuilding(1087, 2)
|
|
||||||
ObjectToBuilding(1088, 2)
|
|
||||||
ObjectToBuilding(1089, 2)
|
|
||||||
TerminalToInterface(522, 1082)
|
|
||||||
TerminalToInterface(523, 1083)
|
|
||||||
TerminalToInterface(524, 1084)
|
|
||||||
TerminalToInterface(525, 1085)
|
|
||||||
TerminalToInterface(526, 1086)
|
|
||||||
TerminalToInterface(527, 1087)
|
|
||||||
TerminalToInterface(528, 1088)
|
|
||||||
TerminalToInterface(529, 1089)
|
|
||||||
|
|
||||||
LocalBuilding(29, FoundationBuilder(Building.Structure)) //South Villa Gun Tower
|
// LocalObject(520, ImplantTerminalMech.Constructor) //Hart B
|
||||||
LocalObject(ServerObjectBuilder(330, Door.Constructor(Vector3(3979.9219f, 2592.0547f, 91.140625f), Vector3(0, 0, 180))))
|
// LocalObject(1081, Terminal.Constructor(implant_terminal_interface)) //tube 520
|
||||||
LocalObject(ServerObjectBuilder(331, Door.Constructor(Vector3(3979.9219f, 2592.0547f, 111.140625f), Vector3(0, 0, 180))))
|
// TerminalToInterface(520, 1081)
|
||||||
LocalObject(ServerObjectBuilder(332, Door.Constructor(Vector3(3979.9688f, 2608.0625f, 91.140625f), Vector3(0, 0, 0))))
|
|
||||||
LocalObject(ServerObjectBuilder(333, Door.Constructor(Vector3(3979.9688f, 2608.0625f, 111.140625f), Vector3(0, 0, 0))))
|
|
||||||
LocalObject(ServerObjectBuilder(556, IFFLock.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(557, IFFLock.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(558, IFFLock.Constructor))
|
|
||||||
LocalObject(ServerObjectBuilder(559, IFFLock.Constructor))
|
|
||||||
ObjectToBuilding(330, 29)
|
|
||||||
ObjectToBuilding(331, 29)
|
|
||||||
ObjectToBuilding(332, 29)
|
|
||||||
ObjectToBuilding(333, 29)
|
|
||||||
ObjectToBuilding(556, 29)
|
|
||||||
ObjectToBuilding(557, 29)
|
|
||||||
ObjectToBuilding(558, 29)
|
|
||||||
ObjectToBuilding(559, 29)
|
|
||||||
DoorToLock(330, 558)
|
|
||||||
DoorToLock(331, 559)
|
|
||||||
DoorToLock(332, 556)
|
|
||||||
DoorToLock(333, 557)
|
|
||||||
|
|
||||||
LocalBuilding(51, FoundationBuilder(Building.Structure))
|
def Building2() : Unit = {
|
||||||
LocalObject(ServerObjectBuilder(304, Terminal.Constructor(dropship_vehicle_terminal)))
|
//HART building C
|
||||||
LocalObject(ServerObjectBuilder(292,
|
LocalBuilding(2, FoundationBuilder(Building.Structure(StructureType.Building)))
|
||||||
VehicleSpawnPad.Constructor(Vector3(3508.9844f, 2895.961f, 92.296875f), Vector3(0f, 0f, 270.0f))
|
LocalObject(186, Terminal.Constructor(cert_terminal))
|
||||||
))
|
LocalObject(187, Terminal.Constructor(cert_terminal))
|
||||||
ObjectToBuilding(304, 51)
|
LocalObject(188, Terminal.Constructor(cert_terminal))
|
||||||
ObjectToBuilding(292, 51)
|
LocalObject(362, Door.Constructor)
|
||||||
TerminalToSpawnPad(304, 292)
|
LocalObject(370, Door.Constructor)
|
||||||
|
LocalObject(371, Door.Constructor)
|
||||||
|
LocalObject(374, Door.Constructor)
|
||||||
|
LocalObject(375, Door.Constructor)
|
||||||
|
LocalObject(394, Door.Constructor)
|
||||||
|
LocalObject(395, Door.Constructor)
|
||||||
|
LocalObject(396, Door.Constructor)
|
||||||
|
LocalObject(397, Door.Constructor)
|
||||||
|
LocalObject(398, Door.Constructor)
|
||||||
|
LocalObject(462, Door.Constructor)
|
||||||
|
LocalObject(463, Door.Constructor)
|
||||||
|
LocalObject(522, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(523, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(524, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(525, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(526, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(527, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(528, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(529, ImplantTerminalMech.Constructor)
|
||||||
|
LocalObject(686, Locker.Constructor)
|
||||||
|
LocalObject(687, Locker.Constructor)
|
||||||
|
LocalObject(688, Locker.Constructor)
|
||||||
|
LocalObject(689, Locker.Constructor)
|
||||||
|
LocalObject(690, Locker.Constructor)
|
||||||
|
LocalObject(691, Locker.Constructor)
|
||||||
|
LocalObject(692, Locker.Constructor)
|
||||||
|
LocalObject(693, Locker.Constructor)
|
||||||
|
LocalObject(842, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(843, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(844, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(845, Terminal.Constructor(order_terminal))
|
||||||
|
LocalObject(1082, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
LocalObject(1083, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
LocalObject(1084, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
LocalObject(1085, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
LocalObject(1086, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
LocalObject(1087, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
LocalObject(1088, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
LocalObject(1089, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct
|
||||||
|
ObjectToBuilding(186, 2)
|
||||||
|
ObjectToBuilding(187, 2)
|
||||||
|
ObjectToBuilding(188, 2)
|
||||||
|
ObjectToBuilding(362, 2)
|
||||||
|
ObjectToBuilding(370, 2)
|
||||||
|
ObjectToBuilding(371, 2)
|
||||||
|
ObjectToBuilding(374, 2)
|
||||||
|
ObjectToBuilding(375, 2)
|
||||||
|
ObjectToBuilding(394, 2)
|
||||||
|
ObjectToBuilding(395, 2)
|
||||||
|
ObjectToBuilding(396, 2)
|
||||||
|
ObjectToBuilding(397, 2)
|
||||||
|
ObjectToBuilding(398, 2)
|
||||||
|
ObjectToBuilding(462, 2)
|
||||||
|
ObjectToBuilding(463, 2)
|
||||||
|
ObjectToBuilding(522, 2)
|
||||||
|
ObjectToBuilding(523, 2)
|
||||||
|
ObjectToBuilding(524, 2)
|
||||||
|
ObjectToBuilding(525, 2)
|
||||||
|
ObjectToBuilding(526, 2)
|
||||||
|
ObjectToBuilding(527, 2)
|
||||||
|
ObjectToBuilding(528, 2)
|
||||||
|
ObjectToBuilding(529, 2)
|
||||||
|
ObjectToBuilding(686, 2)
|
||||||
|
ObjectToBuilding(687, 2)
|
||||||
|
ObjectToBuilding(688, 2)
|
||||||
|
ObjectToBuilding(689, 2)
|
||||||
|
ObjectToBuilding(690, 2)
|
||||||
|
ObjectToBuilding(691, 2)
|
||||||
|
ObjectToBuilding(692, 2)
|
||||||
|
ObjectToBuilding(693, 2)
|
||||||
|
ObjectToBuilding(842, 2)
|
||||||
|
ObjectToBuilding(843, 2)
|
||||||
|
ObjectToBuilding(844, 2)
|
||||||
|
ObjectToBuilding(845, 2)
|
||||||
|
ObjectToBuilding(1082, 2)
|
||||||
|
ObjectToBuilding(1083, 2)
|
||||||
|
ObjectToBuilding(1084, 2)
|
||||||
|
ObjectToBuilding(1085, 2)
|
||||||
|
ObjectToBuilding(1086, 2)
|
||||||
|
ObjectToBuilding(1087, 2)
|
||||||
|
ObjectToBuilding(1088, 2)
|
||||||
|
ObjectToBuilding(1089, 2)
|
||||||
|
TerminalToInterface(522, 1082)
|
||||||
|
TerminalToInterface(523, 1083)
|
||||||
|
TerminalToInterface(524, 1084)
|
||||||
|
TerminalToInterface(525, 1085)
|
||||||
|
TerminalToInterface(526, 1086)
|
||||||
|
TerminalToInterface(527, 1087)
|
||||||
|
TerminalToInterface(528, 1088)
|
||||||
|
TerminalToInterface(529, 1089)
|
||||||
|
}
|
||||||
|
|
||||||
LocalBuilding(77, FoundationBuilder(Building.Structure))
|
def Building29() : Unit = {
|
||||||
LocalObject(ServerObjectBuilder(1063, Terminal.Constructor(ground_vehicle_terminal)))
|
//South Villa Gun Tower
|
||||||
LocalObject(ServerObjectBuilder(706,
|
LocalBuilding(29, FoundationBuilder(Building.Structure(StructureType.Tower)))
|
||||||
VehicleSpawnPad.Constructor(Vector3(3506.0f, 2820.0f, 92.0f), Vector3(0f, 0f, 270.0f))
|
LocalObject(330, Door.Constructor(Vector3(3979.9219f, 2592.0547f, 91.140625f), Vector3(0, 0, 180)))
|
||||||
))
|
LocalObject(331, Door.Constructor(Vector3(3979.9219f, 2592.0547f, 111.140625f), Vector3(0, 0, 180)))
|
||||||
ObjectToBuilding(1063, 77)
|
LocalObject(332, Door.Constructor(Vector3(3979.9688f, 2608.0625f, 91.140625f), Vector3(0, 0, 0)))
|
||||||
ObjectToBuilding(706, 77)
|
LocalObject(333, Door.Constructor(Vector3(3979.9688f, 2608.0625f, 111.140625f), Vector3(0, 0, 0)))
|
||||||
TerminalToSpawnPad(1063, 706)
|
LocalObject(556, IFFLock.Constructor)
|
||||||
|
LocalObject(557, IFFLock.Constructor)
|
||||||
|
LocalObject(558, IFFLock.Constructor)
|
||||||
|
LocalObject(559, IFFLock.Constructor)
|
||||||
|
ObjectToBuilding(330, 29)
|
||||||
|
ObjectToBuilding(331, 29)
|
||||||
|
ObjectToBuilding(332, 29)
|
||||||
|
ObjectToBuilding(333, 29)
|
||||||
|
ObjectToBuilding(556, 29)
|
||||||
|
ObjectToBuilding(557, 29)
|
||||||
|
ObjectToBuilding(558, 29)
|
||||||
|
ObjectToBuilding(559, 29)
|
||||||
|
DoorToLock(330, 558)
|
||||||
|
DoorToLock(331, 559)
|
||||||
|
DoorToLock(332, 556)
|
||||||
|
DoorToLock(333, 557)
|
||||||
|
}
|
||||||
|
|
||||||
ObjectToBuilding(853, 2) //TODO check building_id
|
def Building42() : Unit = {
|
||||||
ObjectToBuilding(855, 2) //TODO check building_id
|
//spawn building south of HART C
|
||||||
ObjectToBuilding(860, 2) //TODO check building_id
|
LocalBuilding(42, FoundationBuilder(Building.Structure(StructureType.Building, Vector3(1, 0, 0))))
|
||||||
|
LocalObject(258, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(259, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(260, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(261, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(262, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(263, Door.Constructor) //spawn tube door
|
||||||
|
LocalObject(372, Door.Constructor) //entrance
|
||||||
|
LocalObject(373, Door.Constructor) //entrance
|
||||||
|
LocalObject(430, Door.Constructor) //vr door
|
||||||
|
LocalObject(431, Door.Constructor) //vr door
|
||||||
|
LocalObject(432, Door.Constructor) //vr door
|
||||||
|
LocalObject(433, Door.Constructor) //vr door
|
||||||
|
LocalObject(434, Door.Constructor) //vr door
|
||||||
|
LocalObject(435, Door.Constructor) //vr door
|
||||||
|
LocalObject(744, SpawnTube.Constructor(Vector3(3684.336f, 2709.0469f, 91.9f), Vector3(0, 0, 180)))
|
||||||
|
LocalObject(745, SpawnTube.Constructor(Vector3(3684.336f, 2713.75f, 91.9f), Vector3(0, 0, 0)))
|
||||||
|
LocalObject(746, SpawnTube.Constructor(Vector3(3690.9062f, 2708.4219f, 91.9f), Vector3(0, 0, 180)))
|
||||||
|
LocalObject(747, SpawnTube.Constructor(Vector3(3691.0703f, 2713.8672f, 91.9f), Vector3(0, 0, 0)))
|
||||||
|
LocalObject(748, SpawnTube.Constructor(Vector3(3697.664f, 2708.3984f, 91.9f), Vector3(0, 0, 180)))
|
||||||
|
LocalObject(749, SpawnTube.Constructor(Vector3(3697.711f, 2713.2344f, 91.9f), Vector3(0, 0, 0)))
|
||||||
|
LocalObject(852, Terminal.Constructor(order_terminal)) //s. wall
|
||||||
|
LocalObject(853, Terminal.Constructor(order_terminal)) //n. wall
|
||||||
|
LocalObject(854, Terminal.Constructor(order_terminal)) //s. wall
|
||||||
|
LocalObject(855, Terminal.Constructor(order_terminal)) //n. wall
|
||||||
|
LocalObject(859, Terminal.Constructor(order_terminal)) //s. wall
|
||||||
|
LocalObject(860, Terminal.Constructor(order_terminal)) //n. wall
|
||||||
|
ObjectToBuilding(258, 42)
|
||||||
|
ObjectToBuilding(259, 42)
|
||||||
|
ObjectToBuilding(260, 42)
|
||||||
|
ObjectToBuilding(261, 42)
|
||||||
|
ObjectToBuilding(262, 42)
|
||||||
|
ObjectToBuilding(263, 42)
|
||||||
|
ObjectToBuilding(372, 42)
|
||||||
|
ObjectToBuilding(373, 42)
|
||||||
|
ObjectToBuilding(430, 42)
|
||||||
|
ObjectToBuilding(431, 42)
|
||||||
|
ObjectToBuilding(432, 42)
|
||||||
|
ObjectToBuilding(433, 42)
|
||||||
|
ObjectToBuilding(434, 42)
|
||||||
|
ObjectToBuilding(435, 42)
|
||||||
|
ObjectToBuilding(744, 42)
|
||||||
|
ObjectToBuilding(745, 42)
|
||||||
|
ObjectToBuilding(746, 42)
|
||||||
|
ObjectToBuilding(747, 42)
|
||||||
|
ObjectToBuilding(748, 42)
|
||||||
|
ObjectToBuilding(749, 42)
|
||||||
|
ObjectToBuilding(852, 42)
|
||||||
|
ObjectToBuilding(853, 42)
|
||||||
|
ObjectToBuilding(854, 42)
|
||||||
|
ObjectToBuilding(855, 42)
|
||||||
|
ObjectToBuilding(859, 42)
|
||||||
|
ObjectToBuilding(860, 42)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Building51() : Unit = {
|
||||||
|
//air terminal west of HART C
|
||||||
|
LocalBuilding(51, FoundationBuilder(Building.Structure(StructureType.Platform)))
|
||||||
|
LocalObject(304, Terminal.Constructor(dropship_vehicle_terminal))
|
||||||
|
LocalObject(292,
|
||||||
|
VehicleSpawnPad.Constructor(Vector3(3508.9844f, 2895.961f, 92.296875f), Vector3(0f, 0f, 270.0f))
|
||||||
|
)
|
||||||
|
ObjectToBuilding(304, 51)
|
||||||
|
ObjectToBuilding(292, 51)
|
||||||
|
TerminalToSpawnPad(304, 292)
|
||||||
|
}
|
||||||
|
|
||||||
|
def Building77() : Unit = {
|
||||||
|
//ground terminal west of HART C
|
||||||
|
LocalBuilding(77, FoundationBuilder(Building.Structure(StructureType.Platform)))
|
||||||
|
LocalObject(1063, Terminal.Constructor(ground_vehicle_terminal))
|
||||||
|
LocalObject(706,
|
||||||
|
VehicleSpawnPad.Constructor(Vector3(3506.0f, 2820.0f, 92.0f), Vector3(0f, 0f, 270.0f))
|
||||||
|
)
|
||||||
|
ObjectToBuilding(1063, 77)
|
||||||
|
ObjectToBuilding(706, 77)
|
||||||
|
TerminalToSpawnPad(1063, 706)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val map14 = new ZoneMap("map13")
|
val map14 = new ZoneMap("map14")
|
||||||
|
|
||||||
val map15 = new ZoneMap("map13")
|
val map15 = new ZoneMap("map15")
|
||||||
|
|
||||||
val map16 = new ZoneMap("map13")
|
val map16 = new ZoneMap("map16")
|
||||||
|
|
||||||
val ugd01 = new ZoneMap("ugd01")
|
val ugd01 = new ZoneMap("ugd01")
|
||||||
|
|
||||||
|
|
@ -209,7 +642,7 @@ object Maps {
|
||||||
|
|
||||||
val ugd06 = new ZoneMap("ugd06")
|
val ugd06 = new ZoneMap("ugd06")
|
||||||
|
|
||||||
val map96 = new ZoneMap("ugd06")
|
val map96 = new ZoneMap("map96")
|
||||||
|
|
||||||
val map97 = new ZoneMap("map97")
|
val map97 = new ZoneMap("map97")
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
import akka.actor.ActorContext
|
import akka.actor.ActorContext
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
|
import net.psforever.types.PlanetSideEmpire
|
||||||
|
|
||||||
object Zones {
|
object Zones {
|
||||||
val z1 = new Zone("z1", Maps.map1, 1)
|
val z1 = new Zone("z1", Maps.map1, 1)
|
||||||
|
|
@ -19,6 +20,13 @@ object Zones {
|
||||||
|
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
Building(2).get.Faction = PlanetSideEmpire.VS
|
Building(2).get.Faction = PlanetSideEmpire.VS
|
||||||
|
Building(2).get.ModelId = 20
|
||||||
|
Building(38).get.ModelId = 0
|
||||||
|
Building(42).get.ModelId = 0
|
||||||
|
Building(48).get.Faction = PlanetSideEmpire.VS
|
||||||
|
Building(48).get.ModelId = 59
|
||||||
|
Building(49).get.Faction = PlanetSideEmpire.VS
|
||||||
|
Building(49).get.ModelId = 69
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -39,7 +47,7 @@ object Zones {
|
||||||
super.Init(context)
|
super.Init(context)
|
||||||
|
|
||||||
import net.psforever.types.PlanetSideEmpire
|
import net.psforever.types.PlanetSideEmpire
|
||||||
Buildings.values.foreach(building => { building.Faction = PlanetSideEmpire.VS })
|
Buildings.values.foreach { _.Faction = PlanetSideEmpire.VS }
|
||||||
Building(29).get.Faction = PlanetSideEmpire.NC //South Villa Gun Tower
|
Building(29).get.Faction = PlanetSideEmpire.NC //South Villa Gun Tower
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -81,4 +89,32 @@ object Zones {
|
||||||
val i3 = new Zone("i3", Maps.map98, 31)
|
val i3 = new Zone("i3", Maps.map98, 31)
|
||||||
|
|
||||||
val i4 = new Zone("i4", Maps.map99, 32)
|
val i4 = new Zone("i4", Maps.map99, 32)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the zone identifier name for the sanctuary continent of a given empire.
|
||||||
|
* @param faction the empire
|
||||||
|
* @return the zone id, with a blank string as an invalidating result
|
||||||
|
*/
|
||||||
|
def SanctuaryZoneId(faction : PlanetSideEmpire.Value) : String = {
|
||||||
|
faction match {
|
||||||
|
case PlanetSideEmpire.NC => "home1"
|
||||||
|
case PlanetSideEmpire.TR => "home2"
|
||||||
|
case PlanetSideEmpire.VS => "home3"
|
||||||
|
case PlanetSideEmpire.NEUTRAL => "" //invalid, not black ops
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the zone number for the sanctuary continent of a given empire.
|
||||||
|
* @param faction the empire
|
||||||
|
* @return the zone number, within the sequence 1-32, and with 0 as an invalidating result
|
||||||
|
*/
|
||||||
|
def SanctuaryZoneNumber(faction : PlanetSideEmpire.Value) : Int = {
|
||||||
|
faction match {
|
||||||
|
case PlanetSideEmpire.NC => 11
|
||||||
|
case PlanetSideEmpire.TR => 12
|
||||||
|
case PlanetSideEmpire.VS => 13
|
||||||
|
case PlanetSideEmpire.NEUTRAL => 0 //invalid, not black ops
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package services.avatar
|
package services.avatar
|
||||||
|
|
||||||
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
||||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||||
import net.psforever.types.{ExoSuitType, Vector3}
|
import net.psforever.types.{ExoSuitType, Vector3}
|
||||||
|
|
@ -24,6 +26,7 @@ object AvatarAction {
|
||||||
final case class ObjectHeld(player_guid : PlanetSideGUID, slot : Int) extends Action
|
final case class ObjectHeld(player_guid : PlanetSideGUID, slot : Int) extends Action
|
||||||
final case class PlanetsideAttribute(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
|
final case class PlanetsideAttribute(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
|
||||||
final case class PlayerState(player_guid : PlanetSideGUID, msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Action
|
final case class PlayerState(player_guid : PlanetSideGUID, msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Action
|
||||||
|
final case class Release(player : Player, zone : Zone, time : Option[Long] = None) extends Action
|
||||||
final case class Reload(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
final case class Reload(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
||||||
final case class WeaponDryFire(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
final case class WeaponDryFire(player_guid : PlanetSideGUID, weapon_guid : PlanetSideGUID) extends Action
|
||||||
// final case class PlayerStateShift(killer : PlanetSideGUID, victim : PlanetSideGUID) extends Action
|
// final case class PlayerStateShift(killer : PlanetSideGUID, victim : PlanetSideGUID) extends Action
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package services.avatar
|
package services.avatar
|
||||||
|
|
||||||
|
import net.psforever.objects.Player
|
||||||
import net.psforever.objects.equipment.Equipment
|
import net.psforever.objects.equipment.Equipment
|
||||||
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
||||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||||
|
|
@ -24,6 +25,7 @@ object AvatarResponse {
|
||||||
final case class ObjectHeld(slot : Int) extends Response
|
final case class ObjectHeld(slot : Int) extends Response
|
||||||
final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response
|
final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response
|
||||||
final case class PlayerState(msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Response
|
final case class PlayerState(msg : PlayerStateMessageUpstream, spectator : Boolean, weaponInHand : Boolean) extends Response
|
||||||
|
final case class Release(player : Player) extends Response
|
||||||
final case class Reload(weapon_guid : PlanetSideGUID) extends Response
|
final case class Reload(weapon_guid : PlanetSideGUID) extends Response
|
||||||
final case class WeaponDryFire(weapon_guid : PlanetSideGUID) extends Response
|
final case class WeaponDryFire(weapon_guid : PlanetSideGUID) extends Response
|
||||||
// final case class PlayerStateShift(itemID : PlanetSideGUID) extends Response
|
// final case class PlayerStateShift(itemID : PlanetSideGUID) extends Response
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,14 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package services.avatar
|
package services.avatar
|
||||||
|
|
||||||
import akka.actor.Actor
|
import akka.actor.{Actor, ActorRef, Props}
|
||||||
|
import services.avatar.support.CorpseRemovalActor
|
||||||
import services.{GenericEventBus, Service}
|
import services.{GenericEventBus, Service}
|
||||||
|
|
||||||
class AvatarService extends Actor {
|
class AvatarService extends Actor {
|
||||||
//import AvatarServiceResponse._
|
private val undertaker : ActorRef = context.actorOf(Props[CorpseRemovalActor], "corpse-removal-agent")
|
||||||
|
undertaker ! "startup"
|
||||||
|
|
||||||
private [this] val log = org.log4s.getLogger
|
private [this] val log = org.log4s.getLogger
|
||||||
|
|
||||||
override def preStart = {
|
override def preStart = {
|
||||||
|
|
@ -87,6 +90,14 @@ class AvatarService extends Actor {
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlayerState(msg, spectator, weapon))
|
AvatarServiceResponse(s"/$forChannel/Avatar", guid, AvatarResponse.PlayerState(msg, spectator, weapon))
|
||||||
)
|
)
|
||||||
|
case AvatarAction.Release(player, zone, time) =>
|
||||||
|
undertaker ! (time match {
|
||||||
|
case Some(t) => CorpseRemovalActor.AddCorpse(player, zone, t)
|
||||||
|
case None => CorpseRemovalActor.AddCorpse(player, zone)
|
||||||
|
})
|
||||||
|
AvatarEvents.publish(
|
||||||
|
AvatarServiceResponse(s"/$forChannel/Avatar", player.GUID, AvatarResponse.Release(player))
|
||||||
|
)
|
||||||
case AvatarAction.Reload(player_guid, weapon_guid) =>
|
case AvatarAction.Reload(player_guid, weapon_guid) =>
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.Reload(weapon_guid))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.Reload(weapon_guid))
|
||||||
|
|
@ -95,9 +106,14 @@ class AvatarService extends Actor {
|
||||||
AvatarEvents.publish(
|
AvatarEvents.publish(
|
||||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.WeaponDryFire(weapon_guid))
|
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.WeaponDryFire(weapon_guid))
|
||||||
)
|
)
|
||||||
|
|
||||||
case _ => ;
|
case _ => ;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//message to Undertaker
|
||||||
|
case AvatarServiceMessage.RemoveSpecificCorpse(corpses) =>
|
||||||
|
undertaker ! AvatarServiceMessage.RemoveSpecificCorpse( corpses.filter(corpse => {corpse.HasGUID && corpse.isBackpack}) )
|
||||||
|
|
||||||
/*
|
/*
|
||||||
case AvatarService.PlayerStateMessage(msg) =>
|
case AvatarService.PlayerStateMessage(msg) =>
|
||||||
// log.info(s"NEW: ${m}")
|
// log.info(s"NEW: ${m}")
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,10 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
package services.avatar
|
package services.avatar
|
||||||
|
|
||||||
|
import net.psforever.objects.Player
|
||||||
|
|
||||||
final case class AvatarServiceMessage(forChannel : String, actionMessage : AvatarAction.Action)
|
final case class AvatarServiceMessage(forChannel : String, actionMessage : AvatarAction.Action)
|
||||||
|
|
||||||
|
object AvatarServiceMessage {
|
||||||
|
final case class RemoveSpecificCorpse(corpse : List[Player])
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
// Copyright (c) 2017 PSForever
|
||||||
|
package services.avatar.support
|
||||||
|
|
||||||
|
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||||
|
import net.psforever.objects.guid.TaskResolver
|
||||||
|
import net.psforever.objects.{DefaultCancellable, Player}
|
||||||
|
import net.psforever.objects.zones.Zone
|
||||||
|
import net.psforever.types.Vector3
|
||||||
|
import services.{Service, ServiceManager}
|
||||||
|
import services.ServiceManager.Lookup
|
||||||
|
import services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||||
|
|
||||||
|
import scala.annotation.tailrec
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
class CorpseRemovalActor extends Actor {
|
||||||
|
private var burial : Cancellable = DefaultCancellable.obj
|
||||||
|
|
||||||
|
private var corpses : List[CorpseRemovalActor.Entry] = List()
|
||||||
|
|
||||||
|
private var taskResolver : ActorRef = Actor.noSender
|
||||||
|
|
||||||
|
private[this] val log = org.log4s.getLogger
|
||||||
|
|
||||||
|
override def postStop() = {
|
||||||
|
//Cart Master: See you on Thursday.
|
||||||
|
corpses.foreach { BurialTask }
|
||||||
|
corpses = Nil
|
||||||
|
}
|
||||||
|
|
||||||
|
def receive : Receive = {
|
||||||
|
case "startup" =>
|
||||||
|
ServiceManager.serviceManager ! Lookup("taskResolver") //ask for a resolver to deal with the GUID system
|
||||||
|
|
||||||
|
case ServiceManager.LookupResult("taskResolver", endpoint) =>
|
||||||
|
//Cart Master: Bring out your dead!
|
||||||
|
taskResolver = endpoint
|
||||||
|
context.become(Processing)
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
def Processing : Receive = {
|
||||||
|
case CorpseRemovalActor.AddCorpse(corpse, zone, time) =>
|
||||||
|
if(corpse.isBackpack) {
|
||||||
|
if(corpses.isEmpty) {
|
||||||
|
//we were the only entry so the event must be started from scratch
|
||||||
|
corpses = List(CorpseRemovalActor.Entry(corpse, zone, time))
|
||||||
|
RetimeFirstTask()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//unknown number of entries; append, sort, then re-time tasking
|
||||||
|
val oldHead = corpses.head
|
||||||
|
corpses = (corpses :+ CorpseRemovalActor.Entry(corpse, zone, time)).sortBy(_.timeAlive)
|
||||||
|
if(oldHead != corpses.head) {
|
||||||
|
RetimeFirstTask()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//Cart Master: 'Ere. He says he's not dead!
|
||||||
|
log.warn(s"$corpse does not qualify as a corpse; ignored queueing request")
|
||||||
|
}
|
||||||
|
|
||||||
|
case AvatarServiceMessage.RemoveSpecificCorpse(targets) =>
|
||||||
|
if(targets.nonEmpty) {
|
||||||
|
//Cart Master: No, I've got to go to the Robinsons'. They've lost nine today.
|
||||||
|
burial.cancel
|
||||||
|
if(targets.size == 1) {
|
||||||
|
log.debug(s"a target corpse submitted for early cleanup: ${targets.head}")
|
||||||
|
//simple selection
|
||||||
|
CorpseRemovalActor.recursiveFindCorpse(corpses.iterator, targets.head) match {
|
||||||
|
case None => ;
|
||||||
|
case Some(index) =>
|
||||||
|
BurialTask(corpses(index))
|
||||||
|
corpses = corpses.take(index) ++ corpses.drop(index+1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
log.debug(s"multiple target corpses submitted for early cleanup: $targets")
|
||||||
|
//cumbersome partition
|
||||||
|
//a - find targets from corpses
|
||||||
|
(for {
|
||||||
|
a <- targets
|
||||||
|
b <- corpses
|
||||||
|
if b.corpse == a &&
|
||||||
|
b.corpse.Continent.equals(a.Continent) &&
|
||||||
|
b.corpse.HasGUID && a.HasGUID && b.corpse.GUID == a.GUID
|
||||||
|
} yield b).foreach { BurialTask }
|
||||||
|
//b - corpses after the found targets are
|
||||||
|
//removed (note: cull any non-GUID entries while at it)
|
||||||
|
corpses = (for {
|
||||||
|
a <- targets
|
||||||
|
b <- corpses
|
||||||
|
if b.corpse.HasGUID && a.HasGUID &&
|
||||||
|
(b.corpse != a ||
|
||||||
|
!b.corpse.Continent.equals(a.Continent) ||
|
||||||
|
!b.corpse.HasGUID || !a.HasGUID || b.corpse.GUID != a.GUID)
|
||||||
|
} yield b).sortBy(_.timeAlive)
|
||||||
|
}
|
||||||
|
RetimeFirstTask()
|
||||||
|
}
|
||||||
|
|
||||||
|
case CorpseRemovalActor.Dispose() =>
|
||||||
|
burial.cancel
|
||||||
|
val now : Long = System.nanoTime
|
||||||
|
val (buried, rotting) = corpses.partition(entry => { now - entry.time >= entry.timeAlive })
|
||||||
|
corpses = rotting
|
||||||
|
buried.foreach { BurialTask }
|
||||||
|
RetimeFirstTask()
|
||||||
|
|
||||||
|
case CorpseRemovalActor.FailureToWork(target, zone, ex) =>
|
||||||
|
//Cart Master: Oh, I can't take him like that. It's against regulations.
|
||||||
|
log.error(s"corpse $target from $zone not properly unregistered - $ex")
|
||||||
|
|
||||||
|
case _ => ;
|
||||||
|
}
|
||||||
|
|
||||||
|
def RetimeFirstTask(now : Long = System.nanoTime) : Unit = {
|
||||||
|
//Cart Master: Thursday.
|
||||||
|
burial.cancel
|
||||||
|
if(corpses.nonEmpty) {
|
||||||
|
val short_timeout : FiniteDuration = math.max(1, corpses.head.timeAlive - (now - corpses.head.time)) nanoseconds
|
||||||
|
import scala.concurrent.ExecutionContext.Implicits.global
|
||||||
|
burial = context.system.scheduler.scheduleOnce(short_timeout, self, CorpseRemovalActor.Dispose())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def BurialTask(entry : CorpseRemovalActor.Entry) : Unit = {
|
||||||
|
//Cart master: Nine pence.
|
||||||
|
val target = entry.corpse
|
||||||
|
val zone = entry.zone
|
||||||
|
target.Position = Vector3.Zero //somewhere it will not disturb anything
|
||||||
|
entry.zone.Population ! Zone.Corpse.Remove(target)
|
||||||
|
context.parent ! AvatarServiceMessage(zone.Id, AvatarAction.ObjectDelete(Service.defaultPlayerGUID, target.GUID))
|
||||||
|
taskResolver ! BurialTask(target, zone)
|
||||||
|
}
|
||||||
|
|
||||||
|
def BurialTask(corpse : Player, zone : Zone) : TaskResolver.GiveTask = {
|
||||||
|
import net.psforever.objects.guid.{GUIDTask, Task}
|
||||||
|
TaskResolver.GiveTask (
|
||||||
|
new Task() {
|
||||||
|
private val localCorpse = corpse
|
||||||
|
private val localZone = zone
|
||||||
|
private val localAnnounce = self
|
||||||
|
|
||||||
|
override def isComplete : Task.Resolution.Value = if(!localCorpse.HasGUID) {
|
||||||
|
Task.Resolution.Success
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Task.Resolution.Incomplete
|
||||||
|
}
|
||||||
|
|
||||||
|
def Execute(resolver : ActorRef) : Unit = {
|
||||||
|
resolver ! scala.util.Success(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def onFailure(ex : Throwable): Unit = {
|
||||||
|
localAnnounce ! CorpseRemovalActor.FailureToWork(localCorpse, localZone, ex)
|
||||||
|
}
|
||||||
|
}, List(GUIDTask.UnregisterPlayer(corpse)(zone.GUID))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object CorpseRemovalActor {
|
||||||
|
final val time : Long = 180000000000L //3 min (180s)
|
||||||
|
|
||||||
|
final case class AddCorpse(corpse : Player, zone : Zone, time : Long = CorpseRemovalActor.time)
|
||||||
|
|
||||||
|
final case class Entry(corpse : Player, zone : Zone, timeAlive : Long = CorpseRemovalActor.time, time : Long = System.nanoTime())
|
||||||
|
|
||||||
|
final case class FailureToWork(corpse : Player, zone : Zone, ex : Throwable)
|
||||||
|
|
||||||
|
final case class Dispose()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A recursive function that finds and removes a specific player from a list of players.
|
||||||
|
* @param iter an `Iterator` of `CorpseRemovalActor.Entry` objects
|
||||||
|
* @param player the target `Player`
|
||||||
|
* @param index the index of the discovered `Player` object
|
||||||
|
* @return the index of the `Player` object in the list to be removed;
|
||||||
|
* `None`, otherwise
|
||||||
|
*/
|
||||||
|
@tailrec final def recursiveFindCorpse(iter : Iterator[CorpseRemovalActor.Entry], player : Player, index : Int = 0) : Option[Int] = {
|
||||||
|
if(!iter.hasNext) {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val corpse = iter.next.corpse
|
||||||
|
if(corpse == player && corpse.Continent.equals(player.Continent) && corpse.GUID == player.GUID) {
|
||||||
|
Some(index)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
recursiveFindCorpse(iter, player, index + 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ import net.psforever.objects.guid.TaskResolver
|
||||||
import net.psforever.objects.vehicles.Seat
|
import net.psforever.objects.vehicles.Seat
|
||||||
import net.psforever.objects.zones.Zone
|
import net.psforever.objects.zones.Zone
|
||||||
import net.psforever.packet.game.PlanetSideGUID
|
import net.psforever.packet.game.PlanetSideGUID
|
||||||
|
import net.psforever.types.Vector3
|
||||||
import services.ServiceManager
|
import services.ServiceManager
|
||||||
import services.ServiceManager.Lookup
|
import services.ServiceManager.Lookup
|
||||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||||
|
|
@ -80,6 +81,7 @@ class DeconstructionActor extends Actor {
|
||||||
vehiclesToScrap.foreach(entry => {
|
vehiclesToScrap.foreach(entry => {
|
||||||
val vehicle = entry.vehicle
|
val vehicle = entry.vehicle
|
||||||
val zone = entry.zone
|
val zone = entry.zone
|
||||||
|
vehicle.Position = Vector3.Zero //somewhere it will not disturb anything
|
||||||
entry.zone.Transport ! Zone.DespawnVehicle(vehicle)
|
entry.zone.Transport ! Zone.DespawnVehicle(vehicle)
|
||||||
context.parent ! DeconstructionActor.DeleteVehicle(vehicle.GUID, zone.Id) //call up to the main event system
|
context.parent ! DeconstructionActor.DeleteVehicle(vehicle.GUID, zone.Id) //call up to the main event system
|
||||||
context.parent ! VehicleServiceMessage.RevokeActorControl(vehicle) //call up to a sibling manager
|
context.parent ! VehicleServiceMessage.RevokeActorControl(vehicle) //call up to a sibling manager
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,21 @@
|
||||||
// Copyright (c) 2017 PSForever
|
// Copyright (c) 2017 PSForever
|
||||||
import akka.actor.Props
|
import akka.actor.Props
|
||||||
|
import akka.routing.RandomPool
|
||||||
import net.psforever.objects._
|
import net.psforever.objects._
|
||||||
|
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||||
|
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||||
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
||||||
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire, Vector3}
|
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire, Vector3}
|
||||||
import services.Service
|
import services.{Service, ServiceManager}
|
||||||
import services.avatar._
|
import services.avatar._
|
||||||
|
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
class AvatarService1Test extends ActorTest {
|
class AvatarService1Test extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"construct" in {
|
"construct" in {
|
||||||
system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
assert(true)
|
assert(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +24,8 @@ class AvatarService1Test extends ActorTest {
|
||||||
class AvatarService2Test extends ActorTest {
|
class AvatarService2Test extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"subscribe" in {
|
"subscribe" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
assert(true)
|
assert(true)
|
||||||
}
|
}
|
||||||
|
|
@ -27,8 +34,9 @@ class AvatarService2Test extends ActorTest {
|
||||||
|
|
||||||
class AvatarService3Test extends ActorTest {
|
class AvatarService3Test extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
|
ServiceManager.boot(system)
|
||||||
"subscribe to a specific channel" in {
|
"subscribe to a specific channel" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! Service.Leave()
|
service ! Service.Leave()
|
||||||
assert(true)
|
assert(true)
|
||||||
|
|
@ -39,7 +47,8 @@ class AvatarService3Test extends ActorTest {
|
||||||
class AvatarService4Test extends ActorTest {
|
class AvatarService4Test extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"subscribe" in {
|
"subscribe" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! Service.LeaveAll()
|
service ! Service.LeaveAll()
|
||||||
assert(true)
|
assert(true)
|
||||||
|
|
@ -50,7 +59,8 @@ class AvatarService4Test extends ActorTest {
|
||||||
class AvatarService5Test extends ActorTest {
|
class AvatarService5Test extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass an unhandled message" in {
|
"pass an unhandled message" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! "hello"
|
service ! "hello"
|
||||||
expectNoMsg()
|
expectNoMsg()
|
||||||
|
|
@ -61,7 +71,8 @@ class AvatarService5Test extends ActorTest {
|
||||||
class ArmorChangedTest extends ActorTest {
|
class ArmorChangedTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ArmorChanged" in {
|
"pass ArmorChanged" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ArmorChanged(PlanetSideGUID(10), ExoSuitType.Reinforced, 0))
|
service ! AvatarServiceMessage("test", AvatarAction.ArmorChanged(PlanetSideGUID(10), ExoSuitType.Reinforced, 0))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ArmorChanged(ExoSuitType.Reinforced, 0)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ArmorChanged(ExoSuitType.Reinforced, 0)))
|
||||||
|
|
@ -72,7 +83,8 @@ class ArmorChangedTest extends ActorTest {
|
||||||
class ConcealPlayerTest extends ActorTest {
|
class ConcealPlayerTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ConcealPlayer" in {
|
"pass ConcealPlayer" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ConcealPlayer(PlanetSideGUID(10)))
|
service ! AvatarServiceMessage("test", AvatarAction.ConcealPlayer(PlanetSideGUID(10)))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ConcealPlayer()))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ConcealPlayer()))
|
||||||
|
|
@ -85,7 +97,8 @@ class EquipmentInHandTest extends ActorTest {
|
||||||
|
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass EquipmentInHand" in {
|
"pass EquipmentInHand" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.EquipmentInHand(PlanetSideGUID(10), 2, tool))
|
service ! AvatarServiceMessage("test", AvatarAction.EquipmentInHand(PlanetSideGUID(10), 2, tool))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentInHand(2, tool)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentInHand(2, tool)))
|
||||||
|
|
@ -101,7 +114,8 @@ class EquipmentOnGroundTest extends ActorTest {
|
||||||
|
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass EquipmentOnGround" in {
|
"pass EquipmentOnGround" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.EquipmentOnGround(PlanetSideGUID(10), Vector3(300f, 200f, 100f), Vector3(450f, 300f, 150f), toolDef.ObjectId, PlanetSideGUID(11), cdata))
|
service ! AvatarServiceMessage("test", AvatarAction.EquipmentOnGround(PlanetSideGUID(10), Vector3(300f, 200f, 100f), Vector3(450f, 300f, 150f), toolDef.ObjectId, PlanetSideGUID(11), cdata))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentOnGround(Vector3(300f, 200f, 100f), Vector3(450f, 300f, 150f), toolDef.ObjectId, PlanetSideGUID(11), cdata)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.EquipmentOnGround(Vector3(300f, 200f, 100f), Vector3(450f, 300f, 150f), toolDef.ObjectId, PlanetSideGUID(11), cdata)))
|
||||||
|
|
@ -110,14 +124,15 @@ class EquipmentOnGroundTest extends ActorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
class LoadPlayerTest extends ActorTest {
|
class LoadPlayerTest extends ActorTest {
|
||||||
val obj = Player("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, 1)
|
val obj = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, 1))
|
||||||
obj.GUID = PlanetSideGUID(10)
|
obj.GUID = PlanetSideGUID(10)
|
||||||
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(11)
|
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(11)
|
||||||
val pdata = obj.Definition.Packet.DetailedConstructorData(obj).get
|
val pdata = obj.Definition.Packet.DetailedConstructorData(obj).get
|
||||||
|
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass LoadPlayer" in {
|
"pass LoadPlayer" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.LoadPlayer(PlanetSideGUID(10), pdata))
|
service ! AvatarServiceMessage("test", AvatarAction.LoadPlayer(PlanetSideGUID(10), pdata))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.LoadPlayer(pdata)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.LoadPlayer(pdata)))
|
||||||
|
|
@ -128,7 +143,8 @@ class LoadPlayerTest extends ActorTest {
|
||||||
class ObjectDeleteTest extends ActorTest {
|
class ObjectDeleteTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ObjectDelete" in {
|
"pass ObjectDelete" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11)))
|
service ! AvatarServiceMessage("test", AvatarAction.ObjectDelete(PlanetSideGUID(10), PlanetSideGUID(11)))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 0)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectDelete(PlanetSideGUID(11), 0)))
|
||||||
|
|
@ -142,7 +158,8 @@ class ObjectDeleteTest extends ActorTest {
|
||||||
class ObjectHeldTest extends ActorTest {
|
class ObjectHeldTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ObjectHeld" in {
|
"pass ObjectHeld" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ObjectHeld(PlanetSideGUID(10), 1))
|
service ! AvatarServiceMessage("test", AvatarAction.ObjectHeld(PlanetSideGUID(10), 1))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectHeld(1)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ObjectHeld(1)))
|
||||||
|
|
@ -153,7 +170,8 @@ class ObjectHeldTest extends ActorTest {
|
||||||
class PlanetsideAttributeTest extends ActorTest {
|
class PlanetsideAttributeTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass PlanetsideAttribute" in {
|
"pass PlanetsideAttribute" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.PlanetsideAttribute(PlanetSideGUID(10), 5, 1200L))
|
service ! AvatarServiceMessage("test", AvatarAction.PlanetsideAttribute(PlanetSideGUID(10), 5, 1200L))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlanetsideAttribute(5, 1200L)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlanetsideAttribute(5, 1200L)))
|
||||||
|
|
@ -166,7 +184,8 @@ class PlayerStateTest extends ActorTest {
|
||||||
|
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass PlayerState" in {
|
"pass PlayerState" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.PlayerState(PlanetSideGUID(10), msg, false, false))
|
service ! AvatarServiceMessage("test", AvatarAction.PlayerState(PlanetSideGUID(10), msg, false, false))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlayerState(msg, false, false)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.PlayerState(msg, false, false)))
|
||||||
|
|
@ -177,7 +196,8 @@ class PlayerStateTest extends ActorTest {
|
||||||
class ReloadTest extends ActorTest {
|
class ReloadTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass Reload" in {
|
"pass Reload" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.Reload(PlanetSideGUID(10), PlanetSideGUID(40)))
|
service ! AvatarServiceMessage("test", AvatarAction.Reload(PlanetSideGUID(10), PlanetSideGUID(40)))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.Reload(PlanetSideGUID(40))))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.Reload(PlanetSideGUID(40))))
|
||||||
|
|
@ -191,7 +211,8 @@ class ChangeAmmoTest extends ActorTest {
|
||||||
|
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ChangeAmmo" in {
|
"pass ChangeAmmo" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ChangeAmmo(PlanetSideGUID(10), PlanetSideGUID(40), 0, PlanetSideGUID(40), ammoDef.ObjectId, PlanetSideGUID(41), ammoDef.Packet.ConstructorData(ammoBox).get))
|
service ! AvatarServiceMessage("test", AvatarAction.ChangeAmmo(PlanetSideGUID(10), PlanetSideGUID(40), 0, PlanetSideGUID(40), ammoDef.ObjectId, PlanetSideGUID(41), ammoDef.Packet.ConstructorData(ammoBox).get))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeAmmo(PlanetSideGUID(40), 0, PlanetSideGUID(40), ammoDef.ObjectId, PlanetSideGUID(41), ammoDef.Packet.ConstructorData(ammoBox).get)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeAmmo(PlanetSideGUID(40), 0, PlanetSideGUID(40), ammoDef.ObjectId, PlanetSideGUID(41), ammoDef.Packet.ConstructorData(ammoBox).get)))
|
||||||
|
|
@ -205,7 +226,8 @@ class ChangeFireModeTest extends ActorTest {
|
||||||
|
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ChangeFireMode" in {
|
"pass ChangeFireMode" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireMode(PlanetSideGUID(10), PlanetSideGUID(40), 0))
|
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireMode(PlanetSideGUID(10), PlanetSideGUID(40), 0))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireMode(PlanetSideGUID(40), 0)))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireMode(PlanetSideGUID(40), 0)))
|
||||||
|
|
@ -216,7 +238,8 @@ class ChangeFireModeTest extends ActorTest {
|
||||||
class ChangeFireStateStartTest extends ActorTest {
|
class ChangeFireStateStartTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ChangeFireState_Start" in {
|
"pass ChangeFireState_Start" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Start(PlanetSideGUID(10), PlanetSideGUID(40)))
|
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Start(PlanetSideGUID(10), PlanetSideGUID(40)))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireState_Start(PlanetSideGUID(40))))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireState_Start(PlanetSideGUID(40))))
|
||||||
|
|
@ -227,7 +250,8 @@ class ChangeFireStateStartTest extends ActorTest {
|
||||||
class ChangeFireStateStopTest extends ActorTest {
|
class ChangeFireStateStopTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass ChangeFireState_Stop" in {
|
"pass ChangeFireState_Stop" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Stop(PlanetSideGUID(10), PlanetSideGUID(40)))
|
service ! AvatarServiceMessage("test", AvatarAction.ChangeFireState_Stop(PlanetSideGUID(10), PlanetSideGUID(40)))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireState_Stop(PlanetSideGUID(40))))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.ChangeFireState_Stop(PlanetSideGUID(40))))
|
||||||
|
|
@ -238,7 +262,8 @@ class ChangeFireStateStopTest extends ActorTest {
|
||||||
class WeaponDryFireTest extends ActorTest {
|
class WeaponDryFireTest extends ActorTest {
|
||||||
"AvatarService" should {
|
"AvatarService" should {
|
||||||
"pass WeaponDryFire" in {
|
"pass WeaponDryFire" in {
|
||||||
val service = system.actorOf(Props[AvatarService], "service")
|
ServiceManager.boot(system)
|
||||||
|
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
|
||||||
service ! Service.Join("test")
|
service ! Service.Join("test")
|
||||||
service ! AvatarServiceMessage("test", AvatarAction.WeaponDryFire(PlanetSideGUID(10), PlanetSideGUID(40)))
|
service ! AvatarServiceMessage("test", AvatarAction.WeaponDryFire(PlanetSideGUID(10), PlanetSideGUID(40)))
|
||||||
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.WeaponDryFire(PlanetSideGUID(40))))
|
expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.WeaponDryFire(PlanetSideGUID(40))))
|
||||||
|
|
@ -246,6 +271,177 @@ class WeaponDryFireTest extends ActorTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object AvatarServiceTest {
|
/*
|
||||||
//decoy
|
Preparation for these three Release tests is involved.
|
||||||
|
The ServiceManager must not only be set up correctly, but must be given a TaskResolver.
|
||||||
|
The AvatarService is started and that starts CorpseRemovalActor, an essential part of this test.
|
||||||
|
The CorpseRemovalActor needs that TaskResolver created by the ServiceManager;
|
||||||
|
but, another independent TaskResolver will be needed for manual parts of the test.
|
||||||
|
(The ServiceManager's TaskResolver can be "borrowed" but that requires writing code to intercept it.)
|
||||||
|
The Zone needs to be set up and initialized properly with a ZoneActor.
|
||||||
|
The ZoneActor builds the GUID Actor and the ZonePopulationActor.
|
||||||
|
|
||||||
|
ALL of these Actors will talk to each other.
|
||||||
|
The lines of communication can short circuit if the next Actor does not have the correct information.
|
||||||
|
Putting Actor startup in the main class, outside of the body of the test, helps.
|
||||||
|
Frequent pauses to allow everything to sort their messages also helps.
|
||||||
|
Even with all this work, the tests have a high chance of failure just due to being asynchronous.
|
||||||
|
*/
|
||||||
|
class AvatarReleaseTest extends ActorTest {
|
||||||
|
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||||
|
val service = system.actorOf(Props[AvatarService], "release-test-service")
|
||||||
|
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||||
|
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||||
|
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||||
|
zone.Actor ! Zone.Init()
|
||||||
|
val obj = Player(Avatar("TestCharacter", PlanetSideEmpire.VS, CharacterGender.Female, 1, 1))
|
||||||
|
obj.Continent = "test"
|
||||||
|
obj.Release
|
||||||
|
|
||||||
|
"AvatarService" should {
|
||||||
|
"pass Release" in {
|
||||||
|
expectNoMsg(100 milliseconds) //spacer
|
||||||
|
|
||||||
|
service ! Service.Join("test")
|
||||||
|
taskResolver ! GUIDTask.RegisterObjectTask(obj)(zone.GUID)
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
zone.Population ! Zone.Corpse.Add(obj)
|
||||||
|
expectNoMsg(100 milliseconds) //spacer
|
||||||
|
|
||||||
|
assert(zone.Corpses.size == 1)
|
||||||
|
assert(obj.HasGUID)
|
||||||
|
val guid = obj.GUID
|
||||||
|
service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone, Some(1000000000))) //alive for one second
|
||||||
|
|
||||||
|
val reply1 = receiveOne(100 milliseconds)
|
||||||
|
assert(reply1.isInstanceOf[AvatarServiceResponse])
|
||||||
|
val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
|
||||||
|
assert(reply1msg.toChannel == "/test/Avatar")
|
||||||
|
assert(reply1msg.avatar_guid == guid)
|
||||||
|
assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
|
||||||
|
assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
|
||||||
|
|
||||||
|
val reply2 = receiveOne(2 seconds)
|
||||||
|
assert(reply2.isInstanceOf[AvatarServiceResponse])
|
||||||
|
val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
|
||||||
|
assert(reply2msg.toChannel.equals("/test/Avatar"))
|
||||||
|
assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
|
||||||
|
assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
|
||||||
|
assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
|
||||||
|
|
||||||
|
expectNoMsg(200 milliseconds)
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
assert(!obj.HasGUID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AvatarReleaseEarly1Test extends ActorTest {
|
||||||
|
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||||
|
val service = system.actorOf(Props[AvatarService], "release-test-service")
|
||||||
|
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||||
|
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||||
|
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||||
|
zone.Actor ! Zone.Init()
|
||||||
|
val obj = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, 1))
|
||||||
|
obj.Continent = "test"
|
||||||
|
obj.Release
|
||||||
|
|
||||||
|
"AvatarService" should {
|
||||||
|
"pass Release" in {
|
||||||
|
expectNoMsg(100 milliseconds) //spacer
|
||||||
|
|
||||||
|
service ! Service.Join("test")
|
||||||
|
taskResolver ! GUIDTask.RegisterObjectTask(obj)(zone.GUID)
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
zone.Population ! Zone.Corpse.Add(obj)
|
||||||
|
expectNoMsg(100 milliseconds) //spacer
|
||||||
|
|
||||||
|
assert(zone.Corpses.size == 1)
|
||||||
|
assert(obj.HasGUID)
|
||||||
|
val guid = obj.GUID
|
||||||
|
service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes!
|
||||||
|
|
||||||
|
val reply1 = receiveOne(100 milliseconds)
|
||||||
|
assert(reply1.isInstanceOf[AvatarServiceResponse])
|
||||||
|
val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
|
||||||
|
assert(reply1msg.toChannel == "/test/Avatar")
|
||||||
|
assert(reply1msg.avatar_guid == guid)
|
||||||
|
assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
|
||||||
|
assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
|
||||||
|
|
||||||
|
service ! AvatarServiceMessage.RemoveSpecificCorpse(List(obj)) //IMPORTANT: ONE ENTRY
|
||||||
|
val reply2 = receiveOne(100 milliseconds)
|
||||||
|
assert(reply2.isInstanceOf[AvatarServiceResponse])
|
||||||
|
val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
|
||||||
|
assert(reply2msg.toChannel.equals("/test/Avatar"))
|
||||||
|
assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
|
||||||
|
assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
|
||||||
|
assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
|
||||||
|
|
||||||
|
expectNoMsg(200 milliseconds)
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
assert(!obj.HasGUID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AvatarReleaseEarly2Test extends ActorTest {
|
||||||
|
ServiceManager.boot(system) ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||||
|
val service = system.actorOf(Props[AvatarService], "release-test-service")
|
||||||
|
val zone = new Zone("test", new ZoneMap("test-map"), 0)
|
||||||
|
val taskResolver = system.actorOf(Props[TaskResolver], "release-test-resolver")
|
||||||
|
zone.Actor = system.actorOf(Props(classOf[ZoneActor], zone), "release-test-zone")
|
||||||
|
zone.Actor ! Zone.Init()
|
||||||
|
val objAlt = Player(Avatar("TestCharacter2", PlanetSideEmpire.NC, CharacterGender.Male, 1, 1)) //necessary clutter
|
||||||
|
val obj = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, 1))
|
||||||
|
obj.Continent = "test"
|
||||||
|
obj.Release
|
||||||
|
|
||||||
|
"AvatarService" should {
|
||||||
|
"pass Release" in {
|
||||||
|
expectNoMsg(100 milliseconds) //spacer
|
||||||
|
|
||||||
|
service ! Service.Join("test")
|
||||||
|
taskResolver ! GUIDTask.RegisterObjectTask(obj)(zone.GUID)
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
zone.Population ! Zone.Corpse.Add(obj)
|
||||||
|
expectNoMsg(100 milliseconds) //spacer
|
||||||
|
|
||||||
|
assert(zone.Corpses.size == 1)
|
||||||
|
assert(obj.HasGUID)
|
||||||
|
val guid = obj.GUID
|
||||||
|
service ! AvatarServiceMessage("test", AvatarAction.Release(obj, zone)) //3+ minutes!
|
||||||
|
|
||||||
|
val reply1 = receiveOne(100 milliseconds)
|
||||||
|
assert(reply1.isInstanceOf[AvatarServiceResponse])
|
||||||
|
val reply1msg = reply1.asInstanceOf[AvatarServiceResponse]
|
||||||
|
assert(reply1msg.toChannel == "/test/Avatar")
|
||||||
|
assert(reply1msg.avatar_guid == guid)
|
||||||
|
assert(reply1msg.replyMessage.isInstanceOf[AvatarResponse.Release])
|
||||||
|
assert(reply1msg.replyMessage.asInstanceOf[AvatarResponse.Release].player == obj)
|
||||||
|
|
||||||
|
service ! AvatarServiceMessage.RemoveSpecificCorpse(List(objAlt, obj)) //IMPORTANT: TWO ENTRIES
|
||||||
|
val reply2 = receiveOne(100 milliseconds)
|
||||||
|
assert(reply2.isInstanceOf[AvatarServiceResponse])
|
||||||
|
val reply2msg = reply2.asInstanceOf[AvatarServiceResponse]
|
||||||
|
assert(reply2msg.toChannel.equals("/test/Avatar"))
|
||||||
|
assert(reply2msg.avatar_guid == Service.defaultPlayerGUID)
|
||||||
|
assert(reply2msg.replyMessage.isInstanceOf[AvatarResponse.ObjectDelete])
|
||||||
|
assert(reply2msg.replyMessage.asInstanceOf[AvatarResponse.ObjectDelete].item_guid == guid)
|
||||||
|
|
||||||
|
expectNoMsg(200 milliseconds)
|
||||||
|
assert(zone.Corpses.isEmpty)
|
||||||
|
assert(!obj.HasGUID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object AvatarServiceTest {
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
private val number = new AtomicInteger(1)
|
||||||
|
|
||||||
|
def TestName : String = {
|
||||||
|
s"service${number.getAndIncrement()}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue