mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-20 02:24:45 +00:00
Facility Turrets (#223)
* object class, actor class, and definitions for base turrets; untested * wired base turrets into existence, with hoop jumping; created interface for objects with mounted weapons (vehicles and turrets); working example phalanx_sgl_hevgatcan in Anguta, Ceryshen * re-wiring manned turrets so that the turreted weapon itself never changes externally but merely identifies different and changes internally; workflow for upgrading wall turrets in place (30s); clarifications and documentation for HackMessage and UseItemMessage; getting rid of orphaned packages from previous location of services * added a simple task that reverts upgraded manned turrets to their None state after a certain amount of time has passed; it works but need improvement * turret weapon upgrades now last for a duration of 30 minutes before reverting; created a service support actor base actor that underlies all current support actors; nano-dispenser now properly loads 1 unit of upgrade canister, rather than 100 units; all canister types have appropriate 2x3 inventory size * forgot to hurry; moved over the Services tests from main/test folder into the common/test folder and needed to change the location of ActorTest to accommodate it; test and documentation for MannedTurret; codecov ignore update * wired facility turrets in Anguta, Ceryshen; Akna tower, Ceryshen; and S.Villa tower, home3 (Anguta tower is a watchtower); attempted workaround for Travis CI issues with receiveN; re-introduced RemoveActorTest, at least the first test; expanded how ZoneActor performs tests on MannedTurret setup * getting rid of useless commented-out code; making common operations for mounting and dismounting * removed outdated comment; added ResourceSilo tests; added extra test for Zone
This commit is contained in:
parent
61a51c1dd1
commit
b81ff2bbf4
15
.codecov.yml
15
.codecov.yml
|
|
@ -9,8 +9,11 @@ ignore:
|
|||
- "common/src/main/scala/net/psforever/objects/equipment/Kits.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/equipment/SItem.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/guid/AvailabilityPolicy.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/serverobject/turret/TurretUpgrade.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/serverobject/CommonMessages.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/vehicles/AccessPermissionGroup.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/vehicles/SeatArmoRestriction.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/vehicles/Turrets.scala"
|
||||
- "common/src/main/scala/net/psforever/objects/vehicles/VehicleLockState.scala"
|
||||
- "common/src/main/scala/net/psforever/packet/crypto"
|
||||
- "common/src/main/scala/net/psforever/packet/game/objectcreate/DrawnSlot.scala"
|
||||
|
|
@ -33,12 +36,12 @@ ignore:
|
|||
- "common/src/main/scala/net/psforever/types/MeritCommendation.scala"
|
||||
- "common/src/main/scala/net/psforever/types/PlanetSideEmpire.scala"
|
||||
- "common/src/main/scala/net/psforever/types/TransactionType.scala"
|
||||
- "pslogin/src/main/scala/services/avatar/AvatarAction.scala"
|
||||
- "pslogin/src/main/scala/services/avatar/AvatarResponse.scala"
|
||||
- "pslogin/src/main/scala/services/local/LocalAction.scala"
|
||||
- "pslogin/src/main/scala/services/local/LocalResponse.scala"
|
||||
- "pslogin/src/main/scala/services/vehicle/VehicleAction.scala"
|
||||
- "pslogin/src/main/scala/services/vehicle/VehicleResponse.scala"
|
||||
- "common/src/main/scala/services/avatar/AvatarAction.scala"
|
||||
- "common/src/main/scala/services/avatar/AvatarResponse.scala"
|
||||
- "common/src/main/scala/services/local/LocalAction.scala"
|
||||
- "common/src/main/scala/services/local/LocalResponse.scala"
|
||||
- "common/src/main/scala/services/vehicle/VehicleAction.scala"
|
||||
- "common/src/main/scala/services/vehicle/VehicleResponse.scala"
|
||||
- "pslogin/src/main/scala/CryptoSessionActor.scala"
|
||||
- "pslogin/src/main/scala/DatabaseConnector.scala"
|
||||
- "pslogin/src/main/scala/LoginConfig.scala"
|
||||
|
|
|
|||
|
|
@ -15,9 +15,11 @@ import net.psforever.objects.serverobject.terminals._
|
|||
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
||||
import net.psforever.objects.ballistics.{DamageType, Projectiles}
|
||||
import net.psforever.objects.serverobject.turret.{MannedTurretDefinition, TurretUpgrade}
|
||||
import net.psforever.objects.vehicles.{SeatArmorRestriction, UtilityType}
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
|
||||
object GlobalDefinitions {
|
||||
|
|
@ -414,11 +416,11 @@ object GlobalDefinitions {
|
|||
val upgrade_canister = AmmoBoxDefinition(Ammo.upgrade_canister)
|
||||
|
||||
val trek_ammo = AmmoBoxDefinition(Ammo.trek_ammo)
|
||||
//
|
||||
|
||||
val bullet_35mm = AmmoBoxDefinition(Ammo.bullet_35mm) //liberator nosegun
|
||||
|
||||
val ancient_ammo_vehicle = AmmoBoxDefinition(Ammo.ancient_ammo_vehicle)
|
||||
//
|
||||
|
||||
val aphelion_laser_ammo = AmmoBoxDefinition(Ammo.aphelion_laser_ammo)
|
||||
|
||||
val aphelion_immolation_cannon_ammo = AmmoBoxDefinition(Ammo.aphelion_immolation_cannon_ammo)
|
||||
|
|
@ -488,6 +490,8 @@ object GlobalDefinitions {
|
|||
val peregrine_sparrow_ammo = AmmoBoxDefinition(Ammo.peregrine_sparrow_ammo)
|
||||
|
||||
val bullet_150mm = AmmoBoxDefinition(Ammo.bullet_150mm)
|
||||
|
||||
val phalanx_ammo = AmmoBoxDefinition(Ammo.phalanx_ammo)
|
||||
init_ammo()
|
||||
|
||||
val chainblade = ToolDefinition(ObjectClass.chainblade)
|
||||
|
|
@ -722,6 +726,12 @@ object GlobalDefinitions {
|
|||
val galaxy_gunship_tailgun = ToolDefinition(ObjectClass.galaxy_gunship_tailgun)
|
||||
|
||||
val galaxy_gunship_gun = ToolDefinition(ObjectClass.galaxy_gunship_gun)
|
||||
|
||||
val phalanx_sgl_hevgatcan = ToolDefinition(ObjectClass.phalanx_sgl_hevgatcan)
|
||||
|
||||
val phalanx_avcombo = ToolDefinition(ObjectClass.phalanx_avcombo)
|
||||
|
||||
val phalanx_flakcombo = ToolDefinition(ObjectClass.phalanx_flakcombo)
|
||||
init_tools()
|
||||
|
||||
/*
|
||||
|
|
@ -849,6 +859,18 @@ object GlobalDefinitions {
|
|||
|
||||
val resource_silo = new ResourceSiloDefinition
|
||||
|
||||
val manned_turret = new MannedTurretDefinition(480) {
|
||||
Name = "manned_turret"
|
||||
MaxHealth = 3600
|
||||
Weapons += 1 -> new mutable.HashMap()
|
||||
Weapons(1) += TurretUpgrade.None -> phalanx_sgl_hevgatcan
|
||||
Weapons(1) += TurretUpgrade.AVCombo -> phalanx_avcombo
|
||||
Weapons(1) += TurretUpgrade.FlakCombo -> phalanx_flakcombo
|
||||
MountPoints += 1 -> 0
|
||||
FactionLocked = true
|
||||
ReserveAmmunition = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a faction, provide the standard assault melee weapon.
|
||||
* @param faction the faction
|
||||
|
|
@ -1352,15 +1374,15 @@ object GlobalDefinitions {
|
|||
|
||||
health_canister.Name = "health_canister"
|
||||
health_canister.Capacity = 100
|
||||
health_canister.Tile = InventoryTile.Tile33
|
||||
health_canister.Tile = InventoryTile.Tile23
|
||||
|
||||
armor_canister.Name = "armor_canister"
|
||||
armor_canister.Capacity = 100
|
||||
armor_canister.Tile = InventoryTile.Tile33
|
||||
armor_canister.Tile = InventoryTile.Tile23
|
||||
|
||||
upgrade_canister.Name = "upgrade_canister"
|
||||
upgrade_canister.Capacity = 100
|
||||
upgrade_canister.Tile = InventoryTile.Tile33
|
||||
upgrade_canister.Capacity = 1
|
||||
upgrade_canister.Tile = InventoryTile.Tile23
|
||||
|
||||
trek_ammo.Name = "trek_ammo"
|
||||
trek_ammo.Size = EquipmentSize.Blocked
|
||||
|
|
@ -1508,6 +1530,10 @@ object GlobalDefinitions {
|
|||
bullet_150mm.Name = "bullet_150mm"
|
||||
bullet_150mm.Capacity = 50
|
||||
bullet_150mm.Tile = InventoryTile.Tile44
|
||||
|
||||
phalanx_ammo.Name = "phalanx_ammo"
|
||||
phalanx_ammo.Capacity = 4000 //sufficient for a reload
|
||||
phalanx_ammo.Size = EquipmentSize.Inventory
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -3743,6 +3769,7 @@ object GlobalDefinitions {
|
|||
nano_dispenser.FireModes.head.AmmoTypeIndices += 1
|
||||
nano_dispenser.FireModes.head.AmmoSlotIndex = 0
|
||||
nano_dispenser.FireModes.head.Magazine = 100
|
||||
nano_dispenser.FireModes.head.CustomMagazine = Ammo.upgrade_canister -> 1
|
||||
nano_dispenser.FireModes.head.Modifiers.Damage1 = 20
|
||||
nano_dispenser.FireModes.head.Modifiers.Damage4 = 20
|
||||
nano_dispenser.Tile = InventoryTile.Tile63
|
||||
|
|
@ -4297,6 +4324,45 @@ object GlobalDefinitions {
|
|||
galaxy_gunship_gun.FireModes.head.AmmoTypeIndices += 0
|
||||
galaxy_gunship_gun.FireModes.head.AmmoSlotIndex = 0
|
||||
galaxy_gunship_gun.FireModes.head.Magazine = 200
|
||||
|
||||
phalanx_sgl_hevgatcan.Name = "phalanx_sgl_hevgatcan"
|
||||
phalanx_sgl_hevgatcan.Size = EquipmentSize.BaseTurretWeapon
|
||||
phalanx_sgl_hevgatcan.AmmoTypes += phalanx_ammo
|
||||
phalanx_sgl_hevgatcan.ProjectileTypes += phalanx_projectile
|
||||
phalanx_sgl_hevgatcan.FireModes += new InfiniteFireModeDefinition
|
||||
phalanx_sgl_hevgatcan.FireModes.head.AmmoTypeIndices += 0
|
||||
phalanx_sgl_hevgatcan.FireModes.head.AmmoSlotIndex = 0
|
||||
phalanx_sgl_hevgatcan.FireModes.head.Magazine = 4000
|
||||
|
||||
phalanx_avcombo.Name = "phalanx_avcombo"
|
||||
phalanx_avcombo.Size = EquipmentSize.BaseTurretWeapon
|
||||
phalanx_avcombo.AmmoTypes += phalanx_ammo
|
||||
phalanx_avcombo.ProjectileTypes += phalanx_projectile
|
||||
phalanx_avcombo.ProjectileTypes += phalanx_av_projectile
|
||||
phalanx_avcombo.FireModes += new InfiniteFireModeDefinition
|
||||
phalanx_avcombo.FireModes.head.AmmoTypeIndices += 0
|
||||
phalanx_avcombo.FireModes.head.AmmoSlotIndex = 0
|
||||
phalanx_avcombo.FireModes.head.Magazine = 4000
|
||||
phalanx_avcombo.FireModes += new InfiniteFireModeDefinition
|
||||
phalanx_avcombo.FireModes(1).AmmoTypeIndices += 0
|
||||
phalanx_avcombo.FireModes(1).ProjectileTypeIndices += 1
|
||||
phalanx_avcombo.FireModes(1).AmmoSlotIndex = 0
|
||||
phalanx_avcombo.FireModes(1).Magazine = 4000
|
||||
|
||||
phalanx_flakcombo.Name = "phalanx_flakcombo"
|
||||
phalanx_flakcombo.Size = EquipmentSize.BaseTurretWeapon
|
||||
phalanx_flakcombo.AmmoTypes += phalanx_ammo
|
||||
phalanx_flakcombo.ProjectileTypes += phalanx_projectile
|
||||
phalanx_flakcombo.ProjectileTypes += phalanx_flak_projectile
|
||||
phalanx_flakcombo.FireModes += new InfiniteFireModeDefinition
|
||||
phalanx_flakcombo.FireModes.head.AmmoTypeIndices += 0
|
||||
phalanx_flakcombo.FireModes.head.AmmoSlotIndex = 0
|
||||
phalanx_flakcombo.FireModes.head.Magazine = 4000
|
||||
phalanx_flakcombo.FireModes += new InfiniteFireModeDefinition
|
||||
phalanx_flakcombo.FireModes(1).AmmoTypeIndices += 0
|
||||
phalanx_flakcombo.FireModes(1).ProjectileTypeIndices += 1
|
||||
phalanx_flakcombo.FireModes(1).AmmoSlotIndex = 0
|
||||
phalanx_flakcombo.FireModes(1).Magazine = 4000
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -21,24 +21,26 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode
|
|||
/** index of the current fire mode on the `ToolDefinition`'s list of fire modes */
|
||||
private var fireModeIndex : Int = 0
|
||||
/** current ammunition slot being used by this fire mode */
|
||||
private val ammoSlots : List[Tool.FireModeSlot] = Tool.LoadDefinition(this)
|
||||
private var ammoSlots : List[Tool.FireModeSlot] = List.empty
|
||||
|
||||
Tool.LoadDefinition(this)
|
||||
|
||||
def FireModeIndex : Int = fireModeIndex
|
||||
|
||||
def FireModeIndex_=(index : Int) : Int = {
|
||||
fireModeIndex = index % toolDef.FireModes.length
|
||||
fireModeIndex = index % Definition.FireModes.length
|
||||
FireModeIndex
|
||||
}
|
||||
|
||||
def FireMode : FireModeDefinition = toolDef.FireModes(fireModeIndex)
|
||||
def FireMode : FireModeDefinition = Definition.FireModes(fireModeIndex)
|
||||
|
||||
def NextFireMode : FireModeDefinition = {
|
||||
FireModeIndex = toolDef.NextFireModeIndex(FireModeIndex)
|
||||
FireModeIndex = Definition.NextFireModeIndex(FireModeIndex)
|
||||
AmmoSlot.Chamber = FireMode.Chamber
|
||||
FireMode
|
||||
}
|
||||
|
||||
def ToFireMode : Int = toolDef.NextFireModeIndex(FireModeIndex)
|
||||
def ToFireMode : Int = Definition.NextFireModeIndex(FireModeIndex)
|
||||
|
||||
def ToFireMode_=(index : Int) : FireModeDefinition = {
|
||||
FireModeIndex = index
|
||||
|
|
@ -53,7 +55,7 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode
|
|||
AmmoTypeIndex
|
||||
}
|
||||
|
||||
def AmmoType : Ammo.Value = toolDef.AmmoTypes(AmmoTypeIndex).AmmoType
|
||||
def AmmoType : Ammo.Value = Definition.AmmoTypes(AmmoTypeIndex).AmmoType
|
||||
|
||||
def NextAmmoType : Ammo.Value = {
|
||||
AmmoSlot.AmmoTypeIndex = AmmoSlot.AmmoTypeIndex + 1
|
||||
|
|
@ -61,7 +63,7 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode
|
|||
}
|
||||
|
||||
def Projectile : ProjectileDefinition = {
|
||||
toolDef.ProjectileTypes({
|
||||
Definition.ProjectileTypes({
|
||||
val projIndices = FireMode.ProjectileTypeIndices
|
||||
if(projIndices.isEmpty) {
|
||||
AmmoTypeIndex //e.g., bullet_9mm -> bullet_9mm_projectile, bullet_9mm_AP -> bullet_9mm_AP_projectile
|
||||
|
|
@ -77,11 +79,20 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode
|
|||
def Magazine : Int = AmmoSlot.Magazine
|
||||
|
||||
def Magazine_=(mag : Int) : Int = {
|
||||
AmmoSlot.Magazine = Math.min(Math.max(0, mag), MaxMagazine)
|
||||
//AmmoSlot.Magazine = Math.min(Math.max(0, mag), MaxMagazine)
|
||||
AmmoSlot.Magazine = Math.max(0, mag)
|
||||
Magazine
|
||||
}
|
||||
|
||||
def MaxMagazine : Int = FireMode.Magazine
|
||||
def MaxMagazine : Int = {
|
||||
val fmode = FireMode
|
||||
fmode.CustomMagazine.get(AmmoType) match {
|
||||
case Some(magSize) =>
|
||||
magSize
|
||||
case None =>
|
||||
fmode.Magazine
|
||||
}
|
||||
}
|
||||
|
||||
def Discharge : Int = {
|
||||
Magazine = FireMode.Discharge(this)
|
||||
|
|
@ -98,6 +109,8 @@ class Tool(private val toolDef : ToolDefinition) extends Equipment with FireMode
|
|||
override def toString : String = Tool.toString(this)
|
||||
}
|
||||
|
||||
//AmmoType = Definition.AmmoTypes( (Definition.FireModes(fireModeIndex)).AmmoTypeIndices( (ammoSlots((Definition.FireModes(fireModeIndex)).AmmoSlotIndex)).AmmoTypeIndex) ).AmmoType
|
||||
|
||||
object Tool {
|
||||
def apply(toolDef : ToolDefinition) : Tool = {
|
||||
new Tool(toolDef)
|
||||
|
|
@ -107,10 +120,10 @@ object Tool {
|
|||
* Use the `*Definition` that was provided to this object to initialize its fields and settings.
|
||||
* @param tool the `Tool` being initialized
|
||||
*/
|
||||
def LoadDefinition(tool : Tool) : List[FireModeSlot] = {
|
||||
def LoadDefinition(tool : Tool) : Unit = {
|
||||
val tdef : ToolDefinition = tool.Definition
|
||||
val maxSlot = tdef.FireModes.maxBy(fmode => fmode.AmmoSlotIndex).AmmoSlotIndex
|
||||
buildFireModes(tdef, (0 to maxSlot).iterator, tdef.FireModes.toList)
|
||||
tool.ammoSlots = buildFireModes(tdef, (0 to maxSlot).iterator, tdef.FireModes.toList)
|
||||
}
|
||||
|
||||
@tailrec private def buildFireModes(tdef : ToolDefinition, iter : Iterator[Int], fmodes : List[FireModeDefinition], list : List[FireModeSlot] = Nil) : List[FireModeSlot] = {
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ import scala.annotation.tailrec
|
|||
class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServerObject
|
||||
with FactionAffinity
|
||||
with Mountable
|
||||
with MountedWeapons
|
||||
with Deployment
|
||||
with Container {
|
||||
private var faction : PlanetSideEmpire.Value = PlanetSideEmpire.TR
|
||||
|
|
@ -371,38 +372,6 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a valid seat number, retrieve an index where the weapon controlled from this seat is mounted.
|
||||
* @param seatNumber the seat number
|
||||
* @return a mounted weapon by index, or `None` if either the seat doesn't exist or there is no controlled weapon
|
||||
*/
|
||||
def WeaponControlledFromSeat(seatNumber : Int) : Option[Equipment] = {
|
||||
Seat(seatNumber) match {
|
||||
case Some(seat) =>
|
||||
wepFromSeat(seat)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
private def wepFromSeat(seat : Seat) : Option[Equipment] = {
|
||||
seat.ControlledWeapon match {
|
||||
case Some(index) =>
|
||||
wepFromSeat(index)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
private def wepFromSeat(wepIndex : Int) : Option[Equipment] = {
|
||||
weapons.get(wepIndex) match {
|
||||
case Some(wep) =>
|
||||
wep.Equipment
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def Utilities : Map[Int, Utility] = utilities
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ object EquipmentSize extends Enumeration {
|
|||
Rifle, //6x3 and 9x3
|
||||
Max, //max weapon only
|
||||
VehicleWeapon, //vehicle-mounted weapons
|
||||
BaseTurretWeapon, //common phalanx cannons, and cavern turrets
|
||||
BFRArmWeapon, //duel arm weapons for bfr
|
||||
BFRGunnerWeapon, //gunner seat for bfr
|
||||
Inventory //reserved
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@ class FireModeDefinition {
|
|||
private var ammoSlotIndex : Int = 0
|
||||
/** how many rounds are replenished each reload cycle */
|
||||
private var magazine : Int = 1
|
||||
/** how many rounds are replenished each reload cycle, per type of ammunition loaded
|
||||
* key - ammo type index, value - magazine capacity*/
|
||||
private val customAmmoMagazine : mutable.HashMap[Ammo.Value, Int] = mutable.HashMap[Ammo.Value, Int]()
|
||||
/** how much is subtracted from the magazine each fire cycle;
|
||||
* most weapons will only fire 1 round per fire cycle; the flamethrower in fire mode 1 fires 50 */
|
||||
private var rounds : Int = 1
|
||||
|
|
@ -53,6 +56,14 @@ class FireModeDefinition {
|
|||
Magazine
|
||||
}
|
||||
|
||||
def CustomMagazine : mutable.HashMap[Ammo.Value, Int] = customAmmoMagazine
|
||||
|
||||
def CustomMagazine_=(kv : (Ammo.Value, Int)) : mutable.HashMap[Ammo.Value, Int] = {
|
||||
val (ammoTypeIndex, cap) = kv
|
||||
customAmmoMagazine += ammoTypeIndex -> cap
|
||||
CustomMagazine
|
||||
}
|
||||
|
||||
def Rounds : Int = rounds
|
||||
|
||||
def Rounds_=(round : Int) : Int = {
|
||||
|
|
|
|||
|
|
@ -82,4 +82,4 @@ object ResourceSilo {
|
|||
obj.Actor ! "startup"
|
||||
obj
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,224 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import net.psforever.objects.{EquipmentSlot, Player}
|
||||
import net.psforever.objects.definition.SeatDefinition
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.inventory.{Container, GridInventory}
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.objects.serverobject.turret.MannedTurret.MannedTurretWeapon
|
||||
import net.psforever.objects.vehicles.{MountedWeapons, Seat => Chair}
|
||||
|
||||
class MannedTurret(tDef : MannedTurretDefinition) extends Amenity
|
||||
with FactionAffinity
|
||||
with Mountable
|
||||
with MountedWeapons
|
||||
with Container {
|
||||
private var health : Int = 1
|
||||
private var jammered : Boolean = false
|
||||
/** manned turrets have just one seat; this is just standard interface */
|
||||
private val seats : Map[Int, Chair] = Map(0 -> Chair(new SeatDefinition() { ControlledWeapon = Some(1) }))
|
||||
/** manned turrets have just one weapon; this is just standard interface */
|
||||
private var weapons : Map[Int, EquipmentSlot] = Map.empty
|
||||
/** may or may not have inaccessible inventory space
|
||||
* see `ReserveAmmunition` in the definition */
|
||||
private val inventory : GridInventory = new GridInventory() {
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
override def Remove(index : Int) : Boolean = false
|
||||
override def Remove(guid : PlanetSideGUID) : Boolean = false
|
||||
}
|
||||
/** some turrets can be updated; they all start without updates */
|
||||
private var upgradePath : TurretUpgrade.Value = TurretUpgrade.None
|
||||
|
||||
MannedTurret.LoadDefinition(this)
|
||||
|
||||
def Health : Int = {
|
||||
health
|
||||
}
|
||||
|
||||
def Health_=(toHealth : Int) : Int = {
|
||||
health = toHealth
|
||||
health
|
||||
}
|
||||
|
||||
def MaxHealth : Int = {
|
||||
Definition.MaxHealth
|
||||
}
|
||||
|
||||
def Seats : Map[Int, Chair] = seats
|
||||
|
||||
def Seat(seatNum : Int) : Option[Chair] = seats.get(seatNum)
|
||||
|
||||
/**
|
||||
* Given the index of an entry mounting point, return the infantry-accessible `Seat` associated with it.
|
||||
* @param mountPoint an index representing the seat position / mounting point
|
||||
* @return a seat number, or `None`
|
||||
*/
|
||||
def GetSeatFromMountPoint(mountPoint : Int) : Option[Int] = {
|
||||
Definition.MountPoints.get(mountPoint)
|
||||
}
|
||||
|
||||
def MountPoints : Map[Int, Int] = Definition.MountPoints.toMap
|
||||
|
||||
def PassengerInSeat(user : Player) : Option[Int] = {
|
||||
if(seats(0).Occupant.contains(user)) {
|
||||
Some(0)
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def Weapons : Map[Int, EquipmentSlot] = weapons.filter({ case(index, _) => index < 2 })
|
||||
|
||||
def ControlledWeapon(wepNumber : Int) : Option[Equipment] = {
|
||||
if(VisibleSlots.contains(wepNumber)) {
|
||||
weapons(wepNumber).Equipment
|
||||
}
|
||||
else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def Inventory : GridInventory = inventory
|
||||
|
||||
def VisibleSlots : Set[Int] = Set(1)
|
||||
|
||||
def Upgrade : TurretUpgrade.Value = upgradePath
|
||||
|
||||
def Upgrade_=(upgrade : TurretUpgrade.Value) : TurretUpgrade.Value = {
|
||||
upgradePath = upgrade
|
||||
//upgrade each weapon as long as that weapon has a valid option for that upgrade
|
||||
Definition.Weapons.foreach({ case(index, upgradePaths) =>
|
||||
if(upgradePaths.contains(upgrade)) {
|
||||
weapons(index).Equipment.get.asInstanceOf[MannedTurretWeapon].Upgrade = upgrade
|
||||
}
|
||||
})
|
||||
Upgrade
|
||||
}
|
||||
|
||||
def Jammered : Boolean = jammered
|
||||
|
||||
def Jammered_=(jamState : Boolean) : Boolean = {
|
||||
jammered = jamState
|
||||
Jammered
|
||||
}
|
||||
|
||||
def Definition : MannedTurretDefinition = tDef
|
||||
}
|
||||
|
||||
object MannedTurret {
|
||||
/**
|
||||
* Overloaded constructor.
|
||||
* @param tDef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
|
||||
* @return a `MannedTurret` object
|
||||
*/
|
||||
def apply(tDef : MannedTurretDefinition) : MannedTurret = {
|
||||
new MannedTurret(tDef)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the `*Definition` that was provided to this object to initialize its fields and settings.
|
||||
* @param turret the `MannedTurret` being initialized
|
||||
* @see `{object}.LoadDefinition`
|
||||
*/
|
||||
def LoadDefinition(turret : MannedTurret) : MannedTurret = {
|
||||
import net.psforever.objects.equipment.EquipmentSize.BaseTurretWeapon
|
||||
val tdef : MannedTurretDefinition = turret.Definition
|
||||
//general stuff
|
||||
turret.Health = tdef.MaxHealth
|
||||
//create weapons; note the class
|
||||
turret.weapons = tdef.Weapons.map({case (num, upgradePaths) =>
|
||||
val slot = EquipmentSlot(BaseTurretWeapon)
|
||||
slot.Equipment = new MannedTurretWeapon(tdef, upgradePaths.toMap)
|
||||
num -> slot
|
||||
}).toMap
|
||||
//special inventory ammunition object(s)
|
||||
if(tdef.ReserveAmmunition) {
|
||||
val allAmmunitionTypes = tdef.Weapons.values.flatMap{ _.values.flatMap { _.AmmoTypes } }.toSet
|
||||
if(allAmmunitionTypes.nonEmpty) {
|
||||
turret.inventory.Resize(allAmmunitionTypes.size, 1)
|
||||
var i : Int = 0
|
||||
allAmmunitionTypes.foreach(ammotype => {
|
||||
turret.inventory.InsertQuickly(i, new TurretAmmoBox(ammotype))
|
||||
i += 1
|
||||
})
|
||||
}
|
||||
}
|
||||
turret
|
||||
}
|
||||
|
||||
import net.psforever.objects.definition.ToolDefinition
|
||||
import net.psforever.objects.Tool
|
||||
/**
|
||||
* A stateful weapon that is mounted in `MannedTurrets`
|
||||
* and may maintains a group of upgraded forms that can by swapped
|
||||
* without reconstructing the weapon object itself or managing object registration.
|
||||
* @param mdef the turret's definition
|
||||
* @param udefs a map of turret upgrades to tool definitions that would be constructed by this weapon
|
||||
* @param default the default upgrade state;
|
||||
* defaults to `None`
|
||||
*/
|
||||
private class MannedTurretWeapon(mdef : MannedTurretDefinition, udefs : Map[TurretUpgrade.Value, ToolDefinition], default : TurretUpgrade.Value = TurretUpgrade.None)
|
||||
extends Tool(udefs(default)) {
|
||||
private var upgradePath : TurretUpgrade.Value = default
|
||||
|
||||
def Upgrade : TurretUpgrade.Value = {
|
||||
/*
|
||||
Must check `not null` due to how this object's `Definition` will be called during `Tool`'s constructor
|
||||
before the internal value can be set to default value `None`
|
||||
*/
|
||||
Option(upgradePath) match {
|
||||
case Some(value) =>
|
||||
value
|
||||
case None =>
|
||||
default
|
||||
}
|
||||
}
|
||||
|
||||
def Upgrade_=(upgrade : TurretUpgrade.Value) : TurretUpgrade.Value = {
|
||||
if(udefs.contains(upgrade)) {
|
||||
val beforeUpgrade = upgradePath
|
||||
upgradePath = upgrade
|
||||
if(beforeUpgrade != upgradePath) {
|
||||
Tool.LoadDefinition(this) //rebuild weapon internal structure
|
||||
FireModeIndex = 0 //reset fire mode; this option is always valid
|
||||
}
|
||||
}
|
||||
Upgrade
|
||||
}
|
||||
|
||||
override def Definition = udefs(Upgrade)
|
||||
}
|
||||
|
||||
import net.psforever.objects.definition.AmmoBoxDefinition
|
||||
import net.psforever.objects.AmmoBox
|
||||
|
||||
/**
|
||||
* A special type of ammunition box contained within a `MannedTurret` for the purposes of infinite reloads.
|
||||
* The original quantity of ammunition does not change.
|
||||
* @param adef ammunition definition
|
||||
*/
|
||||
private class TurretAmmoBox(private val adef : AmmoBoxDefinition) extends AmmoBox(adef, Some(65535)) {
|
||||
import net.psforever.objects.inventory.InventoryTile
|
||||
override def Tile = InventoryTile.Tile11
|
||||
|
||||
override def Capacity_=(toCapacity : Int) = Capacity
|
||||
}
|
||||
|
||||
import akka.actor.ActorContext
|
||||
/**
|
||||
* Instantiate an configure a `MannedTurret` object
|
||||
* @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 `MannedTurret` object
|
||||
*/
|
||||
def Constructor(tdef : MannedTurretDefinition)(id : Int, context : ActorContext) : MannedTurret = {
|
||||
import akka.actor.Props
|
||||
val obj = MannedTurret(tdef)
|
||||
obj.Actor = context.actorOf(Props(classOf[MannedTurretControl], obj), s"${tdef.Name}_$id")
|
||||
obj
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
|
||||
/**
|
||||
* An `Actor` that handles messages being dispatched to a specific `MannedTurret`.<br>
|
||||
* <br>
|
||||
* Mounted turrets have only slightly different entry requirements than a normal vehicle
|
||||
* because they encompass both faction-specific facility turrets
|
||||
* and faction-blind cavern sentry turrets.
|
||||
* @param turret the `MannedTurret` object being governed
|
||||
*/
|
||||
class MannedTurretControl(turret : MannedTurret) extends Actor
|
||||
with FactionAffinityBehavior.Check
|
||||
with MountableBehavior.Dismount {
|
||||
def MountableObject = turret //do not add type!
|
||||
|
||||
def FactionObject : FactionAffinity = turret
|
||||
|
||||
def receive : Receive = checkBehavior
|
||||
.orElse(dismountBehavior)
|
||||
.orElse {
|
||||
case Mountable.TryMount(user, seat_num) =>
|
||||
turret.Seat(seat_num) match {
|
||||
case Some(seat) =>
|
||||
if((!turret.Definition.FactionLocked || user.Faction == turret.Faction) &&
|
||||
(seat.Occupant = user).contains(user)) {
|
||||
user.VehicleSeated = turret.GUID
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanMount(turret, seat_num))
|
||||
}
|
||||
else {
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(turret, seat_num))
|
||||
}
|
||||
case None =>
|
||||
sender ! Mountable.MountMessages(user, Mountable.CanNotMount(turret, seat_num))
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import net.psforever.objects.definition.{ObjectDefinition, ToolDefinition}
|
||||
import net.psforever.objects.vehicles.Turrets
|
||||
|
||||
import scala.collection.mutable
|
||||
|
||||
/**
|
||||
* The definition for any `MannedTurret`.
|
||||
* @param objectId the object's identifier number
|
||||
*/
|
||||
class MannedTurretDefinition(private val objectId : Int) extends ObjectDefinition(objectId) {
|
||||
Turrets(objectId) //let throw NoSuchElementException
|
||||
|
||||
private var maxHealth : Int = 100
|
||||
/* key - entry point index, value - seat index */
|
||||
private val mountPoints : mutable.HashMap[Int, Int] = mutable.HashMap()
|
||||
/* key - seat number, value - hash map (below) */
|
||||
/* key - upgrade, value - weapon definition */
|
||||
private val weapons : mutable.HashMap[Int, mutable.HashMap[TurretUpgrade.Value, ToolDefinition]] =
|
||||
mutable.HashMap[Int, mutable.HashMap[TurretUpgrade.Value, ToolDefinition]]()
|
||||
/** can only be mounted by owning faction when `true` */
|
||||
private var factionLocked : Boolean = true
|
||||
/** creates internal ammunition reserves that can not become depleted
|
||||
* see `MannedTurret.TurretAmmoBox` for details */
|
||||
private var hasReserveAmmunition : Boolean = false
|
||||
|
||||
def MaxHealth : Int = maxHealth
|
||||
|
||||
def MaxHealth_=(health : Int) : Int = {
|
||||
maxHealth = health
|
||||
MaxHealth
|
||||
}
|
||||
|
||||
def MountPoints : mutable.HashMap[Int, Int] = mountPoints
|
||||
|
||||
def Weapons : mutable.HashMap[Int, mutable.HashMap[TurretUpgrade.Value, ToolDefinition]] = weapons
|
||||
|
||||
def FactionLocked : Boolean = factionLocked
|
||||
|
||||
def FactionLocked_=(ownable : Boolean) : Boolean = {
|
||||
factionLocked = ownable
|
||||
FactionLocked
|
||||
}
|
||||
|
||||
def ReserveAmmunition : Boolean = hasReserveAmmunition
|
||||
|
||||
def ReserveAmmunition_=(reserved : Boolean) : Boolean = {
|
||||
hasReserveAmmunition = reserved
|
||||
ReserveAmmunition
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
/**
|
||||
* An `Enumeration` of the available turret upgrade states.
|
||||
*/
|
||||
object TurretUpgrade extends Enumeration {
|
||||
val
|
||||
None, //default, always
|
||||
AVCombo, //phalanx_avcombo
|
||||
FlakCombo //phalanx_flakcombo
|
||||
= Value
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vehicles
|
||||
|
||||
import net.psforever.objects.{EquipmentSlot, PlanetSideGameObject}
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.inventory.Container
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.vehicles.{Seat => Chair}
|
||||
|
||||
trait MountedWeapons {
|
||||
this : PlanetSideGameObject with Mountable with Container =>
|
||||
|
||||
def Weapons : Map[Int, EquipmentSlot]
|
||||
|
||||
/**
|
||||
* Given a valid seat number, retrieve an index where the weapon controlled from this seat is mounted.
|
||||
* @param seatNumber the seat number
|
||||
* @return a mounted weapon by index, or `None` if either the seat doesn't exist or there is no controlled weapon
|
||||
*/
|
||||
def WeaponControlledFromSeat(seatNumber : Int) : Option[Equipment] = {
|
||||
Seat(seatNumber) match {
|
||||
case Some(seat) =>
|
||||
wepFromSeat(seat)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
private def wepFromSeat(seat : Chair) : Option[Equipment] = {
|
||||
seat.ControlledWeapon match {
|
||||
case Some(index) =>
|
||||
ControlledWeapon(index)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
def ControlledWeapon(wepNumber : Int) : Option[Equipment]
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.vehicles
|
||||
|
||||
/**
|
||||
* An `Enumeration` of all the turret type objectss in the game, paired with their object id as the `Value`.
|
||||
*/
|
||||
object Turrets extends Enumeration {
|
||||
val manned_turret = Value(480)
|
||||
val vanu_sentry_turret = Value(943)
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import net.psforever.objects.guid.selector.RandomSelector
|
|||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, Building}
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.serverobject.turret.MannedTurret
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
|
|
@ -93,7 +94,8 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
transport = context.actorOf(Props(classOf[ZoneVehicleActor], this, vehicles), s"$Id-vehicles")
|
||||
population = context.actorOf(Props(classOf[ZonePopulationActor], this, players, corpses), s"$Id-players")
|
||||
|
||||
Map.LocalObjects.foreach({ builderObject => builderObject.Build })
|
||||
BuildLocalObjects(context, guid)
|
||||
BuildSupportObjects()
|
||||
MakeBuildings(context)
|
||||
AssignAmenities()
|
||||
CreateSpawnGroups()
|
||||
|
|
@ -279,6 +281,39 @@ class Zone(private val zoneId : String, zoneMap : ZoneMap, zoneNumber : Int) {
|
|||
buildings.get(id)
|
||||
}
|
||||
|
||||
private def BuildLocalObjects(implicit context : ActorContext, guid : NumberPoolHub) : Unit = {
|
||||
Map.LocalObjects.foreach({ builderObject => builderObject.Build })
|
||||
}
|
||||
|
||||
private def BuildSupportObjects() : Unit = {
|
||||
//guard against errors here, but don't worry about specifics; let ZoneActor.ZoneSetupCheck complain about problems
|
||||
//turret to weapon
|
||||
Map.TurretToWeapon.foreach({ case ((turret_guid, weapon_guid)) =>
|
||||
((GUID(turret_guid) match {
|
||||
case Some(obj : MannedTurret) =>
|
||||
Some(obj)
|
||||
case _ => ;
|
||||
None
|
||||
}) match {
|
||||
case Some(obj) =>
|
||||
obj.Weapons.get(1) match {
|
||||
case Some(slot) =>
|
||||
Some(obj, slot.Equipment)
|
||||
case None =>
|
||||
None
|
||||
}
|
||||
case None =>
|
||||
None
|
||||
}) match {
|
||||
case Some((obj, Some(weapon : Tool))) =>
|
||||
guid.register(weapon, weapon_guid)
|
||||
weapon.AmmoSlots.foreach(slot => guid.register(slot.Box, "dynamic"))
|
||||
obj.Inventory.Items.foreach(item => guid.register(item.obj, "dynamic")) //internal ammunition reserves, if any
|
||||
case _ => ;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private def MakeBuildings(implicit context : ActorContext) : PairMap[Int, Building] = {
|
||||
val buildingList = Map.LocalBuildings
|
||||
buildings = buildingList.map({case(building_id, constructor) => building_id -> constructor.Build(building_id, this) })
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ package net.psforever.objects.zones
|
|||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject}
|
||||
import net.psforever.objects.{GlobalDefinitions, PlanetSideGameObject, Tool}
|
||||
import net.psforever.objects.serverobject.structures.StructureType
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.vehicles.UtilityType
|
||||
|
|
@ -171,73 +171,24 @@ class ZoneActor(zone : Zone) extends Actor {
|
|||
validateObject(mech_guid, ImplantMechCheck, "implant terminal mech")
|
||||
validateObject(interface_guid, TerminalCheck, "implant terminal interface")
|
||||
})
|
||||
|
||||
//check manned turret to weapon association
|
||||
map.TurretToWeapon.foreach({ case ((turret_guid, weapon_guid)) =>
|
||||
validateObject(turret_guid, MannedTurretCheck, "manned turret mount")
|
||||
if(validateObject(weapon_guid, WeaponCheck, "manned turret weapon")) {
|
||||
if(guid(weapon_guid).get.asInstanceOf[Tool].AmmoSlots.count(!_.Box.HasGUID) > 0) {
|
||||
slog.error(s"expected weapon $weapon_guid has an unregistered ammunition unit")
|
||||
errors.incrementAndGet()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
//output number of errors
|
||||
errors.intValue()
|
||||
}
|
||||
}
|
||||
|
||||
object ZoneActor {
|
||||
// import net.psforever.types.PlanetSideEmpire
|
||||
// import net.psforever.objects.Vehicle
|
||||
// import net.psforever.objects.serverobject.structures.Building
|
||||
// def AllSpawnGroup(zone : Zone, targetPosition : Vector3, targetFaction : PlanetSideEmpire.Value) : Option[List[SpawnTube]] = {
|
||||
// ClosestOwnedSpawnTube(AmsSpawnGroup(zone) ++ BuildingSpawnGroup(zone, 0), targetPosition, targetFaction)
|
||||
// }
|
||||
//
|
||||
// def AmsSpawnGroup(vehicles : List[Vehicle]) : Iterable[(Vector3, PlanetSideEmpire.Value, Iterable[SpawnTube])] = {
|
||||
// vehicles
|
||||
// .filter(veh => veh.DeploymentState == DriveState.Deployed && veh.Definition == GlobalDefinitions.ams)
|
||||
// .map(veh =>
|
||||
// (veh.Position, veh.Faction,
|
||||
// veh.Utilities
|
||||
// .values
|
||||
// .filter(util => util.UtilType == UtilityType.ams_respawn_tube)
|
||||
// .map { _().asInstanceOf[SpawnTube] }
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// def AmsSpawnGroup(zone : Zone, spawn_group : Int = 2) : Iterable[(Vector3, PlanetSideEmpire.Value, Iterable[SpawnTube])] = {
|
||||
// if(spawn_group == 2) {
|
||||
// AmsSpawnGroup(zone.Vehicles)
|
||||
// }
|
||||
// else {
|
||||
// Nil
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// def BuildingSpawnGroup(spawnGroups : Map[Building, List[SpawnTube]]) : Iterable[(Vector3, PlanetSideEmpire.Value, Iterable[SpawnTube])] = {
|
||||
// spawnGroups
|
||||
// .map({ case ((building, tubes)) => (building.Position.xy, building.Faction, tubes) })
|
||||
// }
|
||||
//
|
||||
// def BuildingSpawnGroup(zone : Zone, spawn_group : Int) : Iterable[(Vector3, PlanetSideEmpire.Value, Iterable[SpawnTube])] = {
|
||||
// val buildingTypeSet = if(spawn_group == 0) {
|
||||
// Set(StructureType.Facility, StructureType.Tower, StructureType.Building)
|
||||
// }
|
||||
// else if(spawn_group == 6) {
|
||||
// Set(StructureType.Tower)
|
||||
// }
|
||||
// else if(spawn_group == 7) {
|
||||
// Set(StructureType.Facility, StructureType.Building)
|
||||
// }
|
||||
// else {
|
||||
// Set.empty[StructureType.Value]
|
||||
// }
|
||||
// BuildingSpawnGroup(
|
||||
// zone.SpawnGroups().filter({ case((building, _)) => buildingTypeSet.contains(building.BuildingType) })
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// def ClosestOwnedSpawnTube(tubes : Iterable[(Vector3, PlanetSideEmpire.Value, Iterable[SpawnTube])], targetPosition : Vector3, targetFaction : PlanetSideEmpire.Value) : Option[List[SpawnTube]] = {
|
||||
// tubes
|
||||
// .toSeq
|
||||
// .filter({ case (_, faction, _) => faction == targetFaction })
|
||||
// .sortBy({ case (pos, _, _) => Vector3.DistanceSquared(pos, targetPosition) })
|
||||
// .take(1)
|
||||
// .map({ case (_, _, tubes : List[SpawnTube]) => tubes })
|
||||
// .headOption
|
||||
// }
|
||||
|
||||
/**
|
||||
* Recover an object from a collection and perform any number of validating tests upon it.
|
||||
* If the object fails any tests, log an error.
|
||||
|
|
@ -295,4 +246,14 @@ object ZoneActor {
|
|||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
obj.isInstanceOf[VehicleSpawnPad]
|
||||
}
|
||||
|
||||
def MannedTurretCheck(obj : PlanetSideGameObject) : Boolean = {
|
||||
import net.psforever.objects.serverobject.turret.MannedTurret
|
||||
obj.isInstanceOf[MannedTurret]
|
||||
}
|
||||
|
||||
def WeaponCheck(obj : PlanetSideGameObject) : Boolean = {
|
||||
import net.psforever.objects.Tool
|
||||
obj.isInstanceOf[Tool]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import net.psforever.objects.serverobject.{PlanetSideServerObject, ServerObjectB
|
|||
*/
|
||||
class ZoneMap(private val name : String) {
|
||||
private var localObjects : List[ServerObjectBuilder[_]] = List()
|
||||
private var linkTurretWeapon : Map[Int, Int] = Map()
|
||||
private var linkTerminalPad : Map[Int, Int] = Map()
|
||||
private var linkTerminalInterface : Map[Int, Int] = Map()
|
||||
private var linkDoorLock : Map[Int, Int] = Map()
|
||||
|
|
@ -87,4 +88,10 @@ class ZoneMap(private val name : String) {
|
|||
def TerminalToInterface(interface_guid : Int, terminal_guid : Int) : Unit = {
|
||||
linkTerminalInterface = linkTerminalInterface ++ Map(interface_guid -> terminal_guid)
|
||||
}
|
||||
|
||||
def TurretToWeapon : Map[Int, Int] = linkTurretWeapon
|
||||
|
||||
def TurretToWeapon(turret_guid : Int, weapon_guid : Int) : Unit = {
|
||||
linkTurretWeapon = linkTurretWeapon ++ Map(turret_guid -> weapon_guid)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,21 +33,27 @@ object HackState extends Enumeration {
|
|||
}
|
||||
|
||||
/**
|
||||
* Dispatched by the server to control the process of hacking.<br>
|
||||
* Dispatched by the server to control the progress of hacking.
|
||||
* While "hacking" is typically performed against enemy targets,
|
||||
* some actions that involve ally on ally hacking can occur.
|
||||
* In this sense, hacking can be consider change progress.<br>
|
||||
* <br>
|
||||
* Part of the hacking process is regulated by the server while another part of it is automatically reset by the client.
|
||||
* The visibility, update, and closing of the hacking progress bar must be handled manually, for each tick.
|
||||
* When hacking is complete, using the appropriate `HackState` will cue the target to be affected by the hack.
|
||||
* Terminals and door IFF panels will temporarily expose their functionality;
|
||||
* the faction association of vehicles will be converted permanently;
|
||||
* a protracted process of a base conversion will be enacted; etc..
|
||||
* This transfer of faction association occurs to align the target with the faction of the hacking player (as indicated).
|
||||
* The client will select the faction without needing to be explicitly told
|
||||
* and will select the appropriate action to enact upon the target.
|
||||
* Upon the hack's completion, the target on the client will automatically revert back to its original state, if possible.
|
||||
* (It will still be necessary to alert this change from the server's perspective.)
|
||||
* In general, the act of hacking is maintained by the server but the conclusion is managed by the client.
|
||||
* Hacking typically locks the player into a cancellable firing animation and works as all-or-nothing.
|
||||
* The progress bar window is displayed and updated each tick by the server; but, the client can cancel it on its own.
|
||||
* When hacking is complete as indicated by the appropriate `HackState`,
|
||||
* the client performs the intended action upon the target.
|
||||
* Facility amenities will temporarily ignore IFF requirements;
|
||||
* vehicles will permanently transfer control over to the hack-starter's empire;
|
||||
* facility turret weapons will temporarily convert to their anti-vehicle or anti-aircraft configurations;
|
||||
* facilities will be compromised and begin the long process of converting to the hack-starter's empire;
|
||||
* and, so forth.<br>
|
||||
* <br>
|
||||
* As mentioned, one of the unexpected uses of this message
|
||||
* will assist the conversion of allied facility turreted weapons to their upgraded armaments.
|
||||
* @param unk1 na;
|
||||
* 0 commonly;
|
||||
* 2 when performing (phalanx) upgrades;
|
||||
* 3 for building objects during login phase;
|
||||
* hack type?
|
||||
* @param target_guid the target of the hack
|
||||
|
|
|
|||
|
|
@ -7,21 +7,28 @@ import scodec.Codec
|
|||
import scodec.codecs._
|
||||
|
||||
/**
|
||||
* (Where the child object was before it was moved is not specified or important.)<br>
|
||||
* @param avatar_guid the player.
|
||||
* @param item_used_guid The "item" GUID used e.g. a rek to hack or a medkit to heal.
|
||||
* @param object_guid can be : Door, Terminal, Avatar (medkit).
|
||||
* @param unk2 ???
|
||||
* @param unk3 ??? true when use a rek (false when door, medkit or open equip term)
|
||||
* @param unk4 ???
|
||||
* @param unk5 ???
|
||||
* @param unk6 ???
|
||||
* @param unk7 ??? 25 when door 223 when terminal
|
||||
* @param unk8 ??? 0 when door 1 when use rek (252 then equipment term)
|
||||
* @param itemType object ID from game_objects.adb (ex 612 is an equipment terminal, for medkit we have 121 (avatar))
|
||||
* (Where the child object was before it was moved is not specified or important.)
|
||||
* @see `Definition.ObjectId`<br>
|
||||
* `TurretUpgrade`
|
||||
* @param avatar_guid the player
|
||||
* @param item_used_guid the item used;
|
||||
* e.g., a REK to hack, or a medkit to heal
|
||||
* @param object_guid the object affected;
|
||||
* e.g., door when opened, terminal when accessed, avatar when medkit used
|
||||
* @param unk2 na;
|
||||
* when upgrading phalanx turrets, 1 for `AVCombo` and 2 for `FlakCombo`
|
||||
* @param unk3 using tools, e.g., a REK or nano-dispenser
|
||||
* @param unk4 na
|
||||
* @param unk5 na
|
||||
* @param unk6 na
|
||||
* @param unk7 na;
|
||||
* 25 when door 223 when terminal
|
||||
* @param unk8 na;
|
||||
* 0 when door 1 when use rek (252 then equipment term)
|
||||
* @param object_id he object id for `object_guid`'s object
|
||||
*/
|
||||
final case class UseItemMessage(avatar_guid : PlanetSideGUID,
|
||||
item_used_guid : Int,
|
||||
item_used_guid : PlanetSideGUID,
|
||||
object_guid : PlanetSideGUID,
|
||||
unk2 : Long,
|
||||
unk3 : Boolean,
|
||||
|
|
@ -30,7 +37,7 @@ final case class UseItemMessage(avatar_guid : PlanetSideGUID,
|
|||
unk6 : Int,
|
||||
unk7 : Int,
|
||||
unk8 : Int,
|
||||
itemType : Long)
|
||||
object_id : Long)
|
||||
extends PlanetSideGamePacket {
|
||||
type Packet = UseItemMessage
|
||||
def opcode = GamePacketOpcode.UseItemMessage
|
||||
|
|
@ -40,7 +47,7 @@ final case class UseItemMessage(avatar_guid : PlanetSideGUID,
|
|||
object UseItemMessage extends Marshallable[UseItemMessage] {
|
||||
implicit val codec : Codec[UseItemMessage] = (
|
||||
("avatar_guid" | PlanetSideGUID.codec) ::
|
||||
("item_used_guid" | uint16L) ::
|
||||
("item_used_guid" | PlanetSideGUID.codec) ::
|
||||
("object_guid" | PlanetSideGUID.codec) ::
|
||||
("unk2" | uint32L) ::
|
||||
("unk3" | bool) ::
|
||||
|
|
@ -49,6 +56,6 @@ object UseItemMessage extends Marshallable[UseItemMessage] {
|
|||
("unk6" | uint8L) ::
|
||||
("unk7" | uint8L) ::
|
||||
("unk8" | uint8L) ::
|
||||
("itemType" | uint32L)
|
||||
("object_id" | uint32L)
|
||||
).as[UseItemMessage]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -373,6 +373,7 @@ object ObjectClass {
|
|||
final val implant_terminal_interface = 409
|
||||
final val locker_container = 456
|
||||
final val lodestar_repair_terminal = 461
|
||||
final val manned_turret = 480
|
||||
final val matrix_terminala = 517
|
||||
final val matrix_terminalb = 518
|
||||
final val matrix_terminalc = 519
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import net.psforever.objects.guid.TaskResolver
|
|||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.objects.{DefaultCancellable, PlanetSideGameObject}
|
||||
import net.psforever.types.Vector3
|
||||
import services.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions}
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
|
|
@ -29,7 +29,7 @@ import scala.concurrent.duration._
|
|||
* and finally unregistering it.
|
||||
* Some types of object have (de-)implementation variations which should be made explicit through the overrides.
|
||||
*/
|
||||
abstract class RemoverActor extends Actor {
|
||||
abstract class RemoverActor extends SupportActor[RemoverActor.Entry] {
|
||||
/**
|
||||
* The timer that checks whether entries in the first pool are still eligible for that pool.
|
||||
*/
|
||||
|
|
@ -50,16 +50,18 @@ abstract class RemoverActor extends Actor {
|
|||
|
||||
private var taskResolver : ActorRef = Actor.noSender
|
||||
|
||||
private[this] val log = org.log4s.getLogger
|
||||
def trace(msg : String) : Unit = log.trace(msg)
|
||||
def debug(msg : String) : Unit = log.debug(msg)
|
||||
val sameEntryComparator = new SimilarityComparator[RemoverActor.Entry]() {
|
||||
def Test(entry1 : RemoverActor.Entry, entry2 : RemoverActor.Entry) : Boolean = {
|
||||
entry1.obj == entry2.obj && entry1.zone == entry2.zone && entry1.obj.GUID == entry2.obj.GUID
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the initial message that requests a task resolver for assisting in the removal process.
|
||||
*/
|
||||
override def preStart() : Unit = {
|
||||
super.preStart()
|
||||
self ! RemoverActor.Startup()
|
||||
self ! Service.Startup()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,7 +84,7 @@ abstract class RemoverActor extends Actor {
|
|||
}
|
||||
|
||||
def receive : Receive = {
|
||||
case RemoverActor.Startup() =>
|
||||
case Service.Startup() =>
|
||||
ServiceManager.serviceManager ! ServiceManager.Lookup("taskResolver") //ask for a resolver to deal with the GUID system
|
||||
|
||||
case ServiceManager.LookupResult("taskResolver", endpoint) =>
|
||||
|
|
@ -90,83 +92,72 @@ abstract class RemoverActor extends Actor {
|
|||
context.become(Processing)
|
||||
|
||||
case msg =>
|
||||
log.error(s"received message $msg before being properly initialized")
|
||||
debug(s"received message $msg before being properly initialized")
|
||||
}
|
||||
|
||||
def Processing : Receive = {
|
||||
case RemoverActor.AddTask(obj, zone, duration) =>
|
||||
val entry = RemoverActor.Entry(obj, zone, duration.getOrElse(FirstStandardDuration).toNanos)
|
||||
if(InclusionTest(entry) && !secondHeap.exists(test => RemoverActor.Similarity(test, entry) )) {
|
||||
InitialJob(entry)
|
||||
if(firstHeap.isEmpty) {
|
||||
//we were the only entry so the event must be started from scratch
|
||||
firstHeap = List(entry)
|
||||
trace(s"a remover task has been added: $entry")
|
||||
RetimeFirstTask()
|
||||
}
|
||||
else {
|
||||
//unknown number of entries; append, sort, then re-time tasking
|
||||
val oldHead = firstHeap.head
|
||||
if(!firstHeap.exists(test => RemoverActor.Similarity(test, entry))) {
|
||||
firstHeap = (firstHeap :+ entry).sortBy(_.duration)
|
||||
def Processing : Receive = entryManagementBehaviors
|
||||
.orElse {
|
||||
case RemoverActor.AddTask(obj, zone, duration) =>
|
||||
val entry = RemoverActor.Entry(obj, zone, duration.getOrElse(FirstStandardDuration).toNanos)
|
||||
if(InclusionTest(entry) && !secondHeap.exists(test => sameEntryComparator.Test(test, entry) )) {
|
||||
InitialJob(entry)
|
||||
if(firstHeap.isEmpty) {
|
||||
//we were the only entry so the event must be started from scratch
|
||||
firstHeap = List(entry)
|
||||
trace(s"a remover task has been added: $entry")
|
||||
if(oldHead != firstHeap.head) {
|
||||
RetimeFirstTask()
|
||||
}
|
||||
RetimeFirstTask()
|
||||
}
|
||||
else {
|
||||
trace(s"$obj is already queued for removal")
|
||||
//unknown number of entries; append, sort, then re-time tasking
|
||||
val oldHead = firstHeap.head
|
||||
if(!firstHeap.exists(test => sameEntryComparator.Test(test, entry))) {
|
||||
firstHeap = (firstHeap :+ entry).sortBy(entry => entry.time + entry.duration)
|
||||
trace(s"a remover task has been added: $entry")
|
||||
if(oldHead != firstHeap.head) {
|
||||
RetimeFirstTask()
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace(s"$obj is already queued for removal")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace(s"$obj either does not qualify for this Remover or is already queued")
|
||||
}
|
||||
else {
|
||||
trace(s"$obj either does not qualify for this Remover or is already queued")
|
||||
}
|
||||
|
||||
case RemoverActor.HurrySpecific(targets, zone) =>
|
||||
HurrySpecific(targets, zone)
|
||||
//private messages from RemoverActor to RemoverActor
|
||||
case RemoverActor.StartDelete() =>
|
||||
firstTask.cancel
|
||||
secondTask.cancel
|
||||
val now : Long = System.nanoTime
|
||||
val (in, out) = firstHeap.partition(entry => { now - entry.time >= entry.duration })
|
||||
firstHeap = out
|
||||
secondHeap = secondHeap ++ in.map { RepackageEntry }
|
||||
in.foreach { FirstJob }
|
||||
RetimeFirstTask()
|
||||
if(secondHeap.nonEmpty) {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
secondTask = context.system.scheduler.scheduleOnce(SecondStandardDuration, self, RemoverActor.TryDelete())
|
||||
}
|
||||
trace(s"item removal task has found ${in.size} items to remove")
|
||||
|
||||
case RemoverActor.HurryAll() =>
|
||||
HurryAll()
|
||||
case RemoverActor.TryDelete() =>
|
||||
secondTask.cancel
|
||||
val (in, out) = secondHeap.partition { ClearanceTest }
|
||||
secondHeap = out
|
||||
in.foreach { SecondJob }
|
||||
if(out.nonEmpty) {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
secondTask = context.system.scheduler.scheduleOnce(SecondStandardDuration, self, RemoverActor.TryDelete())
|
||||
}
|
||||
trace(s"item removal task has removed ${in.size} items")
|
||||
|
||||
case RemoverActor.ClearSpecific(targets, zone) =>
|
||||
ClearSpecific(targets, zone)
|
||||
case RemoverActor.FailureToWork(entry, ex) =>
|
||||
debug(s"${entry.obj} from ${entry.zone} not properly deleted - $ex")
|
||||
|
||||
case RemoverActor.ClearAll() =>
|
||||
ClearAll()
|
||||
|
||||
//private messages from RemoverActor to RemoverActor
|
||||
case RemoverActor.StartDelete() =>
|
||||
firstTask.cancel
|
||||
secondTask.cancel
|
||||
val now : Long = System.nanoTime
|
||||
val (in, out) = firstHeap.partition(entry => { now - entry.time >= entry.duration })
|
||||
firstHeap = out
|
||||
secondHeap = secondHeap ++ in.map { RepackageEntry }
|
||||
in.foreach { FirstJob }
|
||||
RetimeFirstTask()
|
||||
if(secondHeap.nonEmpty) {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
secondTask = context.system.scheduler.scheduleOnce(SecondStandardDuration, self, RemoverActor.TryDelete())
|
||||
}
|
||||
trace(s"item removal task has found ${in.size} items to remove")
|
||||
|
||||
case RemoverActor.TryDelete() =>
|
||||
secondTask.cancel
|
||||
val (in, out) = secondHeap.partition { ClearanceTest }
|
||||
secondHeap = out
|
||||
in.foreach { SecondJob }
|
||||
if(out.nonEmpty) {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
secondTask = context.system.scheduler.scheduleOnce(SecondStandardDuration, self, RemoverActor.TryDelete())
|
||||
}
|
||||
trace(s"item removal task has removed ${in.size} items")
|
||||
|
||||
case RemoverActor.FailureToWork(entry, ex) =>
|
||||
log.error(s"${entry.obj} from ${entry.zone} not properly deleted - $ex")
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Expedite some entries from the first pool into the second.
|
||||
|
|
@ -175,14 +166,18 @@ abstract class RemoverActor extends Actor {
|
|||
* all targets must be in this zone, with the assumption that this is the zone where they were registered
|
||||
*/
|
||||
def HurrySpecific(targets : List[PlanetSideGameObject], zone : Zone) : Unit = {
|
||||
CullTargetsFromFirstHeap(targets, zone) match {
|
||||
case Nil =>
|
||||
PartitionTargetsFromList(firstHeap, targets.map { RemoverActor.Entry(_, zone, 0) }, zone) match {
|
||||
case (Nil, _) =>
|
||||
debug(s"no tasks matching the targets $targets have been hurried")
|
||||
case list =>
|
||||
debug(s"the following tasks have been hurried: $list")
|
||||
case (in, out) =>
|
||||
debug(s"the following tasks have been hurried: $in")
|
||||
firstHeap = out //.sortBy(entry => entry.time + entry.duration)
|
||||
if(out.nonEmpty) {
|
||||
RetimeFirstTask()
|
||||
}
|
||||
secondTask.cancel
|
||||
list.foreach { FirstJob }
|
||||
secondHeap = secondHeap ++ list.map { RepackageEntry }
|
||||
in.foreach { FirstJob }
|
||||
secondHeap = secondHeap ++ in.map { RepackageEntry }
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
secondTask = context.system.scheduler.scheduleOnce(SecondStandardDuration, self, RemoverActor.TryDelete())
|
||||
}
|
||||
|
|
@ -206,11 +201,15 @@ abstract class RemoverActor extends Actor {
|
|||
* Remove specific entries from the first pool.
|
||||
*/
|
||||
def ClearSpecific(targets : List[PlanetSideGameObject], zone : Zone) : Unit = {
|
||||
CullTargetsFromFirstHeap(targets, zone) match {
|
||||
case Nil =>
|
||||
PartitionTargetsFromList(firstHeap, targets.map { RemoverActor.Entry(_, zone, 0) }, zone) match {
|
||||
case (Nil, _) =>
|
||||
debug(s"no tasks matching the targets $targets have been cleared")
|
||||
case list =>
|
||||
debug(s"the following tasks have been cleared: $list")
|
||||
case (in, out) =>
|
||||
debug(s"the following tasks have been cleared: $in")
|
||||
firstHeap = out //.sortBy(entry => entry.time + entry.duration)
|
||||
if(out.nonEmpty) {
|
||||
RetimeFirstTask()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -232,68 +231,6 @@ abstract class RemoverActor extends Actor {
|
|||
RemoverActor.Entry(entry.obj, entry.zone, SecondStandardDuration.toNanos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the first pool of entries awaiting removal processing.
|
||||
* If any entry has the same object as one of the targets and belongs to the same zone, remove it from the first pool.
|
||||
* If no targets are selected (an empty list), all discovered targets within the appropriate zone are removed.
|
||||
* @param targets a list of objects to pick
|
||||
* @param zone the zone in which these objects must be discovered;
|
||||
* all targets must be in this zone, with the assumption that this is the zone where they were registered
|
||||
* @return all of the discovered entries
|
||||
*/
|
||||
private def CullTargetsFromFirstHeap(targets : List[PlanetSideGameObject], zone : Zone) : List[RemoverActor.Entry] = {
|
||||
val culledEntries = if(targets.nonEmpty) {
|
||||
if(targets.size == 1) {
|
||||
debug(s"a target submitted: ${targets.head}")
|
||||
//simple selection
|
||||
RemoverActor.recursiveFind(firstHeap.iterator, RemoverActor.Entry(targets.head, zone, 0)) match {
|
||||
case None => ;
|
||||
Nil
|
||||
case Some(index) =>
|
||||
val entry = firstHeap(index)
|
||||
firstHeap = (firstHeap.take(index) ++ firstHeap.drop(index + 1)).sortBy(_.duration)
|
||||
List(entry)
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug(s"multiple targets submitted: $targets")
|
||||
//cumbersome partition
|
||||
//a - find targets from entries
|
||||
val locatedTargets = for {
|
||||
a <- targets.map(RemoverActor.Entry(_, zone, 0))
|
||||
b <- firstHeap//.filter(entry => entry.zone == zone)
|
||||
if b.obj.HasGUID && a.obj.HasGUID && RemoverActor.Similarity(b, a)
|
||||
} yield b
|
||||
if(locatedTargets.nonEmpty) {
|
||||
//b - entries, after the found targets are removed (cull any non-GUID entries while at it)
|
||||
firstHeap = (for {
|
||||
a <- locatedTargets
|
||||
b <- firstHeap
|
||||
if b.obj.HasGUID && a.obj.HasGUID && !RemoverActor.Similarity(b, a)
|
||||
} yield b).sortBy(_.duration)
|
||||
locatedTargets
|
||||
}
|
||||
else {
|
||||
Nil
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug(s"all targets within the specified zone $zone will be submitted")
|
||||
//no specific targets; split on all targets in the given zone instead
|
||||
val (in, out) = firstHeap.partition(entry => entry.zone == zone)
|
||||
firstHeap = out.sortBy(_.duration)
|
||||
in
|
||||
}
|
||||
if(culledEntries.nonEmpty) {
|
||||
RetimeFirstTask()
|
||||
culledEntries
|
||||
}
|
||||
else {
|
||||
Nil
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Common function to reset the first task's delayed execution.
|
||||
* Cancels the scheduled timer and will only restart the timer if there is at least one entry in the first pool.
|
||||
|
|
@ -353,15 +290,6 @@ abstract class RemoverActor extends Actor {
|
|||
*/
|
||||
def SecondStandardDuration : FiniteDuration
|
||||
|
||||
/**
|
||||
* Determine whether or not the resulting entry is valid for this removal process.
|
||||
* The primary purpose of this function should be to determine if the appropriate type of object is being submitted.
|
||||
* Override.
|
||||
* @param entry the entry
|
||||
* @return `true`, if it can be processed; `false`, otherwise
|
||||
*/
|
||||
def InclusionTest(entry : RemoverActor.Entry) : Boolean
|
||||
|
||||
/**
|
||||
* Performed when the entry is initially added to the first list.
|
||||
* Override.
|
||||
|
|
@ -392,23 +320,15 @@ abstract class RemoverActor extends Actor {
|
|||
def DeletionTask(entry : RemoverActor.Entry) : TaskResolver.GiveTask
|
||||
}
|
||||
|
||||
object RemoverActor {
|
||||
object RemoverActor extends SupportActorCaseConversions {
|
||||
/**
|
||||
* All information necessary to apply to the removal process to produce an effect.
|
||||
* Internally, all entries have a "time created" field.
|
||||
* @param obj the target
|
||||
* @param zone the zone in which this target is registered
|
||||
* @param duration how much longer the target will exist in its current state (in nanoseconds)
|
||||
* @param _obj the target
|
||||
* @param _zone the zone in which this target is registered
|
||||
* @param _duration how much longer the target will exist in its current state (in nanoseconds)
|
||||
*/
|
||||
case class Entry(obj : PlanetSideGameObject, zone : Zone, duration : Long) {
|
||||
/** The time when this entry was created (in nanoseconds) */
|
||||
val time : Long = System.nanoTime
|
||||
}
|
||||
|
||||
/**
|
||||
* A message that prompts the retrieval of a `TaskResolver` for us in the removal process.
|
||||
*/
|
||||
case class Startup()
|
||||
case class Entry(_obj : PlanetSideGameObject, _zone : Zone, _duration : Long) extends SupportActor.Entry(_obj, _zone, _duration)
|
||||
|
||||
/**
|
||||
* Message to submit an object to the removal process.
|
||||
|
|
@ -420,36 +340,6 @@ object RemoverActor {
|
|||
*/
|
||||
case class AddTask(obj : PlanetSideGameObject, zone : Zone, duration : Option[FiniteDuration] = None)
|
||||
|
||||
/**
|
||||
* "Hurrying" shifts entries with the discovered objects (in the same `zone`)
|
||||
* through their first task and into the second pool.
|
||||
* If the list of targets is empty, all discovered objects in the given zone will be considered targets.
|
||||
* @param targets a list of objects to match
|
||||
* @param zone the zone in which these objects exist;
|
||||
* the assumption is that all these target objects are registered to this zone
|
||||
*/
|
||||
case class HurrySpecific(targets : List[PlanetSideGameObject], zone : Zone)
|
||||
/**
|
||||
* "Hurrying" shifts all entries through their first task and into the second pool.
|
||||
*/
|
||||
case class HurryAll()
|
||||
|
||||
/**
|
||||
* "Clearing" cancels entries with the discovered objects (in the same `zone`)
|
||||
* if they are discovered in the first pool of objects.
|
||||
* Those entries will no longer be affected by any actions performed by the removal process until re-submitted.
|
||||
* If the list of targets is empty, all discovered objects in the given zone will be considered targets.
|
||||
* @param targets a list of objects to match
|
||||
* @param zone the zone in which these objects exist;
|
||||
* the assumption is that all these target objects are registered to this zone
|
||||
*/
|
||||
case class ClearSpecific(targets : List[PlanetSideGameObject], zone : Zone)
|
||||
/**
|
||||
* "Clearing" cancels all entries if they are discovered in the first pool of objects.
|
||||
* Those entries will no longer be affected by any actions performed by the removal process until re-submitted.
|
||||
*/
|
||||
case class ClearAll()
|
||||
|
||||
/**
|
||||
* Message that indicates that the final stage of the remover process has failed.
|
||||
* Since the last step is generally unregistering the object, it could be a critical error.
|
||||
|
|
@ -467,36 +357,4 @@ object RemoverActor {
|
|||
* Internal message to flag operations by data in the second list if it has been in that list long enough.
|
||||
*/
|
||||
private final case class TryDelete()
|
||||
|
||||
/**
|
||||
* Match two entries by object and by zone information.
|
||||
* @param entry1 the first entry
|
||||
* @param entry2 the second entry
|
||||
* @return if they match
|
||||
*/
|
||||
private def Similarity(entry1 : RemoverActor.Entry, entry2 : RemoverActor.Entry) : Boolean = {
|
||||
entry1.obj == entry2.obj && entry1.zone == entry2.zone && entry1.obj.GUID == entry2.obj.GUID
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the index of an entry in the list of entries.
|
||||
* @param iter an `Iterator` of entries
|
||||
* @param target the specific entry to be found
|
||||
* @param index the incrementing index value
|
||||
* @return the index of the entry in the list, if a match to the target is found
|
||||
*/
|
||||
@tailrec private def recursiveFind(iter : Iterator[RemoverActor.Entry], target : RemoverActor.Entry, index : Int = 0) : Option[Int] = {
|
||||
if(!iter.hasNext) {
|
||||
None
|
||||
}
|
||||
else {
|
||||
val entry = iter.next
|
||||
if(entry.obj.HasGUID && target.obj.HasGUID && Similarity(entry, target)) {
|
||||
Some(index)
|
||||
}
|
||||
else {
|
||||
recursiveFind(iter, target, index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import net.psforever.packet.game.PlanetSideGUID
|
|||
object Service {
|
||||
final val defaultPlayerGUID : PlanetSideGUID = PlanetSideGUID(0)
|
||||
|
||||
final case class Startup()
|
||||
final case class Join(channel : String)
|
||||
final case class Leave(channel : Option[String] = None)
|
||||
final case class LeaveAll()
|
||||
|
|
|
|||
|
|
@ -0,0 +1,12 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.support
|
||||
|
||||
abstract class SimilarityComparator[A <: SupportActor.Entry] {
|
||||
/**
|
||||
* Match two entries by object and by zone information.
|
||||
* @param entry1 the first entry
|
||||
* @param entry2 the second entry
|
||||
* @return if they match
|
||||
*/
|
||||
def Test(entry1 : A, entry2 : A) : Boolean
|
||||
}
|
||||
155
common/src/main/scala/services/support/SupportActor.scala
Normal file
155
common/src/main/scala/services/support/SupportActor.scala
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.support
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.zones.Zone
|
||||
|
||||
import scala.annotation.tailrec
|
||||
|
||||
abstract class SupportActor[A <: SupportActor.Entry] extends Actor {
|
||||
private[this] val log = org.log4s.getLogger
|
||||
def info(msg : String) : Unit = log.info(msg)
|
||||
def trace(msg : String) : Unit = log.trace(msg)
|
||||
def debug(msg : String) : Unit = log.debug(msg)
|
||||
|
||||
def sameEntryComparator : SimilarityComparator[A]
|
||||
|
||||
/**
|
||||
* Determine whether or not the resulting entry is valid for this process.
|
||||
* The primary purpose of this function should be to determine if the appropriate type of object is being submitted.
|
||||
* Override.
|
||||
* @param entry the entry
|
||||
* @return `true`, if it can be processed; `false`, otherwise
|
||||
*/
|
||||
def InclusionTest(entry : A) : Boolean
|
||||
|
||||
def entryManagementBehaviors : Receive = {
|
||||
case SupportActor.HurrySpecific(targets, zone) =>
|
||||
HurrySpecific(targets, zone)
|
||||
|
||||
case SupportActor.HurryAll() =>
|
||||
HurryAll()
|
||||
|
||||
case SupportActor.ClearSpecific(targets, zone) =>
|
||||
ClearSpecific(targets, zone)
|
||||
|
||||
case SupportActor.ClearAll() =>
|
||||
ClearAll()
|
||||
}
|
||||
|
||||
def HurrySpecific(targets : List[PlanetSideGameObject], zone : Zone) : Unit
|
||||
|
||||
def HurryAll()
|
||||
|
||||
def ClearSpecific(targets : List[PlanetSideGameObject], zone : Zone) : Unit
|
||||
|
||||
def ClearAll() : Unit
|
||||
|
||||
/*
|
||||
* Search the first pool of entries awaiting removal processing.
|
||||
* If any entry has the same object as one of the targets and belongs to the same zone, remove it from the first pool.
|
||||
* If no targets are selected (an empty list), all discovered targets within the appropriate zone are removed.
|
||||
* @param targets a list of objects to pick
|
||||
* @param zone the zone in which these objects must be discovered;
|
||||
* all targets must be in this zone, with the assumption that this is the zone where they were registered
|
||||
* @return all of the discovered entries
|
||||
*/
|
||||
def PartitionTargetsFromList(list : List[A], targets : List[A], zone : Zone, comparator : SimilarityComparator[A] = sameEntryComparator) : (List[A], List[A]) = {
|
||||
if(targets.nonEmpty) {
|
||||
if(targets.size == 1) {
|
||||
debug(s"a target submitted: ${targets.head}")
|
||||
//simple selection
|
||||
SupportActor.recursiveFind(comparator)(list.iterator, targets.head) match {
|
||||
case None => ;
|
||||
(Nil, list)
|
||||
case Some(index) =>
|
||||
(List(list(index)), list.take(index) ++ list.drop(index + 1))
|
||||
}
|
||||
}
|
||||
else {
|
||||
debug(s"multiple targets submitted: $targets")
|
||||
//cumbersome partition
|
||||
//a - find targets from entries
|
||||
val locatedTargets = for {
|
||||
a <- targets
|
||||
b <- list//.filter(entry => entry.zone == zone)
|
||||
if b.obj.HasGUID && a.obj.HasGUID && comparator.Test(b, a)
|
||||
} yield b
|
||||
if(locatedTargets.nonEmpty) {
|
||||
//b - entries, after the found targets are removed (cull any non-GUID entries while at it)
|
||||
val retained = for {
|
||||
a <- locatedTargets
|
||||
b <- list
|
||||
if b.obj.HasGUID && a.obj.HasGUID && !comparator.Test(b, a)
|
||||
} yield b
|
||||
(locatedTargets, retained)
|
||||
}
|
||||
else {
|
||||
(Nil, list)
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
list.partition(entry => entry.zone == zone)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object SupportActor {
|
||||
class Entry(val obj : PlanetSideGameObject, val zone : Zone, val duration : Long) {
|
||||
val time : Long = System.nanoTime
|
||||
}
|
||||
|
||||
/**
|
||||
* "Hurrying" shifts entries with the discovered objects (in the same `zone`)
|
||||
* through their first task and into the second pool.
|
||||
* If the list of targets is empty, all discovered objects in the given zone will be considered targets.
|
||||
* @param targets a list of objects to match
|
||||
* @param zone the zone in which these objects exist;
|
||||
* the assumption is that all these target objects are registered to this zone
|
||||
*/
|
||||
case class HurrySpecific(targets : List[PlanetSideGameObject], zone : Zone)
|
||||
/**
|
||||
* "Hurrying" shifts all entries through their first task and into the second pool.
|
||||
*/
|
||||
case class HurryAll()
|
||||
|
||||
/**
|
||||
* "Clearing" cancels entries with the discovered objects (in the same `zone`)
|
||||
* if they are discovered in the first pool of objects.
|
||||
* Those entries will no longer be affected by any actions performed by the removal process until re-submitted.
|
||||
* If the list of targets is empty, all discovered objects in the given zone will be considered targets.
|
||||
* @param targets a list of objects to match
|
||||
* @param zone the zone in which these objects exist;
|
||||
* the assumption is that all these target objects are registered to this zone
|
||||
*/
|
||||
case class ClearSpecific(targets : List[PlanetSideGameObject], zone : Zone)
|
||||
/**
|
||||
* "Clearing" cancels all entries if they are discovered in the first pool of objects.
|
||||
* Those entries will no longer be affected by any actions performed by the removal process until re-submitted.
|
||||
*/
|
||||
case class ClearAll()
|
||||
|
||||
/**
|
||||
* Get the index of an entry in the list of entries.
|
||||
* @param iter an `Iterator` of entries
|
||||
* @param target the specific entry to be found
|
||||
* @param index the incrementing index value
|
||||
* @return the index of the entry in the list, if a match to the target is found
|
||||
*/
|
||||
@tailrec private def recursiveFind[A <: SupportActor.Entry](comparator : SimilarityComparator[A])(iter : Iterator[A], target : A, index : Int = 0) : Option[Int] = {
|
||||
if(!iter.hasNext) {
|
||||
None
|
||||
}
|
||||
else {
|
||||
val entry = iter.next
|
||||
if(entry.obj.HasGUID && target.obj.HasGUID && comparator.Test(entry, target)) {
|
||||
Some(index)
|
||||
}
|
||||
else {
|
||||
recursiveFind(comparator)(iter, target, index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.support
|
||||
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.zones.Zone
|
||||
|
||||
trait SupportActorCaseConversions {
|
||||
/**
|
||||
* A mask for converting between a class local and `SupportActor.HurrySpecific`.
|
||||
* @param targets a list of objects to match
|
||||
* @param zone the zone in which these objects exist
|
||||
* @return a `SupportActor.HurrySpecific` object
|
||||
*/
|
||||
def HurrySpecific(targets : List[PlanetSideGameObject], zone : Zone) : SupportActor.HurrySpecific =
|
||||
SupportActor.HurrySpecific(targets, zone)
|
||||
|
||||
/**
|
||||
* A mask for converting between a class local and `SupportActor.HurryAll`.
|
||||
* @return a `SupportActor.HurryAll` object
|
||||
*/
|
||||
def HurryAll() : SupportActor.HurryAll = SupportActor.HurryAll()
|
||||
|
||||
/**
|
||||
* A mask for converting between a class local and `SupportActor.ClearSpecific`.
|
||||
* @param targets a list of objects to match
|
||||
* @param zone the zone in which these objects exist
|
||||
* @return a `SupportActor.ClearSpecific` object
|
||||
*/
|
||||
def ClearSpecific(targets : List[PlanetSideGameObject], zone : Zone) : SupportActor.ClearSpecific =
|
||||
SupportActor.ClearSpecific(targets, zone)
|
||||
|
||||
/**
|
||||
* A mask for converting between a class local and `SupportActor.ClearAll`.
|
||||
* @return a `SupportActor.ClearAll` object
|
||||
*/
|
||||
def ClearAll() : SupportActor.ClearAll = SupportActor.ClearAll()
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ object VehicleAction {
|
|||
final case class ChildObjectState(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Action
|
||||
final case class DeployRequest(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Action
|
||||
final case class DismountVehicle(player_guid : PlanetSideGUID, bailType : BailType.Value, unk2 : Boolean) extends Action
|
||||
final case class EquipmentInSlot(player_guid : PlanetSideGUID, target_guid : PlanetSideGUID, slot : Int, equipment : Equipment) extends Action
|
||||
final case class InventoryState(player_guid : PlanetSideGUID, obj : PlanetSideGameObject, parent_guid : PlanetSideGUID, start : Int, con_data : ConstructorData) extends Action
|
||||
final case class InventoryState2(player_guid : PlanetSideGUID, obj_guid : PlanetSideGUID, parent_guid : PlanetSideGUID, value : Int) extends Action
|
||||
final case class KickPassenger(player_guid : PlanetSideGUID, unk1 : Int, unk2 : Boolean, vehicle_guid : PlanetSideGUID) extends Action
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.vehicle
|
||||
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.{PlanetSideGameObject, Vehicle}
|
||||
import net.psforever.packet.PlanetSideGamePacket
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
|
||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||
import net.psforever.types.{BailType, DriveState, Vector3}
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ object VehicleResponse {
|
|||
final case class DeployRequest(object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Response
|
||||
final case class DetachFromRails(vehicle_guid : PlanetSideGUID, rails_guid : PlanetSideGUID, rails_pos : Vector3, rails_rot : Float) extends Response
|
||||
final case class DismountVehicle(bailType : BailType.Value , unk2 : Boolean) extends Response
|
||||
final case class EquipmentInSlot(pkt : ObjectCreateMessage) extends Response
|
||||
final case class InventoryState(obj : PlanetSideGameObject, parent_guid : PlanetSideGUID, start : Int, con_data : ConstructorData) extends Response
|
||||
final case class InventoryState2(obj_guid : PlanetSideGUID, parent_guid : PlanetSideGUID, value : Int) extends Response
|
||||
final case class KickPassenger(seat_num : Int, kickedByDriver : Boolean, vehicle_guid : PlanetSideGUID) extends Response
|
||||
|
|
|
|||
|
|
@ -4,7 +4,9 @@ package services.vehicle
|
|||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.zones.Zone
|
||||
import services.vehicle.support.VehicleRemover
|
||||
import net.psforever.packet.game.ObjectCreateMessage
|
||||
import net.psforever.packet.game.objectcreate.ObjectCreateMessageParent
|
||||
import services.vehicle.support.{TurretUpgrader, VehicleRemover}
|
||||
import net.psforever.types.DriveState
|
||||
import services.{GenericEventBus, RemoverActor, Service}
|
||||
|
||||
|
|
@ -12,6 +14,7 @@ import scala.concurrent.duration._
|
|||
|
||||
class VehicleService extends Actor {
|
||||
private val vehicleDecon : ActorRef = context.actorOf(Props[VehicleRemover], "vehicle-decon-agent")
|
||||
private val turretUpgrade : ActorRef = context.actorOf(Props[TurretUpgrader], "turret-upgrade-agent")
|
||||
private [this] val log = org.log4s.getLogger
|
||||
|
||||
override def preStart = {
|
||||
|
|
@ -53,6 +56,18 @@ class VehicleService extends Actor {
|
|||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.DismountVehicle(bailType, unk2))
|
||||
)
|
||||
case VehicleAction.EquipmentInSlot(player_guid, target_guid, slot, equipment) =>
|
||||
val definition = equipment.Definition
|
||||
val pkt = ObjectCreateMessage(
|
||||
definition.ObjectId,
|
||||
equipment.GUID,
|
||||
ObjectCreateMessageParent(target_guid, slot),
|
||||
definition.Packet.ConstructorData(equipment).get
|
||||
)
|
||||
ObjectCreateMessageParent(target_guid, slot)
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.EquipmentInSlot(pkt))
|
||||
)
|
||||
case VehicleAction.InventoryState(player_guid, obj, parent_guid, start, con_data) =>
|
||||
VehicleEvents.publish(
|
||||
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.InventoryState(obj, parent_guid, start, con_data))
|
||||
|
|
@ -114,6 +129,10 @@ class VehicleService extends Actor {
|
|||
case VehicleServiceMessage.Decon(msg) =>
|
||||
vehicleDecon forward msg
|
||||
|
||||
//message to TurretUpgrader
|
||||
case VehicleServiceMessage.TurretUpgrade(msg) =>
|
||||
turretUpgrade forward msg
|
||||
|
||||
//from VehicleSpawnControl
|
||||
case VehicleSpawnPad.ConcealPlayer(player_guid, zone_id) =>
|
||||
VehicleEvents.publish(
|
||||
|
|
|
|||
|
|
@ -12,5 +12,7 @@ object VehicleServiceMessage {
|
|||
|
||||
final case class Decon(msg : Any)
|
||||
|
||||
final case class TurretUpgrade(msg : Any)
|
||||
|
||||
final case class AMSDeploymentChange(zone : Zone)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,260 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.vehicle.support
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||
import net.psforever.objects.{AmmoBox, DefaultCancellable, PlanetSideGameObject, Tool}
|
||||
import net.psforever.objects.guid.{GUIDTask, Task, TaskResolver}
|
||||
import net.psforever.objects.serverobject.turret.{MannedTurret, TurretUpgrade}
|
||||
import net.psforever.objects.vehicles.MountedWeapons
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import services.support.{SimilarityComparator, SupportActor, SupportActorCaseConversions}
|
||||
import services.vehicle.{VehicleAction, VehicleServiceMessage}
|
||||
import services.{Service, ServiceManager}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class TurretUpgrader extends SupportActor[TurretUpgrader.Entry] {
|
||||
var task : Cancellable = DefaultCancellable.obj
|
||||
|
||||
var list : List[TurretUpgrader.Entry] = List()
|
||||
|
||||
private var taskResolver : ActorRef = Actor.noSender
|
||||
|
||||
val sameEntryComparator = new SimilarityComparator[TurretUpgrader.Entry]() {
|
||||
def Test(entry1 : TurretUpgrader.Entry, entry2 : TurretUpgrader.Entry) : Boolean = {
|
||||
entry1.obj == entry2.obj && entry1.zone == entry2.zone && entry1.obj.GUID == entry2.obj.GUID
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the initial message that requests a task resolver for assisting in the removal process.
|
||||
*/
|
||||
override def preStart() : Unit = {
|
||||
super.preStart()
|
||||
self ! Service.Startup()
|
||||
}
|
||||
|
||||
/**
|
||||
* Sufficiently clean up the current contents of these waiting removal jobs.
|
||||
* Cancel all timers, rush all entries in the lists through their individual steps, then empty the lists.
|
||||
* This is an improved `HurryAll`.
|
||||
*/
|
||||
override def postStop() : Unit = {
|
||||
super.postStop()
|
||||
task.cancel
|
||||
list.foreach { UpgradeTurretAmmo }
|
||||
list = Nil
|
||||
taskResolver = ActorRef.noSender
|
||||
}
|
||||
|
||||
def CreateEntry(obj : PlanetSideGameObject, zone : Zone, upgrade : TurretUpgrade.Value, duration : Long) = TurretUpgrader.Entry(obj, zone, upgrade, duration)
|
||||
|
||||
def InclusionTest(entry : TurretUpgrader.Entry) : Boolean = entry.obj.isInstanceOf[MannedTurret]
|
||||
|
||||
def receive : Receive = {
|
||||
case Service.Startup() =>
|
||||
ServiceManager.serviceManager ! ServiceManager.Lookup("taskResolver") //ask for a resolver to deal with the GUID system
|
||||
|
||||
case ServiceManager.LookupResult("taskResolver", endpoint) =>
|
||||
taskResolver = endpoint
|
||||
context.become(Processing)
|
||||
|
||||
case msg =>
|
||||
debug(s"received message $msg before being properly initialized")
|
||||
}
|
||||
|
||||
def Processing : Receive = entryManagementBehaviors
|
||||
.orElse {
|
||||
case TurretUpgrader.AddTask(turret, zone, upgrade, duration) =>
|
||||
val lengthOfTime = duration.getOrElse(TurretUpgrader.StandardUpgradeLifetime).toNanos
|
||||
if(lengthOfTime > (1 second).toNanos) { //don't even bother if it's too short; it'll revert near instantly
|
||||
val entry = CreateEntry(turret, zone, TurretUpgrade.None, lengthOfTime)
|
||||
UpgradeTurretAmmo(CreateEntry(turret, zone, upgrade, lengthOfTime))
|
||||
if(list.isEmpty) {
|
||||
//we were the only entry so the event must be started from scratch
|
||||
list = List(entry)
|
||||
trace(s"a task has been added: $entry")
|
||||
RetimeFirstTask()
|
||||
}
|
||||
else{
|
||||
val oldHead = list.head
|
||||
if(!list.exists(test => TurretUpgrader.Similarity(test, entry))) {
|
||||
list = (list :+ entry).sortBy(entry => entry.time + entry.duration)
|
||||
trace(s"a task has been added: $entry")
|
||||
if(oldHead != list.head) {
|
||||
RetimeFirstTask()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case TurretUpgrader.Downgrade() =>
|
||||
task.cancel
|
||||
val now : Long = System.nanoTime
|
||||
val (in, out) = list.partition(entry => { now - entry.time >= entry.duration }) //&& entry.obj.Seats.values.count(_.isOccupied) == 0
|
||||
list = out
|
||||
in.foreach { UpgradeTurretAmmo }
|
||||
RetimeFirstTask()
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
def RetimeFirstTask(now : Long = System.nanoTime) : Unit = {
|
||||
task.cancel
|
||||
if(list.nonEmpty) {
|
||||
val short_timeout : FiniteDuration = math.max(1, list.head.duration - (now - list.head.time)) nanoseconds
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
task = context.system.scheduler.scheduleOnce(short_timeout, self, TurretUpgrader.Downgrade())
|
||||
}
|
||||
}
|
||||
|
||||
def HurrySpecific(targets : List[PlanetSideGameObject], zone : Zone) : Unit = {
|
||||
PartitionTargetsFromList(list, targets.map { TurretUpgrader.Entry(_, zone, TurretUpgrade.None, 0) }, zone) match {
|
||||
case (Nil, _) =>
|
||||
debug(s"no tasks matching the targets $targets have been hurried")
|
||||
case (in, out) =>
|
||||
debug(s"the following tasks have been hurried: $in")
|
||||
in.foreach { UpgradeTurretAmmo }
|
||||
list = out //.sortBy(entry => entry.time + entry.duration)
|
||||
if(out.nonEmpty) {
|
||||
RetimeFirstTask()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def HurryAll() : Unit = {
|
||||
trace("all tasks have been hurried")
|
||||
task.cancel
|
||||
list.foreach { UpgradeTurretAmmo }
|
||||
list = Nil
|
||||
}
|
||||
|
||||
def ClearSpecific(targets : List[PlanetSideGameObject], zone : Zone) : Unit = {
|
||||
PartitionTargetsFromList(list, targets.map { TurretUpgrader.Entry(_, zone, TurretUpgrade.None, 0) }, zone) match {
|
||||
case (Nil, _) =>
|
||||
debug(s"no tasks matching the targets $targets have been cleared")
|
||||
case (in, out) =>
|
||||
debug(s"the following tasks have been cleared: $in")
|
||||
list = out //.sortBy(entry => entry.time + entry.duration)
|
||||
if(out.nonEmpty) {
|
||||
RetimeFirstTask()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def ClearAll() : Unit = {
|
||||
task.cancel
|
||||
list = Nil
|
||||
}
|
||||
|
||||
/**
|
||||
* The process of upgrading a turret is nearly complete.
|
||||
* After the upgrade status is changed, the internal structure of the turret's weapons change to suit the configuration.
|
||||
* Of special importance are internal ammo supplies of the changing weapon,
|
||||
* the original ammunition that must be un-registered,
|
||||
* and the new boxes that must be registered so the weapon may be introduced into the game world properly.
|
||||
* @param entry na
|
||||
*/
|
||||
def UpgradeTurretAmmo(entry : TurretUpgrader.Entry) : Unit = {
|
||||
val target = entry.obj.asInstanceOf[MannedTurret]
|
||||
val zone = entry.zone
|
||||
val zoneId = zone.Id
|
||||
val upgrade = entry.upgrade
|
||||
val guid = zone.GUID
|
||||
val turretGUID = target.GUID
|
||||
//kick all occupying players for duration of conversion
|
||||
target.Seats.values
|
||||
.filter { _.isOccupied }
|
||||
.foreach({seat =>
|
||||
val tplayer = seat.Occupant.get
|
||||
seat.Occupant = None
|
||||
tplayer.VehicleSeated = None
|
||||
if(tplayer.HasGUID) {
|
||||
context.parent ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(tplayer.GUID, 4, false, turretGUID))
|
||||
}
|
||||
})
|
||||
info(s"Converting manned wall turret weapon to $upgrade")
|
||||
|
||||
val oldBoxesTask = AllMountedWeaponMagazines(target)
|
||||
.map(box => GUIDTask.UnregisterEquipment(box)(guid))
|
||||
.toList
|
||||
target.Upgrade = upgrade //perform upgrade
|
||||
|
||||
val newBoxesTask = TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val localFunc : ()=>Unit = FinishUpgradingTurret(entry)
|
||||
|
||||
override def isComplete = Task.Resolution.Success
|
||||
|
||||
def Execute(resolver : ActorRef) : Unit = {
|
||||
localFunc()
|
||||
resolver ! scala.util.Success(this)
|
||||
}
|
||||
}, AllMountedWeaponMagazines(target).map(box => GUIDTask.RegisterEquipment(box)(guid)).toList
|
||||
)
|
||||
taskResolver ! TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
def Execute(resolver : ActorRef) : Unit = {
|
||||
resolver ! scala.util.Success(this)
|
||||
}
|
||||
}, oldBoxesTask :+ newBoxesTask
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* From an object that has mounted weapons, parse all of the internal ammunition loaded into all of the weapons.
|
||||
* @param target the object with mounted weaponry
|
||||
* @return all of the internal ammunition objects
|
||||
*/
|
||||
def AllMountedWeaponMagazines(target : MountedWeapons) : Iterable[AmmoBox] = {
|
||||
target.Weapons
|
||||
.values
|
||||
.map { _.Equipment }
|
||||
.collect { case Some(tool : Tool) => tool.AmmoSlots }
|
||||
.flatMap { _.map { _.Box } }
|
||||
}
|
||||
|
||||
/**
|
||||
* Finish upgrading the turret by announcing to other players that the weapon type has changed.
|
||||
* By this point, a prior required action that required that new ammunition objects had to be registered.
|
||||
* It is now safe to announce that clients can update to the new weapon.
|
||||
* @param entry na
|
||||
*/
|
||||
def FinishUpgradingTurret(entry : TurretUpgrader.Entry)() : Unit = {
|
||||
val target = entry.obj.asInstanceOf[MannedTurret]
|
||||
val zone = entry.zone
|
||||
info(s"Wall turret finished ${target.Upgrade} upgrade")
|
||||
val targetGUID = target.GUID
|
||||
target.Weapons
|
||||
.map({ case (index, slot) => (index, slot.Equipment) })
|
||||
.collect { case (index, Some(tool : Tool)) =>
|
||||
context.parent ! VehicleServiceMessage(
|
||||
zone.Id,
|
||||
VehicleAction.EquipmentInSlot(PlanetSideGUID(0), targetGUID, index, tool)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object TurretUpgrader extends SupportActorCaseConversions {
|
||||
private val StandardUpgradeLifetime : FiniteDuration = 30 minutes
|
||||
|
||||
/**
|
||||
* All information necessary to apply to the removal process to produce an effect.
|
||||
* Internally, all entries have a "time created" field.
|
||||
* @param _obj the target
|
||||
* @param _zone the zone in which this target is registered
|
||||
* @param upgrade the next upgrade state for this turret
|
||||
* @param _duration how much longer the target will exist in its current state (in nanoseconds)
|
||||
*/
|
||||
case class Entry(_obj : PlanetSideGameObject, _zone : Zone, upgrade : TurretUpgrade.Value, _duration : Long) extends SupportActor.Entry(_obj, _zone, _duration)
|
||||
|
||||
final case class AddTask(turret : MannedTurret, zone : Zone, upgrade : TurretUpgrade.Value, duration : Option[FiniteDuration] = None)
|
||||
|
||||
final case class Downgrade()
|
||||
|
||||
private def Similarity(entry1 : TurretUpgrader.Entry, entry2 : TurretUpgrader.Entry) : Boolean = {
|
||||
entry1.obj == entry2.obj && entry1.zone == entry2.zone && entry1.obj.GUID == entry2.obj.GUID
|
||||
}
|
||||
}
|
||||
51
common/src/test/scala/base/ActorTest.scala
Normal file
51
common/src/test/scala/base/ActorTest.scala
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
package base
|
||||
|
||||
// Copyright (c) 2017 PSForever
|
||||
import akka.actor.ActorSystem
|
||||
import akka.testkit.{ImplicitSender, TestKit}
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
|
||||
import org.specs2.specification.Scope
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
|
||||
abstract class ActorTest(sys : ActorSystem = ActorSystem("system", ConfigFactory.parseMap(ActorTest.LoggingConfig)))
|
||||
extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
override def afterAll {
|
||||
TestKit.shutdownActorSystem(system)
|
||||
}
|
||||
}
|
||||
|
||||
object ActorTest {
|
||||
import scala.collection.JavaConverters._
|
||||
private val LoggingConfig = Map(
|
||||
"akka.loggers" -> List("akka.testkit.TestEventListener").asJava,
|
||||
"akka.loglevel" -> "OFF",
|
||||
"akka.stdout-loglevel" -> "OFF",
|
||||
"akka.log-dead-letters" -> "OFF"
|
||||
).asJava
|
||||
|
||||
/**
|
||||
* A (potential) workaround to a Travis CI issue involving polling a series of messages over a period of time.
|
||||
* Running the test in isolation works every time.
|
||||
* Running the test as part of a series produces mixed results.
|
||||
* Travis CI fails the test every time by not getting any messages.
|
||||
* @see TestKit.receiveN
|
||||
* @param n the number of messages to poll
|
||||
* @param timeout how long to wait for each message
|
||||
* @param sys what to poll
|
||||
* @return a list of messages
|
||||
*/
|
||||
def receiveMultiple(n : Int, timeout : FiniteDuration, sys : TestKit) : List[Any] = {
|
||||
assert(0 < n, s"number of expected messages must be positive non-zero integer - $n")
|
||||
val out = {
|
||||
val msgs = mutable.ListBuffer[Any]()
|
||||
(0 until n).foreach(_ => {
|
||||
msgs += sys.receiveOne(timeout)
|
||||
})
|
||||
msgs.toList
|
||||
}
|
||||
out
|
||||
}
|
||||
}
|
||||
|
|
@ -14,7 +14,7 @@ class UseItemMessageTest extends Specification {
|
|||
PacketCoding.DecodePacket(string).require match {
|
||||
case UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType) =>
|
||||
avatar_guid mustEqual PlanetSideGUID(75)
|
||||
unk1 mustEqual 0
|
||||
unk1 mustEqual PlanetSideGUID(0)
|
||||
object_guid mustEqual PlanetSideGUID(372)
|
||||
unk2 mustEqual 0xFFFFFFFFL
|
||||
unk3 mustEqual false
|
||||
|
|
@ -30,7 +30,7 @@ class UseItemMessageTest extends Specification {
|
|||
}
|
||||
|
||||
"encode" in {
|
||||
val msg = UseItemMessage(PlanetSideGUID(75), 0, PlanetSideGUID(372), 0xFFFFFFFFL, false, Vector3(5.0f, 0.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), 11, 25, 0, 364)
|
||||
val msg = UseItemMessage(PlanetSideGUID(75), PlanetSideGUID(0), PlanetSideGUID(372), 0xFFFFFFFFL, false, Vector3(5.0f, 0.0f, 0.0f), Vector3(0.0f, 0.0f, 0.0f), 11, 25, 0, 364)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.ActorSystem
|
||||
import akka.testkit.{ImplicitSender, TestKit}
|
||||
import com.typesafe.config.{ConfigFactory, ConfigValueFactory}
|
||||
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
|
||||
import org.specs2.specification.Scope
|
||||
|
||||
abstract class ActorTest(sys : ActorSystem = ActorSystem("system", ConfigFactory.parseMap(ActorTest.LoggingConfig)))
|
||||
extends TestKit(sys) with Scope with ImplicitSender with WordSpecLike with Matchers with BeforeAndAfterAll {
|
||||
override def afterAll {
|
||||
TestKit.shutdownActorSystem(system)
|
||||
}
|
||||
}
|
||||
|
||||
object ActorTest {
|
||||
import scala.collection.JavaConverters._
|
||||
private val LoggingConfig = Map(
|
||||
"akka.loggers" -> List("akka.testkit.TestEventListener").asJava,
|
||||
"akka.loglevel" -> "OFF",
|
||||
"akka.stdout-loglevel" -> "OFF",
|
||||
"akka.log-dead-letters" -> "OFF"
|
||||
).asJava
|
||||
}
|
||||
|
|
@ -3,6 +3,7 @@ package objects
|
|||
|
||||
import akka.actor.Props
|
||||
import akka.testkit.TestProbe
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Vehicle}
|
||||
import net.psforever.objects.serverobject.pad.process.{AutoDriveControls, VehicleSpawnControlGuided}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
|
|
@ -128,12 +129,11 @@ class BuildingControl2Test extends ActorTest {
|
|||
val bldg = Building(10, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
bldg.Actor = system.actorOf(Props(classOf[BuildingControl], bldg), "test")
|
||||
bldg.Actor ! "startup"
|
||||
|
||||
"Building Control" should {
|
||||
"convert and assert faction affinity on convert request" in {
|
||||
expectNoMsg(250 milliseconds)
|
||||
bldg.Actor ! "startup"
|
||||
expectNoMsg(250 milliseconds)
|
||||
expectNoMsg(500 milliseconds)
|
||||
|
||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||
bldg.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.VS)
|
||||
|
|
@ -159,12 +159,11 @@ class BuildingControl3Test extends ActorTest {
|
|||
door2.Actor = system.actorOf(Props(classOf[DoorControl], door2), "door2-test")
|
||||
bldg.Amenities = door2
|
||||
bldg.Amenities = door1
|
||||
bldg.Actor ! "startup"
|
||||
|
||||
"Building Control" should {
|
||||
"convert and assert faction affinity on convert request, and for each of its amenities" in {
|
||||
expectNoMsg(250 milliseconds)
|
||||
bldg.Actor ! "startup"
|
||||
expectNoMsg(250 milliseconds)
|
||||
expectNoMsg(500 milliseconds)
|
||||
|
||||
assert(bldg.Faction == PlanetSideEmpire.TR)
|
||||
assert(bldg.Amenities.length == 2)
|
||||
|
|
@ -172,7 +171,8 @@ class BuildingControl3Test extends ActorTest {
|
|||
assert(bldg.Amenities(1) == door1)
|
||||
|
||||
bldg.Actor ! FactionAffinity.ConvertFactionAffinity(PlanetSideEmpire.VS)
|
||||
val reply = receiveN(3, Duration.create(500, "ms"))
|
||||
val reply = ActorTest.receiveMultiple(3, 500 milliseconds, this)
|
||||
//val reply = receiveN(3, Duration.create(5000, "ms"))
|
||||
assert(reply.length == 3)
|
||||
var building_count = 0
|
||||
var door_count = 0
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{Actor, ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||
import net.psforever.objects.serverobject.deploy.{Deployment, DeploymentBehavior}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.objects.serverobject.doors.{Door, DoorControl}
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||
|
|
@ -42,7 +43,7 @@ class DoorTest extends Specification {
|
|||
}
|
||||
|
||||
"be opened and closed (2; toggle)" in {
|
||||
val msg = UseItemMessage(PlanetSideGUID(6585), 0, PlanetSideGUID(372), 4294967295L, false, Vector3(5.0f,0.0f,0.0f), Vector3(0.0f,0.0f,0.0f), 11, 25, 0, 364)
|
||||
val msg = UseItemMessage(PlanetSideGUID(6585), PlanetSideGUID(0), PlanetSideGUID(372), 4294967295L, false, Vector3(5.0f,0.0f,0.0f), Vector3(0.0f,0.0f,0.0f), 11, 25, 0, 364)
|
||||
val door = Door(GlobalDefinitions.door)
|
||||
door.Open mustEqual None
|
||||
door.Use(player, msg)
|
||||
|
|
@ -74,7 +75,7 @@ class DoorTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class DoorControl1Test extends ActorTest() {
|
||||
class DoorControl1Test extends ActorTest {
|
||||
"DoorControl" should {
|
||||
"construct" in {
|
||||
val door = Door(GlobalDefinitions.door)
|
||||
|
|
@ -84,11 +85,11 @@ class DoorControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class DoorControl2Test extends ActorTest() {
|
||||
class DoorControl2Test extends ActorTest {
|
||||
"DoorControl" should {
|
||||
"open on use" in {
|
||||
val (player, door) = DoorControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
val msg = UseItemMessage(PlanetSideGUID(1), 0, PlanetSideGUID(2), 0L, false, Vector3(0f,0f,0f),Vector3(0f,0f,0f),0,0,0,0L) //faked
|
||||
val msg = UseItemMessage(PlanetSideGUID(1), PlanetSideGUID(0), PlanetSideGUID(2), 0L, false, Vector3(0f,0f,0f),Vector3(0f,0f,0f),0,0,0,0L) //faked
|
||||
assert(door.Open.isEmpty)
|
||||
|
||||
door.Actor ! Door.Use(player, msg)
|
||||
|
|
@ -103,7 +104,7 @@ class DoorControl2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class DoorControl3Test extends ActorTest() {
|
||||
class DoorControl3Test extends ActorTest {
|
||||
"DoorControl" should {
|
||||
"do nothing if given garbage" in {
|
||||
val (_, door) = DoorControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{Actor, ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
|
|
@ -55,7 +56,7 @@ class FactionAffinityTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class FactionAffinity1Test extends ActorTest() {
|
||||
class FactionAffinity1Test extends ActorTest {
|
||||
"FactionAffinity" should {
|
||||
"assert affinity on confirm request" in {
|
||||
val obj = FactionAffinityTest.SetUpAgent
|
||||
|
|
@ -71,7 +72,7 @@ class FactionAffinity1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class FactionAffinity2Test extends ActorTest() {
|
||||
class FactionAffinity2Test extends ActorTest {
|
||||
"FactionAffinity" should {
|
||||
"assert affinity on assert request" in {
|
||||
val obj = FactionAffinityTest.SetUpAgent
|
||||
|
|
@ -87,7 +88,7 @@ class FactionAffinity2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class FactionAffinity3Test extends ActorTest() {
|
||||
class FactionAffinity3Test extends ActorTest {
|
||||
"FactionAffinity" should {
|
||||
"convert and assert affinity on convert request" in {
|
||||
val obj = FactionAffinityTest.SetUpAgent
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.objects.serverobject.locks.{IFFLock, IFFLockControl}
|
||||
|
|
@ -22,7 +23,7 @@ class IFFLockTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class IFFLockControl1Test extends ActorTest() {
|
||||
class IFFLockControl1Test extends ActorTest {
|
||||
"IFFLockControl" should {
|
||||
"construct" in {
|
||||
val lock = IFFLock(GlobalDefinitions.lock_external)
|
||||
|
|
@ -32,7 +33,7 @@ class IFFLockControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class IFFLockControl2Test extends ActorTest() {
|
||||
class IFFLockControl2Test extends ActorTest {
|
||||
"IFFLockControl" should {
|
||||
"can hack" in {
|
||||
val (player, lock) = IFFLockControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -46,7 +47,7 @@ class IFFLockControl2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class IFFLockControl3Test extends ActorTest() {
|
||||
class IFFLockControl3Test extends ActorTest {
|
||||
"IFFLockControl" should {
|
||||
"can hack" in {
|
||||
val (player, lock) = IFFLockControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinity
|
||||
import net.psforever.objects.serverobject.mblocker.{Locker, LockerControl}
|
||||
|
|
|
|||
179
common/src/test/scala/objects/MannedTurretTest.scala
Normal file
179
common/src/test/scala/objects/MannedTurretTest.scala
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Tool}
|
||||
import net.psforever.objects.definition.ToolDefinition
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||
import net.psforever.objects.serverobject.turret.{MannedTurret, MannedTurretControl, MannedTurretDefinition, TurretUpgrade}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class MannedTurretTest extends Specification {
|
||||
"MannedTurretTest" should {
|
||||
"define" in {
|
||||
val obj = new MannedTurretDefinition(480)
|
||||
obj.Weapons mustEqual mutable.HashMap.empty[TurretUpgrade.Value, ToolDefinition]
|
||||
obj.ReserveAmmunition mustEqual false
|
||||
obj.FactionLocked mustEqual true
|
||||
obj.MaxHealth mustEqual 100
|
||||
obj.MountPoints mustEqual mutable.HashMap.empty[Int,Int]
|
||||
}
|
||||
|
||||
"construct" in {
|
||||
val obj = MannedTurret(GlobalDefinitions.manned_turret)
|
||||
obj.Weapons.size mustEqual 1
|
||||
obj.Weapons(1).Equipment match {
|
||||
case Some(tool : Tool) =>
|
||||
tool.Definition mustEqual GlobalDefinitions.phalanx_sgl_hevgatcan
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
obj.Seats.size mustEqual 1
|
||||
obj.Seats(0).ControlledWeapon mustEqual Some(1)
|
||||
obj.MountPoints.size mustEqual 1
|
||||
obj.MountPoints(1) mustEqual 0
|
||||
obj.Health mustEqual 3600
|
||||
obj.Upgrade mustEqual TurretUpgrade.None
|
||||
obj.Jammered mustEqual false
|
||||
|
||||
obj.Health = 360
|
||||
obj.Health mustEqual 360
|
||||
obj.Jammered = true
|
||||
obj.Jammered mustEqual true
|
||||
}
|
||||
|
||||
"upgrade to a different weapon" in {
|
||||
val obj = MannedTurret(GlobalDefinitions.manned_turret)
|
||||
obj.Upgrade = TurretUpgrade.None
|
||||
obj.Weapons(1).Equipment match {
|
||||
case Some(tool : Tool) =>
|
||||
tool.Definition mustEqual GlobalDefinitions.phalanx_sgl_hevgatcan
|
||||
tool.FireModeIndex mustEqual 0
|
||||
tool.NextFireMode
|
||||
tool.FireModeIndex mustEqual 0 //one fire mode
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
//upgrade
|
||||
obj.Upgrade = TurretUpgrade.AVCombo
|
||||
obj.Weapons(1).Equipment match {
|
||||
case Some(tool : Tool) =>
|
||||
tool.Definition mustEqual GlobalDefinitions.phalanx_avcombo
|
||||
tool.FireModeIndex mustEqual 0
|
||||
tool.ProjectileType mustEqual GlobalDefinitions.phalanx_projectile.ProjectileType
|
||||
tool.NextFireMode
|
||||
tool.FireModeIndex mustEqual 1
|
||||
tool.ProjectileType mustEqual GlobalDefinitions.phalanx_av_projectile.ProjectileType
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
//revert
|
||||
obj.Upgrade = TurretUpgrade.None
|
||||
obj.Weapons(1).Equipment match {
|
||||
case Some(tool : Tool) =>
|
||||
tool.Definition mustEqual GlobalDefinitions.phalanx_sgl_hevgatcan
|
||||
case _ =>
|
||||
ko
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MannedTurretControl1Test extends ActorTest {
|
||||
"MannedTurretControl" should {
|
||||
"construct" in {
|
||||
val obj = MannedTurret(GlobalDefinitions.manned_turret)
|
||||
obj.Actor = system.actorOf(Props(classOf[MannedTurretControl], obj), "turret-control")
|
||||
assert(obj.Actor != ActorRef.noSender)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MannedTurretControl2Test extends ActorTest {
|
||||
val player = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val obj = MannedTurret(GlobalDefinitions.manned_turret)
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[MannedTurretControl], obj), "turret-control")
|
||||
val bldg = Building(0, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Amenities = obj
|
||||
bldg.Faction = PlanetSideEmpire.TR
|
||||
|
||||
"MannedTurretControl" should {
|
||||
"seat on faction affiliation when FactionLock is true" in {
|
||||
assert(player.Faction == PlanetSideEmpire.TR)
|
||||
assert(obj.Faction == PlanetSideEmpire.TR)
|
||||
assert(obj.Definition.FactionLocked)
|
||||
|
||||
obj.Actor ! Mountable.TryMount(player, 0)
|
||||
val reply = receiveOne(300 milliseconds)
|
||||
reply match {
|
||||
case msg : Mountable.MountMessages =>
|
||||
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
||||
case _ =>
|
||||
assert(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MannedTurretControl3Test extends ActorTest {
|
||||
val player = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val obj = MannedTurret(GlobalDefinitions.manned_turret)
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[MannedTurretControl], obj), "turret-control")
|
||||
val bldg = Building(0, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Amenities = obj
|
||||
|
||||
"MannedTurretControl" should {
|
||||
"block seating on mismatched faction affiliation when FactionLock is true" in {
|
||||
assert(player.Faction == PlanetSideEmpire.TR)
|
||||
assert(obj.Faction == PlanetSideEmpire.NEUTRAL)
|
||||
assert(obj.Definition.FactionLocked)
|
||||
|
||||
obj.Actor ! Mountable.TryMount(player, 0)
|
||||
val reply = receiveOne(300 milliseconds)
|
||||
reply match {
|
||||
case msg : Mountable.MountMessages =>
|
||||
assert(msg.response.isInstanceOf[Mountable.CanNotMount])
|
||||
case _ =>
|
||||
assert(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MannedTurretControl4Test extends ActorTest {
|
||||
val player = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
val objDef = new MannedTurretDefinition(480)
|
||||
objDef.FactionLocked = false
|
||||
val obj = MannedTurret(objDef)
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[MannedTurretControl], obj), "turret-control")
|
||||
val bldg = Building(0, Zone.Nowhere, StructureType.Building)
|
||||
bldg.Amenities = obj
|
||||
|
||||
"MannedTurretControl" should {
|
||||
"seating even with mismatched faction affiliation when FactionLock is false" in {
|
||||
assert(player.Faction == PlanetSideEmpire.TR)
|
||||
assert(obj.Faction == PlanetSideEmpire.NEUTRAL)
|
||||
assert(!obj.Definition.FactionLocked)
|
||||
|
||||
obj.Actor ! Mountable.TryMount(player, 0)
|
||||
val reply = receiveOne(300 milliseconds)
|
||||
reply match {
|
||||
case msg : Mountable.MountMessages =>
|
||||
assert(msg.response.isInstanceOf[Mountable.CanMount])
|
||||
case _ =>
|
||||
assert(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.{Avatar, Player}
|
||||
import net.psforever.objects.definition.{ObjectDefinition, SeatDefinition}
|
||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||
|
|
@ -12,7 +13,7 @@ import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
|||
|
||||
import scala.concurrent.duration.Duration
|
||||
|
||||
class MountableControl1Test extends ActorTest() {
|
||||
class MountableControl1Test extends ActorTest {
|
||||
"MountableControl" should {
|
||||
"construct" in {
|
||||
val obj = new MountableTest.MountableTestObject
|
||||
|
|
@ -22,7 +23,7 @@ class MountableControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class MountableControl2Test extends ActorTest() {
|
||||
class MountableControl2Test extends ActorTest {
|
||||
"MountableControl" should {
|
||||
"let a player mount" in {
|
||||
val player = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
|
|
@ -43,7 +44,7 @@ class MountableControl2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class MountableControl3Test extends ActorTest() {
|
||||
class MountableControl3Test extends ActorTest {
|
||||
"MountableControl" should {
|
||||
"block a player from mounting" in {
|
||||
val player1 = Player(Avatar("test1", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
|
|
|
|||
332
common/src/test/scala/objects/ResourceSiloTest.scala
Normal file
332
common/src/test/scala/objects/ResourceSiloTest.scala
Normal file
|
|
@ -0,0 +1,332 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.{Actor, Props}
|
||||
import akka.routing.RandomPool
|
||||
import akka.testkit.TestProbe
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.guid.TaskResolver
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl, ResourceSiloDefinition}
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.{PlanetSideGUID, UseItemMessage}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
|
||||
import org.specs2.mutable.Specification
|
||||
import services.ServiceManager
|
||||
import services.avatar.{AvatarAction, AvatarService, AvatarServiceMessage}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class ResourceSiloTest extends Specification {
|
||||
"Resource Silo" should {
|
||||
"define" in {
|
||||
val obj = new ResourceSiloDefinition
|
||||
obj.ObjectId mustEqual 731
|
||||
}
|
||||
|
||||
"construct" in {
|
||||
val obj = ResourceSilo()
|
||||
obj.Definition mustEqual GlobalDefinitions.resource_silo
|
||||
obj.MaximumCharge mustEqual 1000
|
||||
obj.ChargeLevel mustEqual 0
|
||||
obj.LowNtuWarningOn mustEqual 0
|
||||
obj.CapacitorDisplay mustEqual 0
|
||||
//
|
||||
obj.ChargeLevel = 50
|
||||
obj.LowNtuWarningOn = 25
|
||||
obj.CapacitorDisplay = 75
|
||||
obj.ChargeLevel mustEqual 50
|
||||
obj.LowNtuWarningOn mustEqual 25
|
||||
obj.CapacitorDisplay mustEqual 75
|
||||
}
|
||||
|
||||
"charge level can not exceed limits(0 to maximum)" in {
|
||||
val obj = ResourceSilo()
|
||||
obj.ChargeLevel mustEqual 0
|
||||
obj.ChargeLevel = -5
|
||||
obj.ChargeLevel mustEqual 0
|
||||
|
||||
obj.ChargeLevel = 1250
|
||||
obj.ChargeLevel mustEqual 1000
|
||||
obj.ChargeLevel mustEqual obj.MaximumCharge
|
||||
}
|
||||
|
||||
"using the silo generates a charge event" in {
|
||||
val msg = UseItemMessage(PlanetSideGUID(1), PlanetSideGUID(0), PlanetSideGUID(2), 0L, false, Vector3(0f,0f,0f),Vector3(0f,0f,0f),0,0,0,0L) //faked
|
||||
ResourceSilo().Use(ResourceSiloTest.player, msg) mustEqual ResourceSilo.ChargeEvent()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlStartupTest extends ActorTest {
|
||||
val serviceManager = ServiceManager.boot(system)
|
||||
serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
val probe = TestProbe()
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe), "avatar")
|
||||
|
||||
"Resource silo" should {
|
||||
"startup properly" in {
|
||||
expectNoMsg(500 milliseconds)
|
||||
system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
expectNoMsg(1 seconds)
|
||||
assert(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlUseTest extends ActorTest {
|
||||
val serviceManager = ServiceManager.boot(system)
|
||||
serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val probe = TestProbe()
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe), "avatar")
|
||||
val msg = UseItemMessage(PlanetSideGUID(1), PlanetSideGUID(0), PlanetSideGUID(2), 0L, false, Vector3(0f,0f,0f),Vector3(0f,0f,0f),0,0,0,0L) //faked
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
|
||||
"Resource silo" should {
|
||||
"respond when being used" in {
|
||||
expectNoMsg(1 seconds)
|
||||
obj.Actor ! ResourceSilo.Use(ResourceSiloTest.player, msg)
|
||||
|
||||
val reply = receiveOne(500 milliseconds)
|
||||
assert(reply.isInstanceOf[ResourceSilo.ResourceSiloMessage])
|
||||
assert(reply.asInstanceOf[ResourceSilo.ResourceSiloMessage].player == ResourceSiloTest.player)
|
||||
assert(reply.asInstanceOf[ResourceSilo.ResourceSiloMessage].msg == msg)
|
||||
assert(reply.asInstanceOf[ResourceSilo.ResourceSiloMessage].response == ResourceSilo.ChargeEvent())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlNtuWarningTest extends ActorTest {
|
||||
val serviceManager = ServiceManager.boot(system)
|
||||
serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val probe = TestProbe()
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe), "avatar")
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
obj.Owner = new Building(0, Zone.Nowhere, StructureType.Building) {
|
||||
ModelId = 6
|
||||
}
|
||||
|
||||
"Resource silo" should {
|
||||
"announce low ntu" in {
|
||||
expectNoMsg(1 seconds)
|
||||
assert(obj.LowNtuWarningOn == 0)
|
||||
obj.Actor ! ResourceSilo.LowNtuWarning(10)
|
||||
|
||||
val reply = probe.receiveOne(500 milliseconds)
|
||||
assert(obj.LowNtuWarningOn == 10)
|
||||
assert(reply.isInstanceOf[AvatarServiceMessage])
|
||||
assert(reply.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||
assert(reply.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||
assert(reply.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].player_guid == PlanetSideGUID(6))
|
||||
assert(reply.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_type == 47)
|
||||
assert(reply.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_value == 10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlUpdate1Test extends ActorTest {
|
||||
val serviceManager = ServiceManager.boot(system)
|
||||
serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val probe1 = TestProbe()
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe1), "avatar")
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
val bldg = new Building(0, Zone.Nowhere, StructureType.Building) {
|
||||
ModelId = 6
|
||||
}
|
||||
val probe2 = TestProbe()
|
||||
bldg.Actor = system.actorOf(Props(classOf[ResourceSiloTest.ProbedBuildingControl], probe2), "test-bldg")
|
||||
obj.Owner = bldg
|
||||
|
||||
"Resource silo" should {
|
||||
"update the charge level and capacitor display (report low ntu, power restored)" in {
|
||||
expectNoMsg(1 seconds)
|
||||
|
||||
assert(obj.ChargeLevel == 0)
|
||||
assert(obj.CapacitorDisplay == 0)
|
||||
obj.Actor ! ResourceSilo.UpdateChargeLevel(105)
|
||||
|
||||
val reply1 = probe1.receiveOne(500 milliseconds)
|
||||
val reply2 = probe2.receiveOne(500 milliseconds)
|
||||
assert(obj.ChargeLevel == 105)
|
||||
assert(obj.CapacitorDisplay == 1)
|
||||
assert(reply1.isInstanceOf[AvatarServiceMessage])
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].player_guid == PlanetSideGUID(1))
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_type == 45)
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_value == 1)
|
||||
|
||||
assert(reply2.isInstanceOf[Building.SendMapUpdateToAllClients])
|
||||
|
||||
val reply3 = probe1.receiveOne(500 milliseconds)
|
||||
assert(reply3.isInstanceOf[AvatarServiceMessage])
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].player_guid == PlanetSideGUID(6))
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_type == 48)
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_value == 0)
|
||||
|
||||
val reply4 = probe1.receiveOne(500 milliseconds)
|
||||
assert(obj.LowNtuWarningOn == 1)
|
||||
assert(reply4.isInstanceOf[AvatarServiceMessage])
|
||||
assert(reply4.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||
assert(reply4.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||
assert(reply4.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].player_guid == PlanetSideGUID(6))
|
||||
assert(reply4.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_type == 47)
|
||||
assert(reply4.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_value == 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlUpdate2Test extends ActorTest {
|
||||
val serviceManager = ServiceManager.boot(system)
|
||||
serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val probe1 = TestProbe()
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe1), "avatar")
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
val bldg = new Building(0, Zone.Nowhere, StructureType.Building) {
|
||||
ModelId = 6
|
||||
}
|
||||
val probe2 = TestProbe()
|
||||
bldg.Actor = system.actorOf(Props(classOf[ResourceSiloTest.ProbedBuildingControl], probe2), "test-bldg")
|
||||
obj.Owner = bldg
|
||||
|
||||
"Resource silo" should {
|
||||
"update the charge level and capacitor display (report good ntu)" in {
|
||||
expectNoMsg(1 seconds)
|
||||
|
||||
obj.ChargeLevel = 100
|
||||
obj.CapacitorDisplay = 1
|
||||
obj.LowNtuWarningOn = 1
|
||||
assert(obj.ChargeLevel == 100)
|
||||
assert(obj.CapacitorDisplay == 1)
|
||||
assert(obj.LowNtuWarningOn == 1)
|
||||
obj.Actor ! ResourceSilo.UpdateChargeLevel(105)
|
||||
|
||||
val reply1 = probe1.receiveOne(500 milliseconds)
|
||||
val reply2 = probe2.receiveOne(500 milliseconds)
|
||||
assert(obj.ChargeLevel == 205)
|
||||
assert(obj.CapacitorDisplay == 2)
|
||||
assert(reply1.isInstanceOf[AvatarServiceMessage])
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].player_guid == PlanetSideGUID(1))
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_type == 45)
|
||||
assert(reply1.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_value == 2)
|
||||
|
||||
assert(reply2.isInstanceOf[Building.SendMapUpdateToAllClients])
|
||||
|
||||
val reply3 = probe1.receiveOne(500 milliseconds)
|
||||
assert(obj.LowNtuWarningOn == 0)
|
||||
assert(reply3.isInstanceOf[AvatarServiceMessage])
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].player_guid == PlanetSideGUID(6))
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_type == 47)
|
||||
assert(reply3.asInstanceOf[AvatarServiceMessage]
|
||||
.actionMessage.asInstanceOf[AvatarAction.PlanetsideAttribute].attribute_value == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlNoUpdateTest extends ActorTest {
|
||||
val serviceManager = ServiceManager.boot(system)
|
||||
serviceManager ! ServiceManager.Register(RandomPool(1).props(Props[TaskResolver]), "taskResolver")
|
||||
val probe1 = TestProbe()
|
||||
serviceManager ! ServiceManager.Register(Props(classOf[ResourceSiloTest.ProbedAvatarService], probe1), "avatar")
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
val bldg = new Building(0, Zone.Nowhere, StructureType.Building) {
|
||||
ModelId = 6
|
||||
}
|
||||
val probe2 = TestProbe()
|
||||
bldg.Actor = system.actorOf(Props(classOf[ResourceSiloTest.ProbedBuildingControl], probe2), "test-bldg")
|
||||
obj.Owner = bldg
|
||||
|
||||
"Resource silo" should {
|
||||
"update, but not sufficiently to change the capacitor display" in {
|
||||
expectNoMsg(1 seconds)
|
||||
|
||||
obj.ChargeLevel = 250
|
||||
obj.CapacitorDisplay = 3
|
||||
obj.LowNtuWarningOn = 0
|
||||
assert(obj.ChargeLevel == 250)
|
||||
assert(obj.CapacitorDisplay == 3)
|
||||
assert(obj.LowNtuWarningOn == 0)
|
||||
obj.Actor ! ResourceSilo.UpdateChargeLevel(50)
|
||||
|
||||
expectNoMsg(500 milliseconds)
|
||||
probe1.expectNoMsg(500 milliseconds)
|
||||
probe2.expectNoMsg(500 milliseconds)
|
||||
assert(obj.ChargeLevel == 300)
|
||||
assert(obj.CapacitorDisplay == 3)
|
||||
assert(obj.LowNtuWarningOn == 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ResourceSiloTest {
|
||||
val player = Player(Avatar("TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
|
||||
class ProbedAvatarService(probe : TestProbe) extends Actor {
|
||||
override def receive : Receive = {
|
||||
case msg =>
|
||||
probe.ref ! msg
|
||||
}
|
||||
}
|
||||
|
||||
class ProbedBuildingControl(probe : TestProbe) extends Actor {
|
||||
override def receive : Receive = {
|
||||
case msg =>
|
||||
probe.ref ! msg
|
||||
}
|
||||
}
|
||||
|
||||
class ProbedResourceSiloControl(silo : ResourceSilo, probe : TestProbe) extends ResourceSiloControl(silo) {
|
||||
override def receive : Receive = {
|
||||
case msg =>
|
||||
super.receive.apply(msg)
|
||||
probe.ref ! msg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{Actor, ActorContext, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.objects.serverobject.ServerObjectBuilder
|
||||
|
|
@ -137,7 +138,8 @@ class ProximityTerminalObjectBuilderTest extends ActorTest {
|
|||
"Terminal object" should {
|
||||
"build" in {
|
||||
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, ProximityTerminal.Constructor(medical_terminal)), hub), "term")
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||
ProximityTerminal.Constructor(medical_terminal)), hub), "term")
|
||||
actor ! "!"
|
||||
|
||||
val reply = receiveOne(Duration.create(1000, "ms"))
|
||||
|
|
@ -172,7 +174,7 @@ class VehicleSpawnPadObjectBuilderTest extends ActorTest {
|
|||
|
||||
class LocalProjectileBuilderTest extends ActorTest {
|
||||
import net.psforever.objects.LocalProjectile
|
||||
"Local ProjectileBuilder" should {
|
||||
"Local projectile object" should {
|
||||
"build" in {
|
||||
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||
|
|
@ -190,7 +192,7 @@ class LocalProjectileBuilderTest extends ActorTest {
|
|||
|
||||
class LockerObjectBuilderTest extends ActorTest {
|
||||
import net.psforever.objects.serverobject.mblocker.Locker
|
||||
"LockerObjectBuilder" should {
|
||||
"Locker object" should {
|
||||
"build" in {
|
||||
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||
|
|
@ -206,9 +208,27 @@ class LockerObjectBuilderTest extends ActorTest {
|
|||
}
|
||||
}
|
||||
|
||||
class ResourceSiloObjectBuilderTest extends ActorTest {
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||
"Resource silo object" should {
|
||||
"build" in {
|
||||
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||
ResourceSilo.Constructor), hub), "spawn-tube")
|
||||
actor ! "startup"
|
||||
|
||||
val reply = receiveOne(Duration.create(1000, "ms"))
|
||||
assert(reply.isInstanceOf[ResourceSilo])
|
||||
assert(reply.asInstanceOf[ResourceSilo].HasGUID)
|
||||
assert(reply.asInstanceOf[ResourceSilo].GUID == PlanetSideGUID(1))
|
||||
assert(reply == hub(1).get)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class SpawnTubeObjectBuilderTest extends ActorTest {
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
"LockerObjectBuilder" should {
|
||||
"Spawn tube object" should {
|
||||
"build" in {
|
||||
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||
|
|
@ -226,6 +246,25 @@ class SpawnTubeObjectBuilderTest extends ActorTest {
|
|||
}
|
||||
}
|
||||
|
||||
class MannedTurretObjectBuilderTest extends ActorTest {
|
||||
import net.psforever.objects.GlobalDefinitions.manned_turret
|
||||
import net.psforever.objects.serverobject.turret.MannedTurret
|
||||
"MannedTurretObjectBuilder" should {
|
||||
"build" in {
|
||||
val hub = ServerObjectBuilderTest.NumberPoolHub
|
||||
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
|
||||
MannedTurret.Constructor(manned_turret)), hub), "spawn-tube")
|
||||
actor ! "!"
|
||||
|
||||
val reply = receiveOne(Duration.create(1000, "ms"))
|
||||
assert(reply.isInstanceOf[MannedTurret])
|
||||
assert(reply.asInstanceOf[MannedTurret].HasGUID)
|
||||
assert(reply.asInstanceOf[MannedTurret].GUID == PlanetSideGUID(1))
|
||||
assert(reply == hub(1).get)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object ServerObjectBuilderTest {
|
||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
def NumberPoolHub : NumberPoolHub = {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.GlobalDefinitions
|
||||
import net.psforever.objects.serverobject.tube.{SpawnTube, SpawnTubeControl, SpawnTubeDefinition}
|
||||
import org.specs2.mutable.Specification
|
||||
|
|
@ -48,7 +49,7 @@ class SpawnTubeTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class SpawnTubeControlTest extends ActorTest() {
|
||||
class SpawnTubeControlTest extends ActorTest {
|
||||
"SpawnTubeControl" should {
|
||||
"construct" in {
|
||||
val obj = SpawnTube(GlobalDefinitions.ams_respawn_tube)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.vehicles._
|
||||
|
|
@ -73,7 +74,7 @@ class UtilityTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class Utility1Test extends ActorTest() {
|
||||
class Utility1Test extends ActorTest {
|
||||
"Utility" should {
|
||||
"wire an order_terminala Actor" in {
|
||||
val obj = Utility(UtilityType.order_terminala, UtilityTest.vehicle)
|
||||
|
|
@ -87,7 +88,7 @@ class Utility1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class Utility2Test extends ActorTest() {
|
||||
class Utility2Test extends ActorTest {
|
||||
"Utility" should {
|
||||
"wire an order_terminalb Actor" in {
|
||||
val obj = Utility(UtilityType.order_terminalb, UtilityTest.vehicle)
|
||||
|
|
@ -101,7 +102,7 @@ class Utility2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class Utility3Test extends ActorTest() {
|
||||
class Utility3Test extends ActorTest {
|
||||
"Utility" should {
|
||||
"wire a matrix_terminalc Actor" in {
|
||||
val obj = Utility(UtilityType.matrix_terminalc, UtilityTest.vehicle)
|
||||
|
|
@ -115,7 +116,7 @@ class Utility3Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class Utility4Test extends ActorTest() {
|
||||
class Utility4Test extends ActorTest {
|
||||
"Utility" should {
|
||||
"wire an ams_respawn_tube Actor" in {
|
||||
val obj = Utility(UtilityType.ams_respawn_tube, UtilityTest.vehicle)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package objects
|
|||
|
||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||
import akka.testkit.TestProbe
|
||||
import net.psforever.objects.ballistics.Projectile
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
import net.psforever.objects.serverobject.structures.StructureType
|
||||
|
|
@ -39,7 +39,7 @@ class VehicleSpawnPadTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl1Test extends ActorTest() {
|
||||
class VehicleSpawnControl1Test extends ActorTest {
|
||||
"VehicleSpawnControl" should {
|
||||
"construct" in {
|
||||
val obj = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
|
||||
|
|
@ -49,7 +49,7 @@ class VehicleSpawnControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl2aTest extends ActorTest() {
|
||||
class VehicleSpawnControl2aTest extends ActorTest {
|
||||
// This runs for a long time.
|
||||
"VehicleSpawnControl" should {
|
||||
"complete on a vehicle order (block a second one until the first is done and the spawn pad is cleared)" in {
|
||||
|
|
@ -113,7 +113,7 @@ class VehicleSpawnControl2aTest extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl2bTest extends ActorTest() {
|
||||
class VehicleSpawnControl2bTest extends ActorTest {
|
||||
// This runs for a long time.
|
||||
"VehicleSpawnControl" should {
|
||||
"complete on a vehicle order (railless)" in {
|
||||
|
|
@ -170,7 +170,7 @@ class VehicleSpawnControl2bTest extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl3Test extends ActorTest() {
|
||||
class VehicleSpawnControl3Test extends ActorTest {
|
||||
"VehicleSpawnControl" should {
|
||||
"player is on wrong continent before vehicle can partially load; vehicle is cleaned up" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -241,7 +241,7 @@ class VehicleSpawnControl4Test extends ActorTest() {
|
|||
// }
|
||||
//}
|
||||
|
||||
class VehicleSpawnControl5Test extends ActorTest() {
|
||||
class VehicleSpawnControl5Test extends ActorTest {
|
||||
"VehicleSpawnControl" should {
|
||||
"player dies right after vehicle partially loads; the vehicle spawns and blocks the pad" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -274,7 +274,7 @@ class VehicleSpawnControl5Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl6Test extends ActorTest() {
|
||||
class VehicleSpawnControl6Test extends ActorTest {
|
||||
"VehicleSpawnControl" should {
|
||||
"the player can not sit in vehicle; vehicle spawns and blocks the pad" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects
|
||||
|
||||
import akka.actor.Props
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package objects
|
|||
import java.util.concurrent.atomic.AtomicInteger
|
||||
|
||||
import akka.actor.{ActorContext, ActorRef, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
|
|
@ -74,6 +75,15 @@ class ZoneTest extends Specification {
|
|||
map.TerminalToInterface(3, 4)
|
||||
map.TerminalToInterface mustEqual Map(1 -> 2, 3 -> 4)
|
||||
}
|
||||
|
||||
"associate turrets to weapons" in {
|
||||
val map = new ZoneMap("map13")
|
||||
map.TurretToWeapon mustEqual Map.empty
|
||||
map.TurretToWeapon(1, 2)
|
||||
map.TurretToWeapon mustEqual Map(1 -> 2)
|
||||
map.TurretToWeapon(3, 4)
|
||||
map.TurretToWeapon mustEqual Map(1 -> 2, 3 -> 4)
|
||||
}
|
||||
}
|
||||
|
||||
val map13 = new ZoneMap("map13")
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskRegister1Test extends ActorTest {
|
||||
"RegisterObjectTask" in {
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskRegister2Test extends ActorTest() {
|
||||
class GUIDTaskRegister2Test extends ActorTest {
|
||||
"RegisterEquipment -> RegisterObjectTask" in {
|
||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = AmmoBox(GlobalDefinitions.energy_cell)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskRegister3Test extends ActorTest() {
|
||||
class GUIDTaskRegister3Test extends ActorTest {
|
||||
"RegisterEquipment -> RegisterTool" in {
|
||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Tool(GlobalDefinitions.beamer)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskRegister4Test extends ActorTest() {
|
||||
class GUIDTaskRegister4Test extends ActorTest {
|
||||
"RegisterVehicle" in {
|
||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Vehicle(GlobalDefinitions.fury)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskRegister5Test extends ActorTest() {
|
||||
class GUIDTaskRegister5Test extends ActorTest {
|
||||
"RegisterAvatar" in {
|
||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskRegister6Test extends ActorTest() {
|
||||
class GUIDTaskRegister6Test extends ActorTest {
|
||||
"RegisterPlayer" in {
|
||||
val (_, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskUnregister1Test extends ActorTest() {
|
||||
class GUIDTaskUnregister1Test extends ActorTest {
|
||||
"UnregisterObjectTask" in {
|
||||
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = new GUIDTaskTest.TestObject
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskUnregister2Test extends ActorTest() {
|
||||
class GUIDTaskUnregister2Test extends ActorTest {
|
||||
"UnregisterEquipment -> UnregisterObjectTask" in {
|
||||
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = AmmoBox(GlobalDefinitions.energy_cell)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskUnregister3Test extends ActorTest() {
|
||||
class GUIDTaskUnregister3Test extends ActorTest {
|
||||
"UnregisterEquipment -> UnregisterTool" in {
|
||||
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Tool(GlobalDefinitions.beamer)
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskUnregister4Test extends ActorTest() {
|
||||
class GUIDTaskUnregister4Test extends ActorTest {
|
||||
"RegisterVehicle" in {
|
||||
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Vehicle(GlobalDefinitions.fury)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskUnregister5Test extends ActorTest() {
|
||||
class GUIDTaskUnregister5Test extends ActorTest {
|
||||
"UnregisterAvatar" in {
|
||||
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects.guidtask
|
||||
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
||||
import objects.ActorTest
|
||||
|
||||
class GUIDTaskUnregister6Test extends ActorTest() {
|
||||
class GUIDTaskUnregister6Test extends ActorTest {
|
||||
"UnregisterPlayer" in {
|
||||
val (guid, uns, taskResolver, probe) = GUIDTaskTest.CommonTestSetup
|
||||
val obj = Player(Avatar("test", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
package objects.number
|
||||
|
||||
import akka.actor.{ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.guid.actor.NumberPoolActor
|
||||
import net.psforever.objects.guid.pool.ExclusivePool
|
||||
import net.psforever.objects.guid.selector.RandomSelector
|
||||
import objects.ActorTest
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
|
||||
class NumberPoolActorTest extends ActorTest() {
|
||||
class NumberPoolActorTest extends ActorTest {
|
||||
"NumberPoolActor" should {
|
||||
"GetAnyNumber" in {
|
||||
val pool = new ExclusivePool((25 to 50).toList)
|
||||
|
|
@ -22,7 +22,7 @@ class NumberPoolActorTest extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class NumberPoolActorTest1 extends ActorTest() {
|
||||
class NumberPoolActorTest1 extends ActorTest {
|
||||
"NumberPoolActor" should {
|
||||
"GetSpecificNumber" in {
|
||||
val pool = new ExclusivePool((25 to 50).toList)
|
||||
|
|
@ -34,7 +34,7 @@ class NumberPoolActorTest1 extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class NumberPoolActorTest2 extends ActorTest() {
|
||||
class NumberPoolActorTest2 extends ActorTest {
|
||||
"NumberPoolActor" should {
|
||||
"NoNumber" in {
|
||||
val pool = new ExclusivePool((25 to 25).toList) //pool only has one number - 25
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
package objects.number
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.entity.IdentifiableEntity
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.objects.guid.actor.{NumberPoolActor, Register, UniqueNumberSystem, Unregister}
|
||||
import net.psforever.objects.guid.selector.RandomSelector
|
||||
import net.psforever.objects.guid.source.LimitedNumberSource
|
||||
import objects.ActorTest
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
import scala.util.{Failure, Success}
|
||||
|
||||
class AllocateNumberPoolActors extends ActorTest() {
|
||||
class AllocateNumberPoolActors extends ActorTest {
|
||||
"AllocateNumberPoolActors" in {
|
||||
val src : LimitedNumberSource = LimitedNumberSource(6000)
|
||||
val guid : NumberPoolHub = new NumberPoolHub(src)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package objects.terminal
|
||||
|
||||
import akka.actor.{ActorRef, ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.definition.SeatDefinition
|
||||
import net.psforever.objects.serverobject.mount.Mountable
|
||||
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
|
||||
|
|
@ -9,7 +10,6 @@ import net.psforever.objects.serverobject.structures.StructureType
|
|||
import net.psforever.objects.vehicles.Seat
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
|
||||
import objects.ActorTest
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
|
|
@ -56,7 +56,7 @@ class ImplantTerminalMechTest extends Specification {
|
|||
}
|
||||
}
|
||||
|
||||
class ImplantTerminalMechControl1Test extends ActorTest() {
|
||||
class ImplantTerminalMechControl1Test extends ActorTest {
|
||||
"ImplantTerminalMechControl" should {
|
||||
"construct" in {
|
||||
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
|
||||
|
|
@ -66,7 +66,7 @@ class ImplantTerminalMechControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class ImplantTerminalMechControl2Test extends ActorTest() {
|
||||
class ImplantTerminalMechControl2Test extends ActorTest {
|
||||
"ImplantTerminalMechControl" should {
|
||||
"let a player mount" in {
|
||||
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -85,7 +85,7 @@ class ImplantTerminalMechControl2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class ImplantTerminalMechControl3Test extends ActorTest() {
|
||||
class ImplantTerminalMechControl3Test extends ActorTest {
|
||||
import net.psforever.types.CharacterGender
|
||||
"ImplantTerminalMechControl" should {
|
||||
"block a player from mounting" in {
|
||||
|
|
@ -108,7 +108,7 @@ class ImplantTerminalMechControl3Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class ImplantTerminalMechControl4Test extends ActorTest() {
|
||||
class ImplantTerminalMechControl4Test extends ActorTest {
|
||||
"ImplantTerminalMechControl" should {
|
||||
"dismount player after mounting" in {
|
||||
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -130,7 +130,7 @@ class ImplantTerminalMechControl4Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class ImplantTerminalMechControl5Test extends ActorTest() {
|
||||
class ImplantTerminalMechControl5Test extends ActorTest {
|
||||
"ImplantTerminalMechControl" should {
|
||||
"block a player from dismounting" in {
|
||||
val (player, mech) = ImplantTerminalMechTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
|
|||
|
|
@ -2,16 +2,16 @@
|
|||
package objects.terminal
|
||||
|
||||
import akka.actor.{ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.objects.serverobject.terminals._
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
||||
import objects.ActorTest
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
|
||||
class ProximityTerminalControl1Test extends ActorTest() {
|
||||
class ProximityTerminalControl1Test extends ActorTest {
|
||||
"ProximityTerminalControl" should {
|
||||
"construct (medical terminal)" in {
|
||||
val terminal = ProximityTerminal(GlobalDefinitions.medical_terminal)
|
||||
|
|
@ -20,7 +20,7 @@ class ProximityTerminalControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class ProximityTerminalControl2Test extends ActorTest() {
|
||||
class ProximityTerminalControl2Test extends ActorTest {
|
||||
"ProximityTerminalControl can not process wrong messages" in {
|
||||
val (_, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR)
|
||||
|
||||
|
|
@ -30,7 +30,7 @@ class ProximityTerminalControl2Test extends ActorTest() {
|
|||
}
|
||||
|
||||
//terminal control is mostly a pass-through actor for Terminal.Exchange messages, wrapped in Terminal.TerminalMessage protocol
|
||||
class MedicalTerminalControl1Test extends ActorTest() {
|
||||
class MedicalTerminalControl1Test extends ActorTest {
|
||||
"ProximityTerminalControl sends a message to the first new user only" in {
|
||||
val (player, terminal) = ProximityTerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR)
|
||||
player.GUID = PlanetSideGUID(10)
|
||||
|
|
@ -53,7 +53,7 @@ class MedicalTerminalControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class MedicalTerminalControl2Test extends ActorTest() {
|
||||
class MedicalTerminalControl2Test extends ActorTest {
|
||||
"ProximityTerminalControl sends a message to the last user only" in {
|
||||
val (player, terminal) : (Player, ProximityTerminal) = ProximityTerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR)
|
||||
player.GUID = PlanetSideGUID(10)
|
||||
|
|
@ -82,7 +82,7 @@ class MedicalTerminalControl2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class MedicalTerminalControl3Test extends ActorTest() {
|
||||
class MedicalTerminalControl3Test extends ActorTest {
|
||||
"ProximityTerminalControl sends a message to the last user only (confirmation of test #2)" in {
|
||||
val (player, terminal) : (Player, ProximityTerminal) = ProximityTerminalControlTest.SetUpAgents(GlobalDefinitions.medical_terminal, PlanetSideEmpire.TR)
|
||||
player.GUID = PlanetSideGUID(10)
|
||||
|
|
|
|||
|
|
@ -2,13 +2,13 @@
|
|||
package objects.terminal
|
||||
|
||||
import akka.actor.Props
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
|
||||
import net.psforever.objects.serverobject.terminals.{ProximityTerminal, ProximityTerminalControl, ProximityUnit, Terminal}
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire}
|
||||
import objects.ActorTest
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
|
|
|||
|
|
@ -2,17 +2,17 @@
|
|||
package objects.terminal
|
||||
|
||||
import akka.actor.{ActorSystem, Props}
|
||||
import base.ActorTest
|
||||
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.{Avatar, GlobalDefinitions, Player}
|
||||
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
|
||||
import net.psforever.types._
|
||||
import objects.ActorTest
|
||||
|
||||
import scala.concurrent.duration.Duration
|
||||
|
||||
class TerminalControl1Test extends ActorTest() {
|
||||
class TerminalControl1Test extends ActorTest {
|
||||
"TerminalControl" should {
|
||||
"construct (cert terminal)" in {
|
||||
val terminal = Terminal(GlobalDefinitions.cert_terminal)
|
||||
|
|
@ -21,7 +21,7 @@ class TerminalControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class TerminalControl2Test extends ActorTest() {
|
||||
class TerminalControl2Test extends ActorTest {
|
||||
"TerminalControl can not process wrong messages" in {
|
||||
val (_, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ class TerminalControl2Test extends ActorTest() {
|
|||
|
||||
//terminal control is mostly a pass-through actor for Terminal.Exchange messages, wrapped in Terminal.TerminalMessage protocol
|
||||
//test for Cert_Terminal messages (see CertTerminalTest)
|
||||
class CertTerminalControl1Test extends ActorTest() {
|
||||
class CertTerminalControl1Test extends ActorTest {
|
||||
"TerminalControl can be used to learn a certification ('medium_assault')" in {
|
||||
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
|
||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "medium_assault", 0, PlanetSideGUID(0))
|
||||
|
|
@ -47,7 +47,7 @@ class CertTerminalControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class CertTerminalControl2Test extends ActorTest() {
|
||||
class CertTerminalControl2Test extends ActorTest {
|
||||
"TerminalControl can be used to warn about not learning a fake certification ('juggling')" in {
|
||||
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
|
||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Learn, 0, "juggling", 0, PlanetSideGUID(0))
|
||||
|
|
@ -62,7 +62,7 @@ class CertTerminalControl2Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class CertTerminalControl3Test extends ActorTest() {
|
||||
class CertTerminalControl3Test extends ActorTest {
|
||||
"TerminalControl can be used to forget a certification ('medium_assault')" in {
|
||||
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.cert_terminal, PlanetSideEmpire.TR)
|
||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Sell, 0, "medium_assault", 0, PlanetSideGUID(0))
|
||||
|
|
@ -77,7 +77,7 @@ class CertTerminalControl3Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleTerminalControl1Test extends ActorTest() {
|
||||
class VehicleTerminalControl1Test extends ActorTest {
|
||||
"TerminalControl can be used to buy a vehicle ('two_man_assault_buggy')" in {
|
||||
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.ground_vehicle_terminal, PlanetSideEmpire.TR)
|
||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "two_man_assault_buggy", 0, PlanetSideGUID(0))
|
||||
|
|
@ -102,7 +102,7 @@ class VehicleTerminalControl1Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleTerminalControl2Test extends ActorTest() {
|
||||
class VehicleTerminalControl2Test extends ActorTest {
|
||||
"TerminalControl can be used to warn about not buy a vehicle ('harasser')" in {
|
||||
val (player, terminal) = TerminalControlTest.SetUpAgents(GlobalDefinitions.ground_vehicle_terminal, PlanetSideEmpire.TR)
|
||||
val msg = ItemTransactionMessage(PlanetSideGUID(1), TransactionType.Buy, 0, "harasser", 0, PlanetSideGUID(0))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package service
|
||||
|
||||
import akka.actor.Props
|
||||
import akka.routing.RandomPool
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
|
||||
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
package service
|
||||
|
||||
// Copyright (c) 2017 PSForever
|
||||
import akka.actor.Props
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.{PlanetSideEmpire, Vector3}
|
||||
|
|
@ -1,46 +1,49 @@
|
|||
//// Copyright (c) 2017 PSForever
|
||||
//import akka.actor.{ActorRef, Props}
|
||||
//import akka.routing.RandomPool
|
||||
//import akka.testkit.TestProbe
|
||||
//import net.psforever.objects.PlanetSideGameObject
|
||||
//import net.psforever.objects.definition.{EquipmentDefinition, ObjectDefinition}
|
||||
//import net.psforever.objects.equipment.Equipment
|
||||
//import net.psforever.objects.guid.TaskResolver
|
||||
//import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
//import net.psforever.packet.game.PlanetSideGUID
|
||||
//import services.{RemoverActor, ServiceManager}
|
||||
//
|
||||
//import scala.concurrent.duration._
|
||||
//
|
||||
//class StandardRemoverActorTest extends ActorTest {
|
||||
// ServiceManager.boot ! ServiceManager.Register(RandomPool(2).props(Props[TaskResolver]), "taskResolver")
|
||||
//
|
||||
// "RemoverActor" should {
|
||||
// "handle a simple task" in {
|
||||
// expectNoMsg(500 milliseconds)
|
||||
// val probe = TestProbe()
|
||||
// val remover = system.actorOf(Props(classOf[RemoverActorTest.TestRemover], probe), "test-remover")
|
||||
// remover ! RemoverActor.AddTask(RemoverActorTest.TestObject, Zone.Nowhere)
|
||||
//
|
||||
// val reply1 = probe.receiveOne(200 milliseconds)
|
||||
// assert(reply1.isInstanceOf[RemoverActorTest.InclusionTestAlert])
|
||||
// val reply2 = probe.receiveOne(200 milliseconds)
|
||||
// assert(reply2.isInstanceOf[RemoverActorTest.InitialJobAlert])
|
||||
// probe.expectNoMsg(1 seconds) //delay
|
||||
// val reply3 = probe.receiveOne(300 milliseconds)
|
||||
// assert(reply3.isInstanceOf[RemoverActorTest.FirstJobAlert])
|
||||
// val reply4 = probe.receiveOne(300 milliseconds)
|
||||
// assert(reply4.isInstanceOf[RemoverActorTest.ClearanceTestAlert])
|
||||
// val reply5 = probe.receiveOne(300 milliseconds)
|
||||
// assert(reply5.isInstanceOf[RemoverActorTest.SecondJobAlert])
|
||||
// val reply6 = probe.receiveOne(500 milliseconds)
|
||||
// assert(reply6.isInstanceOf[RemoverActorTest.DeletionTaskAlert])
|
||||
// val reply7 = probe.receiveOne(500 milliseconds)
|
||||
// assert(reply7.isInstanceOf[RemoverActorTest.DeletionTaskRunAlert])
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
// Copyright (c) 2017 PSForever
|
||||
package service
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import akka.routing.RandomPool
|
||||
import akka.testkit.TestProbe
|
||||
import base.ActorTest
|
||||
import net.psforever.objects.PlanetSideGameObject
|
||||
import net.psforever.objects.definition.{EquipmentDefinition, ObjectDefinition}
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.guid.TaskResolver
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import services.{RemoverActor, ServiceManager}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class StandardRemoverActorTest extends ActorTest {
|
||||
ServiceManager.boot ! ServiceManager.Register(RandomPool(2).props(Props[TaskResolver]), "taskResolver")
|
||||
|
||||
"RemoverActor" should {
|
||||
"handle a simple task" in {
|
||||
expectNoMsg(500 milliseconds)
|
||||
val probe = TestProbe()
|
||||
val remover = system.actorOf(Props(classOf[RemoverActorTest.TestRemover], probe), "test-remover")
|
||||
remover ! RemoverActor.AddTask(RemoverActorTest.TestObject, Zone.Nowhere)
|
||||
|
||||
val reply1 = probe.receiveOne(200 milliseconds)
|
||||
assert(reply1.isInstanceOf[RemoverActorTest.InclusionTestAlert])
|
||||
val reply2 = probe.receiveOne(200 milliseconds)
|
||||
assert(reply2.isInstanceOf[RemoverActorTest.InitialJobAlert])
|
||||
probe.expectNoMsg(1 seconds) //delay
|
||||
val reply3 = probe.receiveOne(300 milliseconds)
|
||||
assert(reply3.isInstanceOf[RemoverActorTest.FirstJobAlert])
|
||||
val reply4 = probe.receiveOne(300 milliseconds)
|
||||
assert(reply4.isInstanceOf[RemoverActorTest.ClearanceTestAlert])
|
||||
val reply5 = probe.receiveOne(300 milliseconds)
|
||||
assert(reply5.isInstanceOf[RemoverActorTest.SecondJobAlert])
|
||||
val reply6 = probe.receiveOne(500 milliseconds)
|
||||
assert(reply6.isInstanceOf[RemoverActorTest.DeletionTaskAlert])
|
||||
val reply7 = probe.receiveOne(500 milliseconds)
|
||||
assert(reply7.isInstanceOf[RemoverActorTest.DeletionTaskRunAlert])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//class DelayedRemoverActorTest extends ActorTest {
|
||||
// ServiceManager.boot ! ServiceManager.Register(RandomPool(2).props(Props[TaskResolver]), "taskResolver")
|
||||
//
|
||||
|
|
@ -473,65 +476,65 @@
|
|||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//object RemoverActorTest {
|
||||
// final val TestObject = new Equipment() { def Definition = new EquipmentDefinition(0) { GUID = PlanetSideGUID(1) } }
|
||||
//
|
||||
// final case class InclusionTestAlert()
|
||||
//
|
||||
// final case class InitialJobAlert()
|
||||
//
|
||||
// final case class FirstJobAlert()
|
||||
//
|
||||
// final case class SecondJobAlert()
|
||||
//
|
||||
// final case class ClearanceTestAlert()
|
||||
//
|
||||
// final case class DeletionTaskAlert()
|
||||
//
|
||||
// final case class DeletionTaskRunAlert()
|
||||
//
|
||||
// class TestRemover(probe : TestProbe) extends RemoverActor {
|
||||
// import net.psforever.objects.guid.{Task, TaskResolver}
|
||||
// val FirstStandardDuration = 1 seconds
|
||||
//
|
||||
// val SecondStandardDuration = 100 milliseconds
|
||||
//
|
||||
// def InclusionTest(entry : RemoverActor.Entry) : Boolean = {
|
||||
// probe.ref ! InclusionTestAlert()
|
||||
// entry.obj.isInstanceOf[Equipment]
|
||||
// }
|
||||
//
|
||||
// def InitialJob(entry : RemoverActor.Entry) : Unit = {
|
||||
// probe.ref ! InitialJobAlert()
|
||||
// }
|
||||
//
|
||||
// def FirstJob(entry : RemoverActor.Entry) : Unit = {
|
||||
// probe.ref ! FirstJobAlert()
|
||||
// }
|
||||
//
|
||||
// override def SecondJob(entry : RemoverActor.Entry) : Unit = {
|
||||
// probe.ref ! SecondJobAlert()
|
||||
// super.SecondJob(entry)
|
||||
// }
|
||||
//
|
||||
// def ClearanceTest(entry : RemoverActor.Entry) : Boolean = {
|
||||
// probe.ref ! ClearanceTestAlert()
|
||||
// true
|
||||
// }
|
||||
//
|
||||
// def DeletionTask(entry : RemoverActor.Entry) : TaskResolver.GiveTask = {
|
||||
// probe.ref ! DeletionTaskAlert()
|
||||
// TaskResolver.GiveTask(new Task() {
|
||||
// private val localProbe = probe
|
||||
//
|
||||
// override def isComplete = Task.Resolution.Success
|
||||
//
|
||||
// def Execute(resolver : ActorRef) : Unit = {
|
||||
// localProbe.ref ! DeletionTaskRunAlert()
|
||||
// resolver ! scala.util.Success(this)
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
object RemoverActorTest {
|
||||
final val TestObject = new Equipment() { def Definition = new EquipmentDefinition(0) { GUID = PlanetSideGUID(1) } }
|
||||
|
||||
final case class InclusionTestAlert()
|
||||
|
||||
final case class InitialJobAlert()
|
||||
|
||||
final case class FirstJobAlert()
|
||||
|
||||
final case class SecondJobAlert()
|
||||
|
||||
final case class ClearanceTestAlert()
|
||||
|
||||
final case class DeletionTaskAlert()
|
||||
|
||||
final case class DeletionTaskRunAlert()
|
||||
|
||||
class TestRemover(probe : TestProbe) extends RemoverActor {
|
||||
import net.psforever.objects.guid.{Task, TaskResolver}
|
||||
val FirstStandardDuration = 1 seconds
|
||||
|
||||
val SecondStandardDuration = 100 milliseconds
|
||||
|
||||
def InclusionTest(entry : RemoverActor.Entry) : Boolean = {
|
||||
probe.ref ! InclusionTestAlert()
|
||||
entry.obj.isInstanceOf[Equipment]
|
||||
}
|
||||
|
||||
def InitialJob(entry : RemoverActor.Entry) : Unit = {
|
||||
probe.ref ! InitialJobAlert()
|
||||
}
|
||||
|
||||
def FirstJob(entry : RemoverActor.Entry) : Unit = {
|
||||
probe.ref ! FirstJobAlert()
|
||||
}
|
||||
|
||||
override def SecondJob(entry : RemoverActor.Entry) : Unit = {
|
||||
probe.ref ! SecondJobAlert()
|
||||
super.SecondJob(entry)
|
||||
}
|
||||
|
||||
def ClearanceTest(entry : RemoverActor.Entry) : Boolean = {
|
||||
probe.ref ! ClearanceTestAlert()
|
||||
true
|
||||
}
|
||||
|
||||
def DeletionTask(entry : RemoverActor.Entry) : TaskResolver.GiveTask = {
|
||||
probe.ref ! DeletionTaskAlert()
|
||||
TaskResolver.GiveTask(new Task() {
|
||||
private val localProbe = probe
|
||||
|
||||
override def isComplete = Task.Resolution.Success
|
||||
|
||||
def Execute(resolver : ActorRef) : Unit = {
|
||||
localProbe.ref ! DeletionTaskRunAlert()
|
||||
resolver ! scala.util.Success(this)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package service
|
||||
|
||||
import akka.actor.Props
|
||||
import base.ActorTest
|
||||
import net.psforever.objects._
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types._
|
||||
|
|
@ -11,6 +11,8 @@ import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
|||
import net.psforever.objects.serverobject.structures.{Building, FoundationBuilder, StructureType, WarpGate}
|
||||
import net.psforever.objects.serverobject.terminals.{ProximityTerminal, Terminal}
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||
import net.psforever.objects.serverobject.turret.MannedTurret
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
object Maps {
|
||||
|
|
@ -1215,6 +1217,14 @@ object Maps {
|
|||
LocalObject(1186, Locker.Constructor)
|
||||
LocalObject(1187, Locker.Constructor)
|
||||
LocalObject(1188, Locker.Constructor)
|
||||
LocalObject(1418, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1419, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1421, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1426, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1427, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1428, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1431, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1432, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1492, ProximityTerminal.Constructor(medical_terminal)) //lobby
|
||||
LocalObject(1494, ProximityTerminal.Constructor(medical_terminal)) //kitchen
|
||||
LocalObject(1564, Terminal.Constructor(order_terminal))
|
||||
|
|
@ -1330,6 +1340,14 @@ object Maps {
|
|||
ObjectToBuilding(1186, 2)
|
||||
ObjectToBuilding(1187, 2)
|
||||
ObjectToBuilding(1188, 2)
|
||||
ObjectToBuilding(1418, 2)
|
||||
ObjectToBuilding(1419, 2)
|
||||
ObjectToBuilding(1421, 2)
|
||||
ObjectToBuilding(1426, 2)
|
||||
ObjectToBuilding(1427, 2)
|
||||
ObjectToBuilding(1428, 2)
|
||||
ObjectToBuilding(1431, 2)
|
||||
ObjectToBuilding(1432, 2)
|
||||
ObjectToBuilding(1492, 2)
|
||||
ObjectToBuilding(1494, 2)
|
||||
ObjectToBuilding(1479, 2)
|
||||
|
|
@ -1385,6 +1403,14 @@ object Maps {
|
|||
DoorToLock(715, 751)
|
||||
TerminalToSpawnPad(224, 223)
|
||||
TerminalToSpawnPad(2419, 1479)
|
||||
TurretToWeapon(1418, 5000)
|
||||
TurretToWeapon(1419, 5001)
|
||||
TurretToWeapon(1421, 5002)
|
||||
TurretToWeapon(1426, 5003)
|
||||
TurretToWeapon(1427, 5004)
|
||||
TurretToWeapon(1428, 5005)
|
||||
TurretToWeapon(1431, 5006)
|
||||
TurretToWeapon(1432, 5007)
|
||||
}
|
||||
|
||||
def Building38() : Unit = {
|
||||
|
|
@ -1487,6 +1513,8 @@ object Maps {
|
|||
LocalObject(1226, Locker.Constructor)
|
||||
LocalObject(1227, Locker.Constructor)
|
||||
LocalObject(1228, Locker.Constructor)
|
||||
LocalObject(1440, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1442, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(1591, Terminal.Constructor(order_terminal))
|
||||
LocalObject(1592, Terminal.Constructor(order_terminal))
|
||||
LocalObject(1593, Terminal.Constructor(order_terminal))
|
||||
|
|
@ -1514,6 +1542,8 @@ object Maps {
|
|||
ObjectToBuilding(1226, 49)
|
||||
ObjectToBuilding(1227, 49)
|
||||
ObjectToBuilding(1228, 49)
|
||||
ObjectToBuilding(1440, 49)
|
||||
ObjectToBuilding(1442, 49)
|
||||
ObjectToBuilding(1591, 49)
|
||||
ObjectToBuilding(1592, 49)
|
||||
ObjectToBuilding(1593, 49)
|
||||
|
|
@ -1529,6 +1559,8 @@ object Maps {
|
|||
DoorToLock(431, 907)
|
||||
DoorToLock(432, 902)
|
||||
DoorToLock(433, 903)
|
||||
TurretToWeapon(1440, 5008)
|
||||
TurretToWeapon(1442, 5009)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1615,10 +1647,6 @@ object Maps {
|
|||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map12 = new ZoneMap("map12") {
|
||||
Projectiles(this)
|
||||
}
|
||||
|
||||
val map13 = new ZoneMap("map13") {
|
||||
Building1()
|
||||
Building2()
|
||||
|
|
@ -1766,6 +1794,8 @@ object Maps {
|
|||
LocalObject(557, IFFLock.Constructor)
|
||||
LocalObject(558, IFFLock.Constructor)
|
||||
LocalObject(559, IFFLock.Constructor)
|
||||
LocalObject(670, MannedTurret.Constructor(manned_turret))
|
||||
LocalObject(671, MannedTurret.Constructor(manned_turret))
|
||||
ObjectToBuilding(330, 29)
|
||||
ObjectToBuilding(331, 29)
|
||||
ObjectToBuilding(332, 29)
|
||||
|
|
@ -1774,10 +1804,14 @@ object Maps {
|
|||
ObjectToBuilding(557, 29)
|
||||
ObjectToBuilding(558, 29)
|
||||
ObjectToBuilding(559, 29)
|
||||
ObjectToBuilding(670, 29)
|
||||
ObjectToBuilding(671, 29)
|
||||
DoorToLock(330, 558)
|
||||
DoorToLock(331, 559)
|
||||
DoorToLock(332, 556)
|
||||
DoorToLock(333, 557)
|
||||
TurretToWeapon(670, 5000)
|
||||
TurretToWeapon(671, 5001)
|
||||
}
|
||||
|
||||
def Building42() : Unit = {
|
||||
|
|
|
|||
|
|
@ -219,7 +219,7 @@ object PsLogin {
|
|||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.Future
|
||||
import scala.util.{Failure, Success}
|
||||
implicit val timeout = Timeout(500 milliseconds)
|
||||
implicit val timeout = Timeout(5 seconds)
|
||||
val requestVehicleEventBus : Future[ServiceManager.LookupResult] =
|
||||
(ServiceManager.serviceManager ask ServiceManager.Lookup("vehicle")).mapTo[ServiceManager.LookupResult]
|
||||
requestVehicleEventBus.onComplete {
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ import net.psforever.objects.serverobject.structures.{Building, StructureType, W
|
|||
import net.psforever.objects.serverobject.terminals._
|
||||
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
|
||||
import net.psforever.objects.serverobject.tube.SpawnTube
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, Cargo, Utility, VehicleLockState}
|
||||
import net.psforever.objects.vehicles._
|
||||
import net.psforever.objects.zones.{InterstellarCluster, Zone}
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.types._
|
||||
|
|
@ -43,7 +43,7 @@ import services.{RemoverActor, _}
|
|||
import services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse}
|
||||
import services.galaxy.{GalaxyResponse, GalaxyServiceResponse}
|
||||
import services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
|
||||
import services.vehicle.VehicleAction.UnstowEquipment
|
||||
import services.vehicle.support.TurretUpgrader
|
||||
import services.vehicle.{VehicleAction, VehicleResponse, VehicleServiceMessage, VehicleServiceResponse}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
|
@ -54,6 +54,7 @@ import scala.concurrent.duration._
|
|||
import scala.util.Success
|
||||
import akka.pattern.ask
|
||||
import net.psforever.objects.ballistics.{Projectile, ProjectileResolution}
|
||||
import net.psforever.objects.serverobject.turret.{MannedTurret, TurretUpgrade}
|
||||
|
||||
class WorldSessionActor extends Actor with MDCContextAware {
|
||||
import WorldSessionActor._
|
||||
|
|
@ -179,7 +180,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
* Vehicle cleanup that is specific to log out behavior.
|
||||
*/
|
||||
def DismountVehicleOnLogOut() : Unit = {
|
||||
//TODO Will base guns implement Vehicle type? Don't want those to deconstruct
|
||||
(player.VehicleSeated match {
|
||||
case Some(vehicle_guid) =>
|
||||
continent.GUID(vehicle_guid)
|
||||
|
|
@ -572,6 +572,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case VehicleResponse.DetachFromRails(vehicle_guid, pad_guid, pad_position, pad_orientation_z) =>
|
||||
sendResponse(ObjectDetachMessage(pad_guid, vehicle_guid, pad_position + Vector3(0,0,0.5f), pad_orientation_z))
|
||||
|
||||
case VehicleResponse.EquipmentInSlot(pkt) =>
|
||||
if(tplayer_guid != guid) {
|
||||
sendResponse(pkt)
|
||||
}
|
||||
|
||||
case VehicleResponse.InventoryState(obj, parent_guid, start, con_data) =>
|
||||
if(tplayer_guid != guid) {
|
||||
//TODO prefer ObjectDetachMessage, but how to force ammo pools to update properly?
|
||||
|
|
@ -764,20 +769,24 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Mountable.MountMessages(tplayer, reply) =>
|
||||
reply match {
|
||||
case Mountable.CanMount(obj : ImplantTerminalMech, seat_num) =>
|
||||
val player_guid : PlanetSideGUID = tplayer.GUID
|
||||
val obj_guid : PlanetSideGUID = obj.GUID
|
||||
log.info(s"MountVehicleMsg: $player_guid mounts $obj @ $seat_num")
|
||||
PlayerActionsToCancel()
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, 0, 1000L)) //health of mech
|
||||
sendResponse(ObjectAttachMessage(obj_guid, player_guid, seat_num))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, obj_guid, seat_num))
|
||||
MountingAction(tplayer, obj, seat_num)
|
||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, 1000L)) //health of mech
|
||||
|
||||
case Mountable.CanMount(obj : MannedTurret, seat_num) =>
|
||||
obj.WeaponControlledFromSeat(seat_num) match {
|
||||
case Some(weapon : Tool) =>
|
||||
//update mounted weapon belonging to seat
|
||||
weapon.AmmoSlots.foreach(slot => { //update the magazine(s) in the weapon, specifically
|
||||
val magazine = slot.Box
|
||||
sendResponse(InventoryStateMessage(magazine.GUID, weapon.GUID, magazine.Capacity.toLong))
|
||||
})
|
||||
case _ => ; //no weapons to update
|
||||
}
|
||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, obj.Health))
|
||||
MountingAction(tplayer, obj, seat_num)
|
||||
|
||||
case Mountable.CanMount(obj : Vehicle, seat_num) =>
|
||||
val obj_guid : PlanetSideGUID = obj.GUID
|
||||
val player_guid : PlanetSideGUID = tplayer.GUID
|
||||
log.info(s"MountVehicleMsg: $player_guid mounts $obj_guid @ $seat_num")
|
||||
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(obj), continent)) //clear timer
|
||||
PlayerActionsToCancel()
|
||||
if(seat_num == 0) { //simplistic vehicle ownership management
|
||||
obj.Owner match {
|
||||
case Some(owner_guid) =>
|
||||
|
|
@ -791,7 +800,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case None => ;
|
||||
}
|
||||
tplayer.VehicleOwned = Some(obj_guid)
|
||||
obj.Owner = Some(player_guid)
|
||||
obj.Owner = Some(tplayer.GUID)
|
||||
}
|
||||
obj.WeaponControlledFromSeat(seat_num) match {
|
||||
case Some(weapon : Tool) =>
|
||||
|
|
@ -802,29 +811,27 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
})
|
||||
case _ => ; //no weapons to update
|
||||
}
|
||||
sendResponse(ObjectAttachMessage(obj_guid, player_guid, seat_num))
|
||||
//sendResponse(PlanetsideAttributeMessage(obj.GUID, 0, obj.Health)) //TODO vehicle max health in definition
|
||||
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(obj), continent)) //clear timer
|
||||
AccessContents(obj)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, obj_guid, seat_num))
|
||||
MountingAction(tplayer, obj, seat_num)
|
||||
|
||||
case Mountable.CanMount(obj : Mountable, _) =>
|
||||
log.warn(s"MountVehicleMsg: $obj is some generic mountable object and nothing will happen")
|
||||
|
||||
case Mountable.CanDismount(obj : ImplantTerminalMech, seat_num) =>
|
||||
val obj_guid : PlanetSideGUID = obj.GUID
|
||||
val player_guid : PlanetSideGUID = tplayer.GUID
|
||||
log.info(s"DismountVehicleMsg: $player_guid dismounts $obj @ $seat_num")
|
||||
sendResponse(DismountVehicleMsg(player_guid, BailType.Normal, false))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, BailType.Normal, false))
|
||||
DismountAction(tplayer, obj, seat_num)
|
||||
|
||||
case Mountable.CanDismount(obj : MannedTurret, seat_num) =>
|
||||
DismountAction(tplayer, obj, seat_num)
|
||||
|
||||
case Mountable.CanDismount(obj : Vehicle, seat_num) =>
|
||||
val player_guid : PlanetSideGUID = tplayer.GUID
|
||||
if(player_guid == player.GUID) {
|
||||
//disembarking self
|
||||
log.info(s"DismountVehicleMsg: $player_guid dismounts $obj @ $seat_num")
|
||||
TotalDriverVehicleControl(obj)
|
||||
sendResponse(DismountVehicleMsg(player_guid, BailType.Normal, false))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, BailType.Normal, false))
|
||||
UnAccessContents(obj)
|
||||
DismountAction(tplayer, obj, seat_num)
|
||||
}
|
||||
else {
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, seat_num, true, obj.GUID))
|
||||
|
|
@ -1713,7 +1720,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
antDischargingTick.cancel()
|
||||
}
|
||||
|
||||
case ItemHacking(tplayer, target, tool_guid, delta, completeAction, tickAction) =>
|
||||
case HackingProgress(progressType, tplayer, target, tool_guid, delta, completeAction, tickAction) =>
|
||||
progressBarUpdate.cancel
|
||||
if(progressBarValue.isDefined) {
|
||||
val progressBarVal : Float = progressBarValue.get + delta
|
||||
|
|
@ -1726,10 +1733,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
else {
|
||||
HackState.Ongoing
|
||||
}
|
||||
sendResponse(HackMessage(1, target.GUID, player.GUID, progressBarVal.toInt, 0L, vis, 8L))
|
||||
sendResponse(HackMessage(progressType, target.GUID, player.GUID, progressBarVal.toInt, 0L, vis, 8L))
|
||||
if(progressBarVal > 100) { //done
|
||||
progressBarValue = None
|
||||
log.info(s"Hacked a $target")
|
||||
// sendResponse(HackMessage(0, target.GUID, player.GUID, 100, 1114636288L, HackState.Hacked, 8L))
|
||||
completeAction()
|
||||
}
|
||||
|
|
@ -1737,7 +1743,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
tickAction.getOrElse(() => Unit)()
|
||||
progressBarValue = Some(progressBarVal)
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
progressBarUpdate = context.system.scheduler.scheduleOnce(250 milliseconds, self, ItemHacking(tplayer, target, tool_guid, delta, completeAction))
|
||||
progressBarUpdate = context.system.scheduler.scheduleOnce(250 milliseconds, self, HackingProgress(progressType, tplayer, target, tool_guid, delta, completeAction))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1803,6 +1809,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
avatar.Certifications += GalaxyGunship
|
||||
avatar.Certifications += Phantasm
|
||||
avatar.Certifications += UniMAX
|
||||
avatar.Certifications += Engineering
|
||||
avatar.Certifications += CombatEngineering
|
||||
avatar.Certifications += AdvancedEngineering
|
||||
avatar.Certifications += FortificationEngineering
|
||||
avatar.Certifications += AssaultEngineering
|
||||
AwardBattleExperiencePoints(avatar, 1000000L)
|
||||
player = new Player(avatar)
|
||||
//player.Position = Vector3(3561.0f, 2854.0f, 90.859375f) //home3, HART C
|
||||
|
|
@ -1812,9 +1823,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
//player.Orientation = Vector3(0f, 0f, 132.1875f)
|
||||
// player.ExoSuit = ExoSuitType.MAX //TODO strange issue; divide number above by 10 when uncommenting
|
||||
player.Slot(0).Equipment = SimpleItem(remote_electronics_kit) //Tool(GlobalDefinitions.StandardPistol(player.Faction))
|
||||
player.Slot(2).Equipment = Tool(mini_chaingun) //punisher //suppressor
|
||||
player.Slot(2).Equipment = Tool(nano_dispenser) //punisher //suppressor
|
||||
player.Slot(4).Equipment = Tool(GlobalDefinitions.StandardMelee(player.Faction))
|
||||
player.Slot(6).Equipment = AmmoBox(bullet_9mm, 20) //bullet_9mm
|
||||
player.Slot(6).Equipment = AmmoBox(upgrade_canister) //bullet_9mm
|
||||
player.Slot(9).Equipment = AmmoBox(rocket, 11) //bullet_9mm
|
||||
player.Slot(12).Equipment = AmmoBox(frag_cartridge) //bullet_9mm
|
||||
player.Slot(33).Equipment = AmmoBox(bullet_9mm_AP)
|
||||
|
|
@ -2056,6 +2067,45 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case _ => ;
|
||||
}
|
||||
})
|
||||
|
||||
//base turrets
|
||||
continent.Map.TurretToWeapon.foreach({ case((turret_guid, weapon_guid)) =>
|
||||
val parent_guid = PlanetSideGUID(turret_guid)
|
||||
continent.GUID(turret_guid) match {
|
||||
case Some(turret : MannedTurret) =>
|
||||
//attached weapon
|
||||
turret.ControlledWeapon(1) match {
|
||||
case Some(obj : Tool) =>
|
||||
val objDef = obj.Definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
objDef.ObjectId,
|
||||
obj.GUID,
|
||||
ObjectCreateMessageParent(parent_guid, 1),
|
||||
objDef.Packet.ConstructorData(obj).get
|
||||
)
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
//reserved ammunition?
|
||||
//TODO need to register if it exists
|
||||
//seat turret occupant
|
||||
turret.Seats(0).Occupant match {
|
||||
case Some(tplayer) =>
|
||||
val tdefintion = tplayer.Definition
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
tdefintion.ObjectId,
|
||||
tplayer.GUID,
|
||||
ObjectCreateMessageParent(parent_guid, 0),
|
||||
tdefintion.Packet.ConstructorData(tplayer).get
|
||||
)
|
||||
)
|
||||
case None => ;
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
})
|
||||
StopBundlingPackets()
|
||||
self ! SetCurrentAvatar(player)
|
||||
|
||||
|
|
@ -2079,33 +2129,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case msg @ ChildObjectStateMessage(object_guid, pitch, yaw) =>
|
||||
//the majority of the following check retrieves information to determine if we are in control of the child
|
||||
player.VehicleSeated match {
|
||||
case Some(vehicle_guid) =>
|
||||
continent.GUID(vehicle_guid) match {
|
||||
case Some(obj : Vehicle) =>
|
||||
obj.PassengerInSeat(player) match {
|
||||
case Some(seat_num) =>
|
||||
obj.WeaponControlledFromSeat(seat_num) match {
|
||||
case Some(tool) =>
|
||||
if(tool.GUID == object_guid) {
|
||||
//TODO set tool orientation?
|
||||
player.Orientation = Vector3(0f, pitch, yaw)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.ChildObjectState(player.GUID, object_guid, pitch, yaw))
|
||||
}
|
||||
case None =>
|
||||
log.warn(s"ChildObjectState: player $player is not using stated controllable agent")
|
||||
}
|
||||
case None =>
|
||||
log.warn(s"ChildObjectState: player ${player.GUID} is not in a position to use controllable agent")
|
||||
}
|
||||
case _ =>
|
||||
log.warn(s"ChildObjectState: player $player's controllable agent not available in scope")
|
||||
FindContainedWeapon match {
|
||||
case (Some(_), Some(tool)) =>
|
||||
if(tool.GUID == object_guid) {
|
||||
//TODO set tool orientation?
|
||||
player.Orientation = Vector3(0f, pitch, yaw)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.ChildObjectState(player.GUID, object_guid, pitch, yaw))
|
||||
}
|
||||
case None =>
|
||||
//TODO status condition of "playing getting out of vehicle to allow for late packets without warning
|
||||
//log.warn(s"ChildObjectState: player $player not related to anything with a controllable agent")
|
||||
else {
|
||||
log.warn(s"ChildObjectState: ${player.Name} is using a different controllable agent than #${object_guid.guid}")
|
||||
}
|
||||
case (Some(obj), None) =>
|
||||
log.warn(s"ChildObjectState: ${player.Name} can not find any controllable agent, let alone #${object_guid.guid}")
|
||||
case (None, _) => ;
|
||||
//TODO status condition of "playing getting out of vehicle to allow for late packets without warning
|
||||
//log.warn(s"ChildObjectState: player $player not related to anything with a controllable agent")
|
||||
}
|
||||
//log.info("ChildObjectState: " + msg)
|
||||
|
||||
case msg @ VehicleStateMessage(vehicle_guid, unk1, pos, ang, vel, unk5, unk6, unk7, wheels, unk9, unkA) =>
|
||||
continent.GUID(vehicle_guid) match {
|
||||
|
|
@ -2299,9 +2338,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
FindContainedWeapon match {
|
||||
case (Some(obj), Some(tool : Tool)) =>
|
||||
val originalAmmoType = tool.AmmoType
|
||||
val fullMagazine = tool.MaxMagazine
|
||||
do {
|
||||
val requestedAmmoType = tool.NextAmmoType
|
||||
val fullMagazine = tool.MaxMagazine
|
||||
if(requestedAmmoType != tool.AmmoSlot.Box.AmmoType) {
|
||||
FindEquipmentStock(obj, FindAmmoBoxThatUses(requestedAmmoType), fullMagazine, CountAmmunition).reverse match {
|
||||
case Nil => ;
|
||||
|
|
@ -2823,14 +2862,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.warn(s"Player ${player.GUID} - ${player.Faction} tried to refill silo ${resourceSilo.GUID} - ${resourceSilo.Faction} belonging to another empire")
|
||||
}
|
||||
|
||||
|
||||
case Some(panel : IFFLock) =>
|
||||
if(panel.Faction != player.Faction && panel.HackedBy.isEmpty) {
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool : SimpleItem) =>
|
||||
if(tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.ItemHacking(player, panel, tool.GUID, GetPlayerHackSpeed(), FinishHacking(panel, 1114636288L))
|
||||
self ! WorldSessionActor.HackingProgress(1, player, panel, tool.GUID, GetPlayerHackSpeed(), FinishHacking(panel, 1114636288L))
|
||||
log.info("Hacking a door~")
|
||||
}
|
||||
case _ => ;
|
||||
|
|
@ -2892,7 +2930,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(tool: SimpleItem) =>
|
||||
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.ItemHacking(player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
self ! WorldSessionActor.HackingProgress(1, player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
log.info("Hacking a locker")
|
||||
}
|
||||
case _ => ;
|
||||
|
|
@ -2907,6 +2945,32 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.info(s"UseItem: not $player's locker")
|
||||
}
|
||||
|
||||
case Some(obj : MannedTurret) =>
|
||||
player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(tool : Tool) =>
|
||||
if(tool.Definition == GlobalDefinitions.nano_dispenser && tool.Magazine > 0) {
|
||||
val ammo = tool.AmmoType
|
||||
if(ammo == Ammo.upgrade_canister && obj.Seats.values.count(_.isOccupied) == 0) {
|
||||
progressBarValue = Some(-1.25f)
|
||||
self ! WorldSessionActor.HackingProgress(
|
||||
2,
|
||||
player,
|
||||
obj,
|
||||
tool.GUID,
|
||||
1.25f,
|
||||
FinishUpgradingMannedTurret(obj, tool, TurretUpgrade(unk2.toInt))
|
||||
)
|
||||
}
|
||||
else if(ammo == Ammo.armor_canister && obj.Health < obj.MaxHealth) {
|
||||
//repair turret
|
||||
}
|
||||
}
|
||||
else if(tool.Definition == GlobalDefinitions.trek) {
|
||||
//infect turret with virus
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
case Some(obj : Vehicle) =>
|
||||
val equipment = player.Slot(player.DrawnSlot).Equipment
|
||||
if(player.Faction == obj.Faction) {
|
||||
|
|
@ -2969,7 +3033,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(tool: SimpleItem) =>
|
||||
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-GetPlayerHackSpeed())
|
||||
self ! WorldSessionActor.ItemHacking(player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
self ! WorldSessionActor.HackingProgress(1, player, obj, tool.GUID, GetPlayerHackSpeed(), FinishHacking(obj, 3212836864L))
|
||||
log.info("Hacking a terminal")
|
||||
}
|
||||
case _ => ;
|
||||
|
|
@ -2979,7 +3043,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
// Otherwise allow the faction that owns the terminal to use it
|
||||
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
case Some(obj : SpawnTube) =>
|
||||
|
|
@ -3853,7 +3916,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
/**
|
||||
* The process of hacking an object is completed
|
||||
* The process of hacking an object is completed.
|
||||
* Pass the message onto the hackable object and onto the local events system.
|
||||
* @param target the `Hackable` object that has been hacked
|
||||
* @param unk na;
|
||||
|
|
@ -3862,16 +3925,33 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
*/
|
||||
//TODO add params here depending on which params in HackMessage are important
|
||||
private def FinishHacking(target : PlanetSideServerObject with Hackable, unk : Long)() : Unit = {
|
||||
log.info(s"Hacked a $target")
|
||||
// Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
ask(target.Actor, CommonMessages.Hack(player))(1 second).mapTo[Boolean].onComplete {
|
||||
case Success(_) =>
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.TriggerSound(player.GUID, target.HackSound, player.Position, 30, 0.49803925f))
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk))
|
||||
case scala.util.Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
|
||||
}
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk))
|
||||
case scala.util.Failure(_) =>
|
||||
log.warn(s"Hack message failed on target guid: ${target.GUID}")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The process of upgrading a turret's weapon(s) is completed.
|
||||
* Pass the message onto the turret and onto the vehicle events system.
|
||||
* Additionally, force-deplete the ammunition count of the nano-dispenser used to perform the upgrade.
|
||||
* @param target the turret
|
||||
* @param tool the nano-dispenser that was used to perform this upgrade
|
||||
* @param upgrade the new upgrade state
|
||||
*/
|
||||
private def FinishUpgradingMannedTurret(target : MannedTurret, tool : Tool, upgrade : TurretUpgrade.Value)() : Unit = {
|
||||
log.info(s"Converting manned wall turret weapon to $upgrade")
|
||||
tool.Magazine = 0
|
||||
sendResponse(InventoryStateMessage(tool.AmmoSlot.Box.GUID, tool.GUID, 0))
|
||||
vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.ClearSpecific(List(target), continent))
|
||||
vehicleService ! VehicleServiceMessage.TurretUpgrade(TurretUpgrader.AddTask(target, continent, upgrade))
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary function that iterates over vehicle permissions and turns them into `PlanetsideAttributeMessage` packets.<br>
|
||||
|
|
@ -3887,7 +3967,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
* Occasionally, during deployment, local(?) vehicle seat access permissions may change.
|
||||
* This results in players being locked into their own vehicle.
|
||||
* Reloading vehicle permissions supposedly ensures the seats will be properly available.
|
||||
* This is considered a client issue; but, somehow, it also impacts server operation somehow.
|
||||
* This is considered a client issue; but, somehow, it also impacts server operation somehow.<br>
|
||||
* <br>
|
||||
* 22 June 2018:<br>
|
||||
* I think vehicle ownership works properly now.
|
||||
* @param vehicle the `Vehicle`
|
||||
*/
|
||||
def ReloadVehicleAccessPermissions(vehicle : Vehicle) : Unit = {
|
||||
|
|
@ -4025,7 +4108,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
player.VehicleSeated match {
|
||||
case Some(vehicle_guid) => //weapon is vehicle turret?
|
||||
continent.GUID(vehicle_guid) match {
|
||||
case Some(vehicle : Vehicle) =>
|
||||
case Some(vehicle : Mountable with MountedWeapons with Container) =>
|
||||
vehicle.PassengerInSeat(player) match {
|
||||
case Some(seat_num) =>
|
||||
(Some(vehicle), vehicle.WeaponControlledFromSeat(seat_num))
|
||||
|
|
@ -5312,6 +5395,34 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Common activities/procedure when a player mounts a valid object.
|
||||
* @param tplayer the player
|
||||
* @param obj the mountable object
|
||||
* @param seatNum the seat into which the player is mounting
|
||||
*/
|
||||
def MountingAction(tplayer : Player, obj : PlanetSideGameObject with Mountable, seatNum : Int) : Unit = {
|
||||
val player_guid : PlanetSideGUID = tplayer.GUID
|
||||
val obj_guid : PlanetSideGUID = obj.GUID
|
||||
PlayerActionsToCancel()
|
||||
log.info(s"MountVehicleMsg: $player_guid mounts $obj @ $seatNum")
|
||||
sendResponse(ObjectAttachMessage(obj_guid, player_guid, seatNum))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, obj_guid, seatNum))
|
||||
}
|
||||
|
||||
/**
|
||||
* Common activities/procedure when a player dismounts a valid object.
|
||||
* @param tplayer the player
|
||||
* @param obj the mountable object
|
||||
* @param seatNum the seat out of which which the player is disembarking
|
||||
*/
|
||||
def DismountAction(tplayer : Player, obj : PlanetSideGameObject with Mountable, seatNum : Int) : Unit = {
|
||||
val player_guid : PlanetSideGUID = tplayer.GUID
|
||||
log.info(s"DismountVehicleMsg: ${tplayer.Name} dismounts $obj from $seatNum")
|
||||
sendResponse(DismountVehicleMsg(player_guid, BailType.Normal, false))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, BailType.Normal, false))
|
||||
}
|
||||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
sendResponse(ConnectionClose())
|
||||
|
|
@ -5470,9 +5581,12 @@ object WorldSessionActor {
|
|||
|
||||
|
||||
/**
|
||||
* A message that indicates the user is using a remote electronics kit to hack some server object.
|
||||
* A message that indicates the user is using a remote electronics kit to hack some server object.<br>
|
||||
* <br>
|
||||
* Each time this message is sent for a given hack attempt counts as a single "tick" of progress.
|
||||
* The process of "making progress" with a hack involves sending this message repeatedly until the progress is 100 or more.
|
||||
* To calculate the actual amount of change in the progress `delta`,
|
||||
* start with 100, divide by the length of time in seconds, then divide once more by 4.
|
||||
* @param tplayer the player
|
||||
* @param target the object being hacked
|
||||
* @param tool_guid the REK
|
||||
|
|
@ -5480,12 +5594,13 @@ object WorldSessionActor {
|
|||
* @param completeAction a custom action performed once the hack is completed
|
||||
* @param tickAction an optional action is is performed for each tick of progress
|
||||
*/
|
||||
private final case class ItemHacking(tplayer : Player,
|
||||
target : PlanetSideServerObject,
|
||||
tool_guid : PlanetSideGUID,
|
||||
delta : Float,
|
||||
completeAction : () => Unit,
|
||||
tickAction : Option[() => Unit] = None)
|
||||
private final case class HackingProgress(progressType : Int,
|
||||
tplayer : Player,
|
||||
target : PlanetSideServerObject,
|
||||
tool_guid : PlanetSideGUID,
|
||||
delta : Float,
|
||||
completeAction : () => Unit,
|
||||
tickAction : Option[() => Unit] = None)
|
||||
|
||||
private final case class NtuCharging(tplayer: Player,
|
||||
vehicle: Vehicle)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
import akka.actor.{ActorRef, ActorSystem, MDCContextAware}
|
||||
import akka.testkit.{ImplicitSender, TestKit, TestProbe}
|
||||
import com.typesafe.config.{ConfigFactory, ConfigValueFactory}
|
||||
import com.typesafe.config.ConfigFactory
|
||||
import net.psforever.packet.{ControlPacket, GamePacket}
|
||||
import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike}
|
||||
import org.specs2.specification.Scope
|
||||
|
|
@ -39,7 +39,7 @@ object ActorTest {
|
|||
Normally inaccessible from the outside, the payload is unwrapped within the standard receive PartialFunction.
|
||||
By interacting with a TestProbe constructor param, information that would be concealed by MdcMsg can be polled.
|
||||
|
||||
The l-neighbor of the MDCContextAware is the system of the ActorTest TestKit.
|
||||
The l-neighbor of the MDCContextAware is the system of the base.ActorTest TestKit.
|
||||
The r-neighbor of the MDCContextAware is this MDCTestProbe and, indirectly, the TestProbe that was interjected.
|
||||
Pass l-input into the MDCContextAware itself.
|
||||
The r-output is a normal message that can be polled on that TestProbe.
|
||||
|
|
|
|||
Loading…
Reference in a new issue