mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
Amenity Auto-Repair (#594)
* working proof of concept for ntu request/flow * ntu is now measured in Float rather than Int; adjusted the type declarations in ChatActor, as it was complaining * added auto repair information for amenities; modified terminal working example to include periodic repair timer * crude power state acknowledgement exchange between ntu silo and building, following by building and amenities; better management and control over auto-repair * separated auto-repair from terminal control; resource silo publishes an appropriate power state message upon formal start-up * various Damageble objects have been granted auto-repair; doors no longer report no event for intercepting unhandled messages * documentation and comments; unit tests and integration tests for AmneityAutoRepair, ResourceSilo, and BuildingActor * merge plus some fixes * addition checks for auto-repairing cavern equipment and for auto-repairing un-owned equipment
This commit is contained in:
parent
e4664d1727
commit
e58f1d5987
|
|
@ -11,19 +11,19 @@ object NtuCommand {
|
|||
*
|
||||
* @param source the nanite container recognized as the sender
|
||||
*/
|
||||
final case class Offer(source: NtuContainer) extends Command
|
||||
final case class Offer(source: NtuContainer, replyTo: ActorRef[Request]) extends Command
|
||||
|
||||
/** Message for asking for nanites from the recipient.
|
||||
*
|
||||
* @param amount the amount of nanites requested
|
||||
*/
|
||||
final case class Request(amount: Int, replyTo: ActorRef[Grant]) extends Command
|
||||
final case class Request(amount: Float, replyTo: ActorRef[Grant]) extends Command
|
||||
|
||||
/** Response for transferring nanites to a recipient.
|
||||
*
|
||||
* @param source the nanite container recognized as the sender
|
||||
* @param amount the nanites transferred in this package
|
||||
*/
|
||||
final case class Grant(source: NtuContainer, amount: Int)
|
||||
final case class Grant(source: NtuContainer, amount: Float) extends Command
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import net.psforever.objects.avatar.{BattleRank, Certification, CommandRank, Cos
|
|||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
import net.psforever.objects.{Default, GlobalDefinitions, Player, Session}
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.objects.serverobject.turret.{FacilityTurret, TurretUpgrade, WeaponTurrets}
|
||||
import net.psforever.objects.zones.Zoning
|
||||
import net.psforever.packet.game.{ChatMsg, DeadState, RequestDestroyMessage, ZonePopulationUpdateMessage}
|
||||
|
|
@ -346,9 +347,9 @@ class ChatActor(
|
|||
building.Amenities.foreach(amenity =>
|
||||
amenity.Definition match {
|
||||
case GlobalDefinitions.resource_silo =>
|
||||
val r = new scala.util.Random
|
||||
val silo = amenity.asInstanceOf[ResourceSilo]
|
||||
val ntu: Int = 900 + r.nextInt(100) - silo.NtuCapacitor
|
||||
val r = new scala.util.Random
|
||||
val silo = amenity.asInstanceOf[ResourceSilo]
|
||||
val ntu = 900f + r.nextFloat() * 100f - silo.NtuCapacitor
|
||||
silo.Actor ! ResourceSilo.UpdateChargeLevel(ntu)
|
||||
|
||||
case _ => ()
|
||||
|
|
@ -363,8 +364,8 @@ class ChatActor(
|
|||
case (CMT_CAPTUREBASE, _, contents) if gmCommandAllowed =>
|
||||
val args = contents.split(" ").filter(_ != "")
|
||||
|
||||
val (faction, factionPos) = args.zipWithIndex
|
||||
.map { case (faction, pos) => (faction.toLowerCase, pos) }
|
||||
val (faction, factionPos): (PlanetSideEmpire.Value, Option[Int]) = args.zipWithIndex
|
||||
.map { case (factionName, pos) => (factionName.toLowerCase, pos) }
|
||||
.flatMap {
|
||||
case ("tr", pos) => Some(PlanetSideEmpire.TR, pos)
|
||||
case ("nc", pos) => Some(PlanetSideEmpire.NC, pos)
|
||||
|
|
@ -373,11 +374,11 @@ class ChatActor(
|
|||
case _ => None
|
||||
}
|
||||
.headOption match {
|
||||
case Some((faction, pos)) => (faction, Some(pos))
|
||||
case Some((isFaction, pos)) => (isFaction, Some(pos))
|
||||
case None => (session.player.Faction, None)
|
||||
}
|
||||
|
||||
val (buildingsOption, buildingPos) = args.zipWithIndex.flatMap {
|
||||
val (buildingsOption, buildingPos): (Option[Seq[Building]], Option[Int]) = args.zipWithIndex.flatMap {
|
||||
case (_, pos) if factionPos.isDefined && factionPos.get == pos => None
|
||||
case ("all", pos) =>
|
||||
Some(
|
||||
|
|
@ -391,7 +392,7 @@ class ChatActor(
|
|||
),
|
||||
Some(pos)
|
||||
)
|
||||
case (name, pos) =>
|
||||
case (name: String, pos) =>
|
||||
session.zone.Buildings.find {
|
||||
case (_, building) => name.equalsIgnoreCase(building.Name) && building.CaptureTerminal.isDefined
|
||||
} match {
|
||||
|
|
@ -411,11 +412,11 @@ class ChatActor(
|
|||
case None => (None, None)
|
||||
}
|
||||
|
||||
val (timerOption, timerPos) = args.zipWithIndex.flatMap {
|
||||
val (timerOption, timerPos): (Option[Int], Option[Int]) = args.zipWithIndex.flatMap {
|
||||
case (_, pos)
|
||||
if factionPos.isDefined && factionPos.get == pos || buildingPos.isDefined && buildingPos.get == pos =>
|
||||
None
|
||||
case (timer, pos) =>
|
||||
case (timer: String, pos) =>
|
||||
try {
|
||||
val t = timer.toInt // TODO what is the timer format supposed to be?
|
||||
Some(Some(t), Some(pos))
|
||||
|
|
@ -436,15 +437,15 @@ class ChatActor(
|
|||
(None | Some(1), Some(0), None, Some(_), None) | (Some(1), Some(0), Some(2), Some(_), Some(_)) |
|
||||
// [all [<empire>|none]]
|
||||
(Some(1) | None, Some(0), None, Some(_), None) =>
|
||||
val buildings = buildingsOption.getOrElse(
|
||||
val buildings: Seq[Building] = buildingsOption.getOrElse(
|
||||
session.zone.Buildings
|
||||
.filter {
|
||||
case (_, building) =>
|
||||
building.PlayersInSOI.exists { soiPlayer =>
|
||||
session.player.CharId == soiPlayer.CharId
|
||||
}
|
||||
.values
|
||||
.filter { building =>
|
||||
building.PlayersInSOI.exists { soiPlayer =>
|
||||
session.player.CharId == soiPlayer.CharId
|
||||
}
|
||||
}
|
||||
.map { case (_, building) => building }
|
||||
.toSeq
|
||||
)
|
||||
buildings foreach { building =>
|
||||
// TODO implement timer
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
|
|||
import akka.pattern.ask
|
||||
import akka.util.Timeout
|
||||
import java.util.concurrent.TimeUnit
|
||||
import MDCContextAware.Implicits._
|
||||
import net.psforever.actors.net.MiddlewareActor
|
||||
import net.psforever.services.ServiceManager.Lookup
|
||||
import net.psforever.objects.locker.LockerContainer
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer}
|
|||
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
|
||||
import akka.{actor => classic}
|
||||
import net.psforever.actors.commands.NtuCommand
|
||||
import net.psforever.objects.serverobject.structures.{Building, WarpGate}
|
||||
import net.psforever.objects.{CommonNtuContainer, NtuContainer}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.persistence
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
|
@ -40,7 +42,13 @@ object BuildingActor {
|
|||
// Once they do, we won't need this anymore
|
||||
final case class MapUpdate() extends Command
|
||||
|
||||
final case class AmenityStateChange(obj: Amenity) extends Command
|
||||
|
||||
final case class Ntu(command: NtuCommand.Command) extends Command
|
||||
|
||||
final case class SuppliedWithNtu() extends Command
|
||||
|
||||
final case class NtuDepleted() extends Command
|
||||
}
|
||||
|
||||
class BuildingActor(
|
||||
|
|
@ -147,6 +155,26 @@ class BuildingActor(
|
|||
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||
Behaviors.same
|
||||
|
||||
case AmenityStateChange(_) =>
|
||||
//TODO when parameter object is finally immutable, perform analysis on it to determine specific actions
|
||||
//for now, just update the map
|
||||
galaxyService ! GalaxyServiceMessage(GalaxyAction.MapUpdate(building.infoUpdateMessage()))
|
||||
Behaviors.same
|
||||
|
||||
case msg @ NtuDepleted() =>
|
||||
log.trace(s"${building.Definition.Name} ${building.Name} ntu has been depleted")
|
||||
building.Amenities.foreach { amenity =>
|
||||
amenity.Actor ! msg
|
||||
}
|
||||
Behaviors.same
|
||||
|
||||
case msg @ SuppliedWithNtu() =>
|
||||
log.trace(s"ntu supply has been restored to ${building.Definition.Name} ${building.Name}")
|
||||
building.Amenities.foreach { amenity =>
|
||||
amenity.Actor ! msg
|
||||
}
|
||||
Behaviors.same
|
||||
|
||||
case Ntu(msg) =>
|
||||
ntu(msg)
|
||||
}
|
||||
|
|
@ -154,22 +182,41 @@ class BuildingActor(
|
|||
|
||||
def ntu(msg: NtuCommand.Command): Behavior[Command] = {
|
||||
import NtuCommand._
|
||||
val ntuBuilding = building match {
|
||||
case b: WarpGate => b
|
||||
case _ => return Behaviors.unhandled
|
||||
}
|
||||
|
||||
msg match {
|
||||
case Offer(source) =>
|
||||
case Offer(_, _) =>
|
||||
Behaviors.same
|
||||
case Request(amount, replyTo) =>
|
||||
ntuBuilding match {
|
||||
case warpGate: WarpGate => replyTo ! Grant(warpGate, if (warpGate.Active) amount else 0)
|
||||
case _ => return Behaviors.unhandled
|
||||
building match {
|
||||
case b: WarpGate =>
|
||||
//warp gates are an infiite source of nanites
|
||||
replyTo ! Grant(b, if (b.Active) amount else 0)
|
||||
Behaviors.same
|
||||
case _ if building.BuildingType == StructureType.Tower || building.Zone.map.cavern =>
|
||||
//towers and cavern stuff get free repairs
|
||||
replyTo ! NtuCommand.Grant(new FakeNtuSource(building), amount)
|
||||
Behaviors.same
|
||||
case _ =>
|
||||
//all other facilities require a storage silo for ntu
|
||||
building.Amenities.find(_.isInstanceOf[NtuContainer]) match {
|
||||
case Some(ntuContainer) =>
|
||||
ntuContainer.Actor ! msg //needs to redirect
|
||||
Behaviors.same
|
||||
case None =>
|
||||
replyTo ! NtuCommand.Grant(null, 0)
|
||||
Behaviors.unhandled
|
||||
}
|
||||
}
|
||||
|
||||
case _ =>
|
||||
Behaviors.same
|
||||
}
|
||||
|
||||
Behaviors.same
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class FakeNtuSource(private val building: Building)
|
||||
extends PlanetSideServerObject
|
||||
with CommonNtuContainer {
|
||||
override def NtuCapacitor = Float.MaxValue
|
||||
override def Faction = building.Faction
|
||||
override def Zone = building.Zone
|
||||
override def Definition = null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ import net.psforever.objects.serverobject.painbox.PainboxDefinition
|
|||
import net.psforever.objects.serverobject.terminals._
|
||||
import net.psforever.objects.serverobject.tube.SpawnTubeDefinition
|
||||
import net.psforever.objects.serverobject.resourcesilo.ResourceSiloDefinition
|
||||
import net.psforever.objects.serverobject.structures.{BuildingDefinition, WarpGateDefinition}
|
||||
import net.psforever.objects.serverobject.structures.{AutoRepairStats, BuildingDefinition, WarpGateDefinition}
|
||||
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
|
||||
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
|
||||
import net.psforever.objects.vital.damage.{DamageCalculations, DamageModifiers}
|
||||
|
|
@ -6747,6 +6747,7 @@ object GlobalDefinitions {
|
|||
spawn_terminal.Name = "spawn_terminal"
|
||||
spawn_terminal.Damageable = false
|
||||
spawn_terminal.Repairable = false
|
||||
spawn_terminal.autoRepair = AutoRepairStats(1, 5000, 200, 1) //TODO amount and drain are default? undefined?
|
||||
|
||||
order_terminal.Name = "order_terminal"
|
||||
order_terminal.Tab += 0 -> OrderTerminalDefinition.EquipmentPage(
|
||||
|
|
@ -6765,6 +6766,7 @@ object GlobalDefinitions {
|
|||
order_terminal.MaxHealth = 500
|
||||
order_terminal.Damageable = true
|
||||
order_terminal.Repairable = true
|
||||
order_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
order_terminal.RepairIfDestroyed = true
|
||||
order_terminal.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6828,6 +6830,7 @@ object GlobalDefinitions {
|
|||
cert_terminal.MaxHealth = 500
|
||||
cert_terminal.Damageable = true
|
||||
cert_terminal.Repairable = true
|
||||
cert_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
cert_terminal.RepairIfDestroyed = true
|
||||
cert_terminal.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6835,6 +6838,7 @@ object GlobalDefinitions {
|
|||
implant_terminal_mech.MaxHealth = 1500 //TODO 1000; right now, 1000 (mech) + 500 (interface)
|
||||
implant_terminal_mech.Damageable = true
|
||||
implant_terminal_mech.Repairable = true
|
||||
implant_terminal_mech.autoRepair = AutoRepairStats(1, 5000, 2400, 0.5f)
|
||||
implant_terminal_mech.RepairIfDestroyed = true
|
||||
|
||||
implant_terminal_interface.Name = "implant_terminal_interface"
|
||||
|
|
@ -6842,6 +6846,7 @@ object GlobalDefinitions {
|
|||
implant_terminal_interface.MaxHealth = 500
|
||||
implant_terminal_interface.Damageable = false //TODO true
|
||||
implant_terminal_interface.Repairable = true
|
||||
implant_terminal_interface.autoRepair = AutoRepairStats(1, 5000, 200, 1) //TODO amount and drain are default? undefined?
|
||||
implant_terminal_interface.RepairIfDestroyed = true
|
||||
|
||||
ground_vehicle_terminal.Name = "ground_vehicle_terminal"
|
||||
|
|
@ -6853,6 +6858,7 @@ object GlobalDefinitions {
|
|||
ground_vehicle_terminal.MaxHealth = 500
|
||||
ground_vehicle_terminal.Damageable = true
|
||||
ground_vehicle_terminal.Repairable = true
|
||||
ground_vehicle_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
ground_vehicle_terminal.RepairIfDestroyed = true
|
||||
ground_vehicle_terminal.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6865,6 +6871,7 @@ object GlobalDefinitions {
|
|||
air_vehicle_terminal.MaxHealth = 500
|
||||
air_vehicle_terminal.Damageable = true
|
||||
air_vehicle_terminal.Repairable = true
|
||||
air_vehicle_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
air_vehicle_terminal.RepairIfDestroyed = true
|
||||
air_vehicle_terminal.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6877,6 +6884,7 @@ object GlobalDefinitions {
|
|||
dropship_vehicle_terminal.MaxHealth = 500
|
||||
dropship_vehicle_terminal.Damageable = true
|
||||
dropship_vehicle_terminal.Repairable = true
|
||||
dropship_vehicle_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
dropship_vehicle_terminal.RepairIfDestroyed = true
|
||||
dropship_vehicle_terminal.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6889,6 +6897,7 @@ object GlobalDefinitions {
|
|||
vehicle_terminal_combined.MaxHealth = 500
|
||||
vehicle_terminal_combined.Damageable = true
|
||||
vehicle_terminal_combined.Repairable = true
|
||||
vehicle_terminal_combined.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
vehicle_terminal_combined.RepairIfDestroyed = true
|
||||
vehicle_terminal_combined.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6901,6 +6910,7 @@ object GlobalDefinitions {
|
|||
vanu_air_vehicle_term.MaxHealth = 500
|
||||
vanu_air_vehicle_term.Damageable = true
|
||||
vanu_air_vehicle_term.Repairable = true
|
||||
vanu_air_vehicle_term.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
vanu_air_vehicle_term.RepairIfDestroyed = true
|
||||
vanu_air_vehicle_term.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6913,6 +6923,7 @@ object GlobalDefinitions {
|
|||
vanu_vehicle_term.MaxHealth = 500
|
||||
vanu_vehicle_term.Damageable = true
|
||||
vanu_vehicle_term.Repairable = true
|
||||
vanu_vehicle_term.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
vanu_vehicle_term.RepairIfDestroyed = true
|
||||
vanu_vehicle_term.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6925,6 +6936,7 @@ object GlobalDefinitions {
|
|||
bfr_terminal.MaxHealth = 500
|
||||
bfr_terminal.Damageable = true
|
||||
bfr_terminal.Repairable = true
|
||||
bfr_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
bfr_terminal.RepairIfDestroyed = true
|
||||
bfr_terminal.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6935,6 +6947,7 @@ object GlobalDefinitions {
|
|||
respawn_tube.Damageable = true
|
||||
respawn_tube.DamageableByFriendlyFire = false
|
||||
respawn_tube.Repairable = true
|
||||
respawn_tube.autoRepair = AutoRepairStats(1, 10000, 2400, 1)
|
||||
respawn_tube.RepairIfDestroyed = true
|
||||
respawn_tube.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6944,6 +6957,7 @@ object GlobalDefinitions {
|
|||
respawn_tube_sanctuary.Damageable = false //true?
|
||||
respawn_tube_sanctuary.DamageableByFriendlyFire = false
|
||||
respawn_tube_sanctuary.Repairable = true
|
||||
respawn_tube_sanctuary.autoRepair = AutoRepairStats(1, 10000, 2400, 1)
|
||||
|
||||
respawn_tube_tower.Name = "respawn_tube_tower"
|
||||
respawn_tube_tower.Delay = 10
|
||||
|
|
@ -6952,6 +6966,7 @@ object GlobalDefinitions {
|
|||
respawn_tube_tower.Damageable = true
|
||||
respawn_tube_tower.DamageableByFriendlyFire = false
|
||||
respawn_tube_tower.Repairable = true
|
||||
respawn_tube_tower.autoRepair = AutoRepairStats(1, 10000, 2400, 1)
|
||||
respawn_tube_tower.RepairIfDestroyed = true
|
||||
respawn_tube_tower.Subtract.Damage1 = 8
|
||||
|
||||
|
|
@ -6969,6 +6984,7 @@ object GlobalDefinitions {
|
|||
medical_terminal.MaxHealth = 500
|
||||
medical_terminal.Damageable = true
|
||||
medical_terminal.Repairable = true
|
||||
medical_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
medical_terminal.RepairIfDestroyed = true
|
||||
|
||||
adv_med_terminal.Name = "adv_med_terminal"
|
||||
|
|
@ -6980,6 +6996,7 @@ object GlobalDefinitions {
|
|||
adv_med_terminal.MaxHealth = 750
|
||||
adv_med_terminal.Damageable = true
|
||||
adv_med_terminal.Repairable = true
|
||||
adv_med_terminal.autoRepair = AutoRepairStats(1, 5000, 2400, 0.5f)
|
||||
adv_med_terminal.RepairIfDestroyed = true
|
||||
|
||||
crystals_health_a.Name = "crystals_health_a"
|
||||
|
|
@ -7007,6 +7024,7 @@ object GlobalDefinitions {
|
|||
portable_med_terminal.MaxHealth = 500
|
||||
portable_med_terminal.Damageable = false //TODO actually true
|
||||
portable_med_terminal.Repairable = false
|
||||
portable_med_terminal.autoRepair = AutoRepairStats(1, 5000, 3500, 0.5f)
|
||||
|
||||
pad_landing_frame.Name = "pad_landing_frame"
|
||||
pad_landing_frame.Interval = 1000
|
||||
|
|
@ -7120,6 +7138,7 @@ object GlobalDefinitions {
|
|||
manned_turret.Damageable = true
|
||||
manned_turret.DamageDisablesAt = 0
|
||||
manned_turret.Repairable = true
|
||||
manned_turret.autoRepair = AutoRepairStats(1, 10000, 1600, 0.5f)
|
||||
manned_turret.RepairIfDestroyed = true
|
||||
manned_turret.Weapons += 1 -> new mutable.HashMap()
|
||||
manned_turret.Weapons(1) += TurretUpgrade.None -> phalanx_sgl_hevgatcan
|
||||
|
|
@ -7134,6 +7153,7 @@ object GlobalDefinitions {
|
|||
vanu_sentry_turret.Damageable = true
|
||||
vanu_sentry_turret.DamageDisablesAt = 0
|
||||
vanu_sentry_turret.Repairable = true
|
||||
vanu_sentry_turret.autoRepair = AutoRepairStats(3, 10000, 1000, 0.5f)
|
||||
vanu_sentry_turret.RepairIfDestroyed = true
|
||||
vanu_sentry_turret.Weapons += 1 -> new mutable.HashMap()
|
||||
vanu_sentry_turret.Weapons(1) += TurretUpgrade.None -> vanu_sentry_turret_weapon
|
||||
|
|
@ -7175,9 +7195,9 @@ object GlobalDefinitions {
|
|||
generator.Damageable = true
|
||||
generator.DamageableByFriendlyFire = false
|
||||
generator.Repairable = true
|
||||
generator.autoRepair = AutoRepairStats(1, 5000, 875, 1)
|
||||
generator.RepairDistance = 13.5f
|
||||
generator.RepairIfDestroyed = true
|
||||
generator.Subtract.Damage1 = 9
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ object Ntu {
|
|||
* @param max the amount of nanites required to not make further requests;
|
||||
* if 0, the `sender` is full and the message is for clean up operations
|
||||
*/
|
||||
final case class Request(min: Int, max: Int)
|
||||
final case class Request(min: Float, max: Float)
|
||||
|
||||
/**
|
||||
* Message for transferring nanites to a recipient.
|
||||
|
|
@ -31,23 +31,23 @@ object Ntu {
|
|||
* @param src the nanite container recognized as the sender
|
||||
* @param amount the nanites transferred in this package
|
||||
*/
|
||||
final case class Grant(src: NtuContainer, amount: Int)
|
||||
final case class Grant(src: NtuContainer, amount: Float)
|
||||
}
|
||||
|
||||
trait NtuContainer extends TransferContainer {
|
||||
def NtuCapacitor: Int
|
||||
def NtuCapacitor: Float
|
||||
|
||||
def NtuCapacitor_=(value: Int): Int
|
||||
def NtuCapacitor_=(value: Float): Float
|
||||
|
||||
def Definition: NtuContainerDefinition
|
||||
}
|
||||
|
||||
trait CommonNtuContainer extends NtuContainer {
|
||||
private var ntuCapacitor: Int = 0
|
||||
private var ntuCapacitor: Float = 0
|
||||
|
||||
def NtuCapacitor: Int = ntuCapacitor
|
||||
def NtuCapacitor: Float = ntuCapacitor
|
||||
|
||||
def NtuCapacitor_=(value: Int): Int = {
|
||||
def NtuCapacitor_=(value: Float): Float = {
|
||||
ntuCapacitor = scala.math.max(0, scala.math.min(value, Definition.MaxNtuCapacitor))
|
||||
NtuCapacitor
|
||||
}
|
||||
|
|
@ -56,11 +56,11 @@ trait CommonNtuContainer extends NtuContainer {
|
|||
}
|
||||
|
||||
trait NtuContainerDefinition {
|
||||
private var maxNtuCapacitor: Int = 0
|
||||
private var maxNtuCapacitor: Float = 0
|
||||
|
||||
def MaxNtuCapacitor: Int = maxNtuCapacitor
|
||||
def MaxNtuCapacitor: Float = maxNtuCapacitor
|
||||
|
||||
def MaxNtuCapacitor_=(max: Int): Int = {
|
||||
def MaxNtuCapacitor_=(max: Float): Float = {
|
||||
maxNtuCapacitor = max
|
||||
MaxNtuCapacitor
|
||||
}
|
||||
|
|
@ -76,7 +76,12 @@ trait NtuStorageBehavior extends Actor {
|
|||
|
||||
case Ntu.Request(min, max) => HandleNtuRequest(sender(), min, max)
|
||||
|
||||
case NtuCommand.Request(amount, replyTo) =>
|
||||
import akka.actor.typed.scaladsl.adapter.TypedActorRefOps
|
||||
HandleNtuRequest(new TypedActorRefOps(replyTo).toClassic, amount, amount+1)
|
||||
|
||||
case Ntu.Grant(src, amount) => HandleNtuGrant(sender(), src, amount)
|
||||
|
||||
case NtuCommand.Grant(src, amount) => HandleNtuGrant(sender(), src, amount)
|
||||
}
|
||||
|
||||
|
|
@ -84,7 +89,7 @@ trait NtuStorageBehavior extends Actor {
|
|||
|
||||
def StopNtuBehavior(sender: ActorRef): Unit
|
||||
|
||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit
|
||||
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit
|
||||
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit
|
||||
}
|
||||
|
|
|
|||
|
|
@ -231,9 +231,9 @@ object Vehicles {
|
|||
// Forcefully dismount any cargo
|
||||
target.CargoHolds.values.foreach(cargoHold => {
|
||||
cargoHold.Occupant match {
|
||||
case Some(cargo: Vehicle) => {
|
||||
case Some(cargo: Vehicle) =>
|
||||
cargo.Seats(0).Occupant match {
|
||||
case Some(cargoDriver: Player) =>
|
||||
case Some(_: Player) =>
|
||||
CargoBehavior.HandleVehicleCargoDismount(
|
||||
target.Zone,
|
||||
cargo.GUID,
|
||||
|
|
@ -243,8 +243,7 @@ object Vehicles {
|
|||
)
|
||||
case None =>
|
||||
log.error("FinishHackingVehicle: vehicle in cargo hold missing driver")
|
||||
CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, target.GUID, target, false, false, true)
|
||||
}
|
||||
CargoBehavior.HandleVehicleCargoDismount(cargo.GUID, cargo, target.GUID, target, bailed = false, requestedByPassenger = false, kicked = true)
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
|
|
@ -326,7 +325,7 @@ object Vehicles {
|
|||
Vector3.DistanceSquared(obj.Position.xy, target.Position.xy) < soiRadius * soiRadius
|
||||
} =>
|
||||
Some(target.asInstanceOf[NtuContainer])
|
||||
case None =>
|
||||
case _ =>
|
||||
None
|
||||
}).orElse {
|
||||
val position = obj.Position.xy
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ class DoorControl(door: Door) extends Actor with FactionAffinityBehavior.Check {
|
|||
case Door.Use(player, msg) =>
|
||||
sender() ! Door.DoorMessage(player, msg, door.Use(player, msg))
|
||||
|
||||
case _ =>
|
||||
sender() ! Door.NoEvent()
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
package net.psforever.objects.serverobject.generator
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.{Player, Tool}
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||
import net.psforever.objects.serverobject.damage.DamageableEntity
|
||||
import net.psforever.objects.serverobject.repair.{Repairable, RepairableEntity}
|
||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, Repairable, RepairableEntity}
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
import net.psforever.objects.vital.DamageFromExplosion
|
||||
import net.psforever.packet.game.TriggerEffectMessage
|
||||
|
|
@ -27,10 +28,12 @@ class GeneratorControl(gen: Generator)
|
|||
extends Actor
|
||||
with FactionAffinityBehavior.Check
|
||||
with DamageableEntity
|
||||
with RepairableEntity {
|
||||
def FactionObject = gen
|
||||
def DamageableObject = gen
|
||||
def RepairableObject = gen
|
||||
with RepairableEntity
|
||||
with AmenityAutoRepair {
|
||||
def FactionObject = gen
|
||||
def DamageableObject = gen
|
||||
def RepairableObject = gen
|
||||
def AutoRepairObject = gen
|
||||
var imminentExplosion: Boolean = false
|
||||
var alarmCooldownPeriod: Boolean = false
|
||||
|
||||
|
|
@ -38,6 +41,7 @@ class GeneratorControl(gen: Generator)
|
|||
checkBehavior
|
||||
.orElse(takesDamage)
|
||||
.orElse(canBeRepairedByNanoDispenser)
|
||||
.orElse(autoRepairBehavior)
|
||||
.orElse {
|
||||
case GeneratorControl.GeneratorExplodes() => //TODO this only works with projectiles right now!
|
||||
val zone = gen.Zone
|
||||
|
|
@ -89,6 +93,7 @@ class GeneratorControl(gen: Generator)
|
|||
}
|
||||
|
||||
override protected def DamageAwareness(target: Target, cause: ResolvedProjectile, amount: Any): Unit = {
|
||||
tryAutoRepair()
|
||||
super.DamageAwareness(target, cause, amount)
|
||||
val damageTo = amount match {
|
||||
case a: Int => a
|
||||
|
|
@ -98,6 +103,7 @@ class GeneratorControl(gen: Generator)
|
|||
}
|
||||
|
||||
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
||||
tryAutoRepair()
|
||||
if (!target.Destroyed) {
|
||||
target.Health = 1 //temporary
|
||||
imminentExplosion = true
|
||||
|
|
@ -106,6 +112,14 @@ class GeneratorControl(gen: Generator)
|
|||
}
|
||||
}
|
||||
|
||||
override def PerformRepairs(target : Target, amount : Int) : Int = {
|
||||
val newHealth = super.PerformRepairs(target, amount)
|
||||
if(newHealth == target.Definition.MaxHealth) {
|
||||
stopAutoRepair()
|
||||
}
|
||||
newHealth
|
||||
}
|
||||
|
||||
override def Restoration(obj: Repairable.Target): Unit = {
|
||||
super.Restoration(obj)
|
||||
gen.Condition = PlanetSideGeneratorState.Normal
|
||||
|
|
@ -137,7 +151,7 @@ object GeneratorControl {
|
|||
*/
|
||||
private def UpdateOwner(obj: Generator): Unit = {
|
||||
obj.Owner match {
|
||||
case b: Building => b.Actor ! Building.AmenityStateChange(obj)
|
||||
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(obj)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
|||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity, DamageableMountable}
|
||||
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
||||
import net.psforever.objects.serverobject.repair.RepairableEntity
|
||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableEntity}
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
|
||||
/**
|
||||
|
|
@ -24,12 +24,14 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
with MountableBehavior.Dismount
|
||||
with HackableBehavior.GenericHackable
|
||||
with DamageableEntity
|
||||
with RepairableEntity {
|
||||
with RepairableEntity
|
||||
with AmenityAutoRepair {
|
||||
def MountableObject = mech
|
||||
def HackableObject = mech
|
||||
def FactionObject = mech
|
||||
def DamageableObject = mech
|
||||
def RepairableObject = mech
|
||||
def AutoRepairObject = mech
|
||||
|
||||
def receive: Receive =
|
||||
checkBehavior
|
||||
|
|
@ -38,6 +40,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
.orElse(hackableBehavior)
|
||||
.orElse(takesDamage)
|
||||
.orElse(canBeRepairedByNanoDispenser)
|
||||
.orElse(autoRepairBehavior)
|
||||
.orElse {
|
||||
case CommonMessages.Use(player, Some(item: SimpleItem))
|
||||
if item.Definition == GlobalDefinitions.remote_electronics_kit =>
|
||||
|
|
@ -73,6 +76,7 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
}
|
||||
|
||||
override protected def DamageAwareness(target: Target, cause: ResolvedProjectile, amount: Any): Unit = {
|
||||
tryAutoRepair()
|
||||
super.DamageAwareness(target, cause, amount)
|
||||
val damageTo = amount match {
|
||||
case a: Int => a
|
||||
|
|
@ -86,4 +90,12 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
|
|||
DamageableMountable.DestructionAwareness(DamageableObject, cause)
|
||||
target.ClearHistory()
|
||||
}
|
||||
|
||||
override def PerformRepairs(target : Damageable.Target, amount : Int) : Int = {
|
||||
val newHealth = super.PerformRepairs(target, amount)
|
||||
if(newHealth == target.Definition.MaxHealth) {
|
||||
stopAutoRepair()
|
||||
}
|
||||
newHealth
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,197 @@
|
|||
//Copyright (c) 2020 PSForever
|
||||
package net.psforever.objects.serverobject.repair
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||
import akka.actor.typed.{ActorRef => TypedActorRef}
|
||||
import akka.actor.typed.scaladsl.adapter.ClassicActorRefOps
|
||||
import net.psforever.actors.commands.NtuCommand
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.{Default, NtuContainer, NtuStorageBehavior}
|
||||
import net.psforever.objects.serverobject.damage.Damageable
|
||||
import net.psforever.objects.serverobject.structures.{Amenity, AutoRepairStats, Building}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
* A mixin for handling the automatic repair functionality of facility amenities.
|
||||
* Auto-repair is facilitated primarily as a function of nanite transfer unit (NTU) provisions
|
||||
* and is prompted by the amenity itself sustaining damage
|
||||
* and being, at some level, capable of being repaired.
|
||||
* In major facilities - technology plants, bio labs, etc. -
|
||||
* this NTU is obtained from that facility's nanite resource silo.
|
||||
* The amenity that wishes to be repaired asks the facility for nanite.
|
||||
* The reply comes from the NTU source, or from the facility again.
|
||||
* In exchange for the automatic repair, the silo looses some of its NTU stockpile
|
||||
* and that entails all of the consequences of losing all of the NTU for the base.
|
||||
* In smaller field tower bases, the lack of resource silo should not hinder operations
|
||||
* as auto-repair is still carried out nonetheless.
|
||||
* The consequences of losing NTU do not apply in this case;
|
||||
* the field tower is considered to have unlimited, unshared NTU.
|
||||
*/
|
||||
trait AmenityAutoRepair
|
||||
extends NtuStorageBehavior {
|
||||
_: Damageable with RepairableEntity with Actor =>
|
||||
/** a dedicated reference to self that facilitates in receiving `NtuCommand.Grant` messages for auto-repair operation */
|
||||
private lazy val ntuGrantActorRef: TypedActorRef[NtuCommand.Grant] =
|
||||
new ClassicActorRefOps(self).toTyped[NtuCommand.Grant]
|
||||
/** the function that initializes auto-repair operations, if those operations have not yet started */
|
||||
private var autoRepairStartFunc: ()=>Unit = startAutoRepairIfStopped
|
||||
/** the timer for requests for auto-repair-actionable resource deposits (NTU) */
|
||||
private var autoRepairTimer: Cancellable = Default.Cancellable
|
||||
|
||||
def AutoRepairObject: Amenity
|
||||
|
||||
final val autoRepairBehavior: Receive = storageBehavior.orElse {
|
||||
case BuildingActor.SuppliedWithNtu() =>
|
||||
withNtuSupplyCallback()
|
||||
|
||||
case BuildingActor.NtuDepleted() =>
|
||||
noNtuSupplyCallback()
|
||||
}
|
||||
|
||||
//nothing special
|
||||
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = { }
|
||||
|
||||
/**
|
||||
* Stop the auto-repair timer.
|
||||
*/
|
||||
def StopNtuBehavior(sender : ActorRef) : Unit = {
|
||||
autoRepairTimer.cancel()
|
||||
}
|
||||
|
||||
//nothing special
|
||||
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = { }
|
||||
|
||||
/**
|
||||
* When reports of an NTU provision is returned to the requesting amenity,
|
||||
* the amount of repair that can be performed is obtained
|
||||
* and, if the amenity still requires those repairs,
|
||||
* auto-repair executes a single tick.
|
||||
* @see `RepairableAmenity`
|
||||
*/
|
||||
def HandleNtuGrant(sender : ActorRef, src : NtuContainer, amount : Float) : Unit = {
|
||||
val obj = AutoRepairObject
|
||||
obj.Definition.autoRepair match {
|
||||
case Some(repair : AutoRepairStats) if obj.Health < obj.Definition.MaxHealth =>
|
||||
PerformRepairs(obj, repair.amount)
|
||||
case _ =>
|
||||
StopNtuBehavior(sender)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Confirm that a provision of NTU to the potential requesting amenity is possible.
|
||||
* Attempt to start auto-repair operations.
|
||||
*/
|
||||
def withNtuSupplyCallback(): Unit = {
|
||||
startAutoRepairFunctionality()
|
||||
}
|
||||
|
||||
/**
|
||||
* No (further) provisions of NTU to the potential requesting amenity will be forthcoming.
|
||||
* Cancel any attempts at auto-repair.
|
||||
*/
|
||||
def noNtuSupplyCallback(): Unit = {
|
||||
stopAutoRepairFunctionality()
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to start auto-repair operation if possible,
|
||||
* restarting an existing timed operation if necessary.
|
||||
* Set a function that will attempt auto-repair operations under specific trigger-able conditions (damage).
|
||||
*/
|
||||
private def startAutoRepairFunctionality(): Unit = {
|
||||
retimeAutoRepair()
|
||||
autoRepairStartFunc = startAutoRepairIfStopped
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any attempts at auto-repair
|
||||
* by stopping any currently processing repair timer
|
||||
* and ensuring that otherwise trigger-able conditions (damages) do not instigate auto-repair operations.
|
||||
* @see `stopAutoRepair`
|
||||
*/
|
||||
private def stopAutoRepairFunctionality(): Unit = {
|
||||
autoRepairTimer.cancel()
|
||||
autoRepairStartFunc = ()=>{}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to start auto-repair operation
|
||||
* only if no operation is currently being processed.
|
||||
*/
|
||||
private def startAutoRepairIfStopped(): Unit = {
|
||||
if(autoRepairTimer.isCancelled) {
|
||||
retimeAutoRepair()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to start auto-repair operation
|
||||
* only if no operation is currently being processed.
|
||||
* @return `true`, if the auto-repair process started specifically due to this call;
|
||||
* `false`, if it was already started, or did not start
|
||||
*/
|
||||
final def tryAutoRepair(): Boolean = {
|
||||
val before = autoRepairTimer.isCancelled
|
||||
autoRepairStartFunc()
|
||||
!(before || autoRepairTimer.isCancelled)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancel any attempts at auto-repair
|
||||
* by stopping any currently processing repair timer
|
||||
* The operation can be resumed.
|
||||
* @see `stopAutoRepairFunctionality`
|
||||
*/
|
||||
final def stopAutoRepair(): Unit = {
|
||||
autoRepairTimer.cancel()
|
||||
}
|
||||
|
||||
/**
|
||||
* As long as setup information regarding the auto-repair process can be discovered in the amenity's definition
|
||||
* and the amenity actually requires to be performed,
|
||||
* perform the setup for the auto-repair operation.
|
||||
*/
|
||||
private def retimeAutoRepair(): Unit = {
|
||||
val obj = AutoRepairObject
|
||||
obj.Definition.autoRepair match {
|
||||
case Some(AutoRepairStats(_, start, interval, drain)) if obj.Health < obj.Definition.MaxHealth =>
|
||||
retimeAutoRepair(start, interval, drain)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As long as setup information regarding the auto-repair process can be provided,
|
||||
* perform the setup for the auto-repair operation.
|
||||
* @see `BuildingActor.Ntu`
|
||||
* @see `NtuCommand.Request`
|
||||
* @see `scheduleWithFixedDelay`
|
||||
* @param initialDelay the delay before the first message
|
||||
* @param delay the delay between subsequent messages, after the first
|
||||
* @param drain the amount of NTU being levied as a cost for auto-repair operation
|
||||
* (the responding entity determines how to satisfy the cost)
|
||||
*/
|
||||
private def retimeAutoRepair(initialDelay: Long, delay: Long, drain: Float): Unit = {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
autoRepairTimer.cancel()
|
||||
autoRepairTimer = if(AutoRepairObject.Owner == Building.NoBuilding) {
|
||||
//without an owner, auto-repair freely
|
||||
context.system.scheduler.scheduleWithFixedDelay(
|
||||
initialDelay milliseconds,
|
||||
delay milliseconds,
|
||||
self,
|
||||
NtuCommand.Grant(null, drain)
|
||||
)
|
||||
} else {
|
||||
//ask
|
||||
context.system.scheduler.scheduleWithFixedDelay(
|
||||
initialDelay milliseconds,
|
||||
delay milliseconds,
|
||||
AutoRepairObject.Owner.Actor,
|
||||
BuildingActor.Ntu(NtuCommand.Request(drain, ntuGrantActorRef))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -78,32 +78,21 @@ trait RepairableEntity extends Repairable {
|
|||
*/
|
||||
protected def PerformRepairs(target: Repairable.Target, player: Player, item: Tool): Unit = {
|
||||
val definition = target.Definition
|
||||
val zone = target.Zone
|
||||
val events = zone.AvatarEvents
|
||||
val events = target.Zone.AvatarEvents
|
||||
val name = player.Name
|
||||
val tguid = target.GUID
|
||||
val originalHealth = target.Health
|
||||
val updatedHealth =
|
||||
if (!(player.isMoving(1f) || target.isMoving(1f))) { //only allow stationary repairs within margin of error
|
||||
val newHealth = target.Health = originalHealth + Repairable.Quality + RepairValue(item) + definition.RepairMod
|
||||
val zoneId = zone.id
|
||||
val repairValue = Repairable.Quality + RepairValue(item) + target.Definition.RepairMod
|
||||
val magazine = item.Discharge()
|
||||
events ! AvatarServiceMessage(
|
||||
name,
|
||||
player.Name,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
InventoryStateMessage(item.AmmoSlot.Box.GUID, item.GUID, magazine.toLong)
|
||||
)
|
||||
)
|
||||
if (target.Destroyed) {
|
||||
if (newHealth >= definition.RepairRestoresAt) {
|
||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
||||
Restoration(target)
|
||||
}
|
||||
} else {
|
||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
||||
}
|
||||
newHealth
|
||||
PerformRepairs(target, repairValue)
|
||||
} else {
|
||||
originalHealth
|
||||
}
|
||||
|
|
@ -112,11 +101,28 @@ trait RepairableEntity extends Repairable {
|
|||
name,
|
||||
AvatarAction.SendResponse(
|
||||
Service.defaultPlayerGUID,
|
||||
RepairMessage(tguid, updatedHealth * 100 / definition.MaxHealth)
|
||||
RepairMessage(target.GUID, updatedHealth * 100 / definition.MaxHealth)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
protected def PerformRepairs(target: Repairable.Target, amount: Int): Int = {
|
||||
val zone = target.Zone
|
||||
val zoneId = zone.id
|
||||
val events = zone.AvatarEvents
|
||||
val tguid = target.GUID
|
||||
val newHealth = target.Health = target.Health + amount
|
||||
if (target.Destroyed) {
|
||||
if (newHealth >= target.Definition.RepairRestoresAt) {
|
||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
||||
Restoration(target)
|
||||
}
|
||||
} else {
|
||||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 0, newHealth))
|
||||
}
|
||||
newHealth
|
||||
}
|
||||
|
||||
/* random object repair modifier */
|
||||
override def RepairValue(item: Tool): Int = item.FireMode.Add.Damage1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
|||
// For the NTU display bar
|
||||
private var capacitorDisplay: Long = 0
|
||||
|
||||
def MaxNtuCapacitor : Int = Definition.MaxNtuCapacitor
|
||||
def MaxNtuCapacitor : Float = Definition.MaxNtuCapacitor
|
||||
|
||||
def LowNtuWarningOn: Boolean = lowNtuWarningOn
|
||||
def LowNtuWarningOn_=(enabled: Boolean): Boolean = {
|
||||
|
|
@ -24,7 +24,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
|||
LowNtuWarningOn
|
||||
}
|
||||
|
||||
def CapacitorDisplay : Long = scala.math.ceil((NtuCapacitor.toFloat / MaxNtuCapacitor.toFloat) * 10).toInt
|
||||
def CapacitorDisplay : Long = scala.math.ceil((NtuCapacitor / MaxNtuCapacitor) * 10).toInt
|
||||
|
||||
def Definition: ResourceSiloDefinition = GlobalDefinitions.resource_silo
|
||||
|
||||
|
|
@ -34,7 +34,7 @@ class ResourceSilo extends Amenity with CommonNtuContainer {
|
|||
}
|
||||
|
||||
object ResourceSilo {
|
||||
final case class UpdateChargeLevel(amount: Int)
|
||||
final case class UpdateChargeLevel(amount: Float)
|
||||
final case class LowNtuWarning(enabled: Boolean)
|
||||
sealed trait Exchange
|
||||
final case class ChargeEvent() extends Exchange
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.resourcesilo
|
|||
|
||||
import akka.actor.{Actor, ActorRef}
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
|
||||
import net.psforever.objects.serverobject.transfer.TransferBehavior
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
|
|
@ -28,12 +28,19 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
def FactionObject: FactionAffinity = resourceSilo
|
||||
|
||||
private[this] val log = org.log4s.getLogger
|
||||
var panelAnimationFunc: Int => Unit = PanelAnimation
|
||||
var panelAnimationFunc: Float => Unit = PanelAnimation
|
||||
|
||||
def receive: Receive = {
|
||||
case "startup" =>
|
||||
// todo: This is just a temporary solution to drain NTU over time. When base object destruction is properly implemented NTU should be deducted when base objects repair themselves
|
||||
// context.system.scheduler.schedule(5 second, 5 second, self, ResourceSilo.UpdateChargeLevel(-1))
|
||||
resourceSilo.Owner match {
|
||||
case building: Building =>
|
||||
building.Actor ! (if (resourceSilo.NtuCapacitor <= 0f ) {
|
||||
BuildingActor.NtuDepleted()
|
||||
} else {
|
||||
BuildingActor.SuppliedWithNtu()
|
||||
})
|
||||
case _ => ;
|
||||
}
|
||||
context.become(Processing)
|
||||
|
||||
case _ => ;
|
||||
|
|
@ -59,7 +66,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
case ResourceSilo.LowNtuWarning(enabled: Boolean) =>
|
||||
LowNtuWarning(enabled)
|
||||
|
||||
case ResourceSilo.UpdateChargeLevel(amount: Int) =>
|
||||
case ResourceSilo.UpdateChargeLevel(amount: Float) =>
|
||||
UpdateChargeLevel(amount)
|
||||
|
||||
case _ => ;
|
||||
|
|
@ -76,7 +83,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
)
|
||||
}
|
||||
|
||||
def UpdateChargeLevel(amount: Int): Unit = {
|
||||
def UpdateChargeLevel(amount: Float): Unit = {
|
||||
val siloChargeBeforeChange = resourceSilo.NtuCapacitor
|
||||
val siloDisplayBeforeChange = resourceSilo.CapacitorDisplay
|
||||
val building = resourceSilo.Owner.asInstanceOf[Building]
|
||||
|
|
@ -93,14 +100,13 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
log.trace(
|
||||
s"Silo ${resourceSilo.GUID} NTU bar level has changed from $siloDisplayBeforeChange to ${resourceSilo.CapacitorDisplay}"
|
||||
)
|
||||
resourceSilo.Owner.Actor ! BuildingActor.MapUpdate()
|
||||
zone.AvatarEvents ! AvatarServiceMessage(
|
||||
zone.id,
|
||||
AvatarAction.PlanetsideAttribute(resourceSilo.GUID, 45, resourceSilo.CapacitorDisplay)
|
||||
)
|
||||
building.Actor ! BuildingActor.MapUpdate()
|
||||
}
|
||||
val ntuIsLow = resourceSilo.NtuCapacitor.toFloat / resourceSilo.Definition.MaxNtuCapacitor.toFloat < 0.2f
|
||||
val ntuIsLow = resourceSilo.NtuCapacitor / resourceSilo.Definition.MaxNtuCapacitor < 0.2f
|
||||
if (resourceSilo.LowNtuWarningOn && !ntuIsLow) {
|
||||
LowNtuWarning(enabled = false)
|
||||
} else if (!resourceSilo.LowNtuWarningOn && ntuIsLow) {
|
||||
|
|
@ -109,6 +115,8 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
if (resourceSilo.NtuCapacitor == 0 && siloChargeBeforeChange > 0) {
|
||||
// Oops, someone let the base run out of power. Shut it all down.
|
||||
zone.AvatarEvents ! AvatarServiceMessage(zone.id, AvatarAction.PlanetsideAttribute(building.GUID, 48, 1))
|
||||
building.Actor ! BuildingActor.NtuDepleted()
|
||||
building.Actor ! BuildingActor.AmenityStateChange(resourceSilo)
|
||||
building.Actor ! BuildingActor.SetFaction(PlanetSideEmpire.NEUTRAL)
|
||||
} else if (siloChargeBeforeChange == 0 && resourceSilo.NtuCapacitor > 0) {
|
||||
// Power restored. Reactor Online. Sensors Online. Weapons Online. All systems nominal.
|
||||
|
|
@ -117,7 +125,8 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
zone.id,
|
||||
AvatarAction.PlanetsideAttribute(building.GUID, 48, 0)
|
||||
)
|
||||
building.Zone.actor ! ZoneActor.ZoneMapUpdate()
|
||||
building.Actor ! BuildingActor.SuppliedWithNtu()
|
||||
building.Actor ! BuildingActor.AmenityStateChange(resourceSilo)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -148,7 +157,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
* @param min a minimum amount of nanites requested;
|
||||
* @param max the amount of nanites required to not make further requests;
|
||||
*/
|
||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit = {
|
||||
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = {
|
||||
val originalAmount = resourceSilo.NtuCapacitor
|
||||
UpdateChargeLevel(-min)
|
||||
sender ! Ntu.Grant(resourceSilo, originalAmount - resourceSilo.NtuCapacitor)
|
||||
|
|
@ -157,7 +166,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
/**
|
||||
* Accept nanites into the silo capacitor and set the animation state.
|
||||
*/
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit = {
|
||||
if (amount != 0) {
|
||||
val originalAmount = resourceSilo.NtuCapacitor
|
||||
UpdateChargeLevel(amount)
|
||||
|
|
@ -174,7 +183,7 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
* @param trigger if positive, activate the animation;
|
||||
* if negative or zero, disable the animation
|
||||
*/
|
||||
def PanelAnimation(trigger: Int): Unit = {
|
||||
def PanelAnimation(trigger: Float): Unit = {
|
||||
val zone = resourceSilo.Zone
|
||||
zone.VehicleEvents ! VehicleServiceMessage(
|
||||
zone.id,
|
||||
|
|
@ -185,5 +194,5 @@ class ResourceSiloControl(resourceSilo: ResourceSilo)
|
|||
/**
|
||||
* Do nothing this turn.
|
||||
*/
|
||||
def SkipPanelAnimation(trigger: Int): Unit = {}
|
||||
def SkipPanelAnimation(trigger: Float): Unit = {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import net.psforever.objects.vital.damage.DamageCalculations
|
|||
import net.psforever.objects.vital.{DamageResistanceModel, StandardAmenityResistance, StandardResolutions, VitalityDefinition}
|
||||
import net.psforever.objects.vital.resistance.ResistanceProfileMutators
|
||||
|
||||
final case class AutoRepairStats(amount: Int, start: Long, repeat: Long, drain: Float)
|
||||
|
||||
abstract class AmenityDefinition(objectId: Int)
|
||||
extends ObjectDefinition(objectId)
|
||||
with ResistanceProfileMutators
|
||||
|
|
@ -15,4 +17,13 @@ abstract class AmenityDefinition(objectId: Int)
|
|||
DamageUsing = DamageCalculations.AgainstVehicle
|
||||
ResistUsing = StandardAmenityResistance
|
||||
Model = StandardResolutions.Amenities
|
||||
|
||||
var autoRepair: Option[AutoRepairStats] = None
|
||||
|
||||
def autoRepair_=(auto: AutoRepairStats): Option[AutoRepairStats] = {
|
||||
autoRepair = Some(auto)
|
||||
autoRepair
|
||||
}
|
||||
|
||||
def hasAutoRepair: Boolean = autoRepair.nonEmpty
|
||||
}
|
||||
|
|
|
|||
|
|
@ -330,9 +330,7 @@ object Building {
|
|||
)(name: String, guid: Int, id: Int, zone: Zone, context: ActorContext): Building = {
|
||||
val obj = new Building(name, guid, id, zone, buildingType, buildingDefinition)
|
||||
obj.Position = location
|
||||
context.spawn(BuildingActor(zone, obj), s"$id-$buildingType-building").toClassic
|
||||
obj.Actor = context.spawn(BuildingActor(zone, obj), s"$id-$buildingType-building").toClassic
|
||||
obj
|
||||
}
|
||||
|
||||
final case class AmenityStateChange(obj: Amenity)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -150,9 +150,9 @@ class WarpGate(name: String, building_guid: Int, map_id: Int, zone: Zone, buildi
|
|||
|
||||
def Owner: PlanetSideServerObject = this
|
||||
|
||||
def NtuCapacitor: Int = Definition.MaxNtuCapacitor
|
||||
def NtuCapacitor: Float = Definition.MaxNtuCapacitor
|
||||
|
||||
def NtuCapacitor_=(value: Int): Int = NtuCapacitor
|
||||
def NtuCapacitor_=(value: Float): Float = NtuCapacitor
|
||||
|
||||
override def Definition: WarpGateDefinition = buildingDefinition
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,8 +96,7 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
|
|||
case ProximityUnit.Action(_, _) =>
|
||||
//reserved
|
||||
|
||||
case msg =>
|
||||
log.warn(s"unexpected message $msg")
|
||||
case _ =>
|
||||
}
|
||||
|
||||
def Use(target: PlanetSideGameObject, zone: String, callback: ActorRef): Unit = {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
package net.psforever.objects.serverobject.terminals
|
||||
|
||||
import akka.actor.{Actor, ActorRef}
|
||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||
import net.psforever.objects.{GlobalDefinitions, SimpleItem}
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||
import net.psforever.objects.serverobject.damage.DamageableAmenity
|
||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableAmenity}
|
||||
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
|
||||
import net.psforever.objects.serverobject.repair.RepairableAmenity
|
||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity}
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
|
||||
/**
|
||||
|
|
@ -19,17 +21,20 @@ class TerminalControl(term: Terminal)
|
|||
with FactionAffinityBehavior.Check
|
||||
with HackableBehavior.GenericHackable
|
||||
with DamageableAmenity
|
||||
with RepairableAmenity {
|
||||
with RepairableAmenity
|
||||
with AmenityAutoRepair {
|
||||
def FactionObject = term
|
||||
def HackableObject = term
|
||||
def DamageableObject = term
|
||||
def RepairableObject = term
|
||||
def AutoRepairObject = term
|
||||
|
||||
def receive: Receive =
|
||||
checkBehavior
|
||||
.orElse(hackableBehavior)
|
||||
.orElse(takesDamage)
|
||||
.orElse(canBeRepairedByNanoDispenser)
|
||||
.orElse(autoRepairBehavior)
|
||||
.orElse {
|
||||
case Terminal.Request(player, msg) =>
|
||||
TerminalControl.Dispatch(sender(), term, Terminal.TerminalMessage(player, msg, term.Request(player, msg)))
|
||||
|
|
@ -46,9 +51,28 @@ class TerminalControl(term: Terminal)
|
|||
)
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
override protected def DamageAwareness(target : Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||
tryAutoRepair()
|
||||
super.DamageAwareness(target, cause, amount)
|
||||
}
|
||||
|
||||
override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile) : Unit = {
|
||||
tryAutoRepair()
|
||||
super.DestructionAwareness(target, cause)
|
||||
}
|
||||
|
||||
override def PerformRepairs(target : Target, amount : Int) : Int = {
|
||||
val newHealth = super.PerformRepairs(target, amount)
|
||||
if(newHealth == target.Definition.MaxHealth) {
|
||||
stopAutoRepair()
|
||||
}
|
||||
newHealth
|
||||
}
|
||||
|
||||
override def toString: String = term.Definition.Name
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,12 @@
|
|||
package net.psforever.objects.serverobject.tube
|
||||
|
||||
import akka.actor.Actor
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.ballistics.ResolvedProjectile
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||
import net.psforever.objects.serverobject.damage.Damageable.Target
|
||||
import net.psforever.objects.serverobject.damage.DamageableAmenity
|
||||
import net.psforever.objects.serverobject.repair.{Repairable, RepairableAmenity}
|
||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, Repairable, RepairableAmenity}
|
||||
import net.psforever.objects.serverobject.structures.Building
|
||||
|
||||
/**
|
||||
|
|
@ -17,31 +18,48 @@ class SpawnTubeControl(tube: SpawnTube)
|
|||
extends Actor
|
||||
with FactionAffinityBehavior.Check
|
||||
with DamageableAmenity
|
||||
with RepairableAmenity {
|
||||
with RepairableAmenity
|
||||
with AmenityAutoRepair {
|
||||
def FactionObject = tube
|
||||
def DamageableObject = tube
|
||||
def RepairableObject = tube
|
||||
def AutoRepairObject = tube
|
||||
|
||||
def receive: Receive =
|
||||
checkBehavior
|
||||
.orElse(takesDamage)
|
||||
.orElse(canBeRepairedByNanoDispenser)
|
||||
.orElse(autoRepairBehavior)
|
||||
.orElse {
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
override protected def DamageAwareness(target : Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||
tryAutoRepair()
|
||||
super.DamageAwareness(target, cause, amount)
|
||||
}
|
||||
|
||||
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
||||
tryAutoRepair()
|
||||
super.DestructionAwareness(target, cause)
|
||||
tube.Owner match {
|
||||
case b: Building => b.Actor ! Building.AmenityStateChange(tube)
|
||||
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
override def PerformRepairs(target : Target, amount : Int) : Int = {
|
||||
val newHealth = super.PerformRepairs(target, amount)
|
||||
if(newHealth == target.Definition.MaxHealth) {
|
||||
stopAutoRepair()
|
||||
}
|
||||
newHealth
|
||||
}
|
||||
|
||||
override def Restoration(obj: Repairable.Target): Unit = {
|
||||
super.Restoration(obj)
|
||||
tube.Owner match {
|
||||
case b: Building => b.Actor ! Building.AmenityStateChange(tube)
|
||||
case b: Building => b.Actor ! BuildingActor.AmenityStateChange(tube)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,10 +8,9 @@ import net.psforever.objects.equipment.{Ammo, JammableMountedWeapons}
|
|||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.mount.MountableBehavior
|
||||
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
|
||||
import net.psforever.objects.serverobject.damage.DamageableWeaponTurret
|
||||
import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTurret}
|
||||
import net.psforever.objects.serverobject.hackable.GenericHackables
|
||||
import net.psforever.objects.serverobject.repair.Repairable.Target
|
||||
import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
|
||||
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableWeaponTurret}
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
|
||||
|
||||
|
|
@ -34,12 +33,14 @@ class FacilityTurretControl(turret: FacilityTurret)
|
|||
with MountableBehavior.Dismount
|
||||
with DamageableWeaponTurret
|
||||
with RepairableWeaponTurret
|
||||
with AmenityAutoRepair
|
||||
with JammableMountedWeapons {
|
||||
def FactionObject = turret
|
||||
def MountableObject = turret
|
||||
def JammableObject = turret
|
||||
def DamageableObject = turret
|
||||
def RepairableObject = turret
|
||||
def AutoRepairObject = turret
|
||||
|
||||
// Used for timing ammo recharge for vanu turrets in caves
|
||||
var weaponAmmoRechargeTimer = Default.Cancellable
|
||||
|
|
@ -47,6 +48,7 @@ class FacilityTurretControl(turret: FacilityTurret)
|
|||
override def postStop(): Unit = {
|
||||
super.postStop()
|
||||
damageableWeaponTurretPostStop()
|
||||
stopAutoRepair()
|
||||
}
|
||||
|
||||
def receive: Receive =
|
||||
|
|
@ -56,6 +58,7 @@ class FacilityTurretControl(turret: FacilityTurret)
|
|||
.orElse(dismountBehavior)
|
||||
.orElse(takesDamage)
|
||||
.orElse(canBeRepairedByNanoDispenser)
|
||||
.orElse(autoRepairBehavior)
|
||||
.orElse {
|
||||
case CommonMessages.Use(player, Some((item: Tool, upgradeValue: Int)))
|
||||
if player.Faction == turret.Faction &&
|
||||
|
|
@ -110,7 +113,13 @@ class FacilityTurretControl(turret: FacilityTurret)
|
|||
case _ => ;
|
||||
}
|
||||
|
||||
override protected def DestructionAwareness(target: Target, cause: ResolvedProjectile): Unit = {
|
||||
override protected def DamageAwareness(target : Damageable.Target, cause : ResolvedProjectile, amount : Any) : Unit = {
|
||||
tryAutoRepair()
|
||||
super.DamageAwareness(target, cause, amount)
|
||||
}
|
||||
|
||||
override protected def DestructionAwareness(target: Damageable.Target, cause: ResolvedProjectile): Unit = {
|
||||
tryAutoRepair()
|
||||
super.DestructionAwareness(target, cause)
|
||||
val zone = target.Zone
|
||||
val zoneId = zone.id
|
||||
|
|
@ -120,7 +129,15 @@ class FacilityTurretControl(turret: FacilityTurret)
|
|||
events ! AvatarServiceMessage(zoneId, AvatarAction.PlanetsideAttributeToAll(tguid, 51, 1))
|
||||
}
|
||||
|
||||
override def Restoration(obj: Target): Unit = {
|
||||
override def PerformRepairs(target : Damageable.Target, amount : Int) : Int = {
|
||||
val newHealth = super.PerformRepairs(target, amount)
|
||||
if(newHealth == target.Definition.MaxHealth) {
|
||||
stopAutoRepair()
|
||||
}
|
||||
newHealth
|
||||
}
|
||||
|
||||
override def Restoration(obj: Damageable.Target): Unit = {
|
||||
super.Restoration(obj)
|
||||
val zone = turret.Zone
|
||||
val zoneId = zone.id
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
|||
//ANTs would charge from 0-100% in roughly 75s on live (https://www.youtube.com/watch?v=veOWToR2nSk&feature=youtu.be&t=1194)
|
||||
val max = obj.Definition.MaxNtuCapacitor - obj.NtuCapacitor
|
||||
target.Actor ! BuildingActor.Ntu(
|
||||
NtuCommand.Request(scala.math.min(obj.Definition.MaxNtuCapacitor / 75, max), context.self)
|
||||
NtuCommand.Request(scala.math.min(obj.Definition.MaxNtuCapacitor / 75f, max), context.self)
|
||||
)
|
||||
case _ =>
|
||||
}
|
||||
|
|
@ -86,7 +86,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
|||
}
|
||||
}
|
||||
|
||||
def ReceiveAndDepositUntilFull(vehicle: Vehicle, amount: Int): Boolean = {
|
||||
def ReceiveAndDepositUntilFull(vehicle: Vehicle, amount: Float): Boolean = {
|
||||
val isNotFull = (vehicle.NtuCapacitor += amount) < vehicle.Definition.MaxNtuCapacitor
|
||||
UpdateNtuUI(vehicle)
|
||||
isNotFull
|
||||
|
|
@ -128,7 +128,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
|||
ActivatePanelsForChargingEvent(ChargeTransferObject)
|
||||
}
|
||||
|
||||
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Int): Any = {
|
||||
def WithdrawAndTransmit(vehicle: Vehicle, maxRequested: Float): Any = {
|
||||
val chargeable = ChargeTransferObject
|
||||
var chargeToDeposit = Math.min(Math.min(chargeable.NtuCapacitor, 100), maxRequested)
|
||||
chargeable.NtuCapacitor -= chargeToDeposit
|
||||
|
|
@ -176,7 +176,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
|||
|
||||
def HandleNtuOffer(sender: ActorRef, src: NtuContainer): Unit = {}
|
||||
|
||||
def HandleNtuRequest(sender: ActorRef, min: Int, max: Int): Unit = {
|
||||
def HandleNtuRequest(sender: ActorRef, min: Float, max: Float): Unit = {
|
||||
if (transferEvent == TransferBehavior.Event.Discharging) {
|
||||
val chargeable = ChargeTransferObject
|
||||
val chargeToDeposit = if (min == 0) {
|
||||
|
|
@ -197,7 +197,7 @@ trait AntTransferBehavior extends TransferBehavior with NtuStorageBehavior {
|
|||
}
|
||||
}
|
||||
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Int): Unit = {
|
||||
def HandleNtuGrant(sender: ActorRef, src: NtuContainer, amount: Float): Unit = {
|
||||
if (transferEvent == TransferBehavior.Event.Charging) {
|
||||
val obj = ChargeTransferObject
|
||||
if (ReceiveAndDepositUntilFull(obj, amount)) {
|
||||
|
|
|
|||
164
src/test/scala/objects/AutoRepairIntegrationTest.scala
Normal file
164
src/test/scala/objects/AutoRepairIntegrationTest.scala
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.Props
|
||||
import akka.testkit.TestProbe
|
||||
import base.FreedContextActorTest
|
||||
import net.psforever.objects.avatar.Avatar
|
||||
import net.psforever.objects.ballistics.{Projectile, ProjectileResolution, ResolvedProjectile, SourceEntry}
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.objects.guid.source.MaxNumberSource
|
||||
import net.psforever.objects.serverobject.resourcesilo.{ResourceSilo, ResourceSiloControl}
|
||||
import net.psforever.objects.serverobject.structures.{AutoRepairStats, Building, StructureType}
|
||||
import net.psforever.objects.serverobject.terminals.{OrderTerminalDefinition, Terminal, TerminalControl}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.vital.damage.DamageProfile
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||
import net.psforever.services.galaxy.GalaxyService
|
||||
import net.psforever.services.{InterstellarClusterService, ServiceManager}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class AutoRepairFacilityIntegrationTest extends FreedContextActorTest {
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairIntegrationTest.terminal_definition)
|
||||
val silo = new ResourceSilo()
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
guid.register(silo, number = 5)
|
||||
|
||||
val building = Building.Structure(StructureType.Facility)(name = "test-building", guid = 6, map_id = 0, zone, context)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
building.Amenities = silo
|
||||
building.Amenities = terminal
|
||||
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
|
||||
silo.NtuCapacitor = 1000
|
||||
silo.Actor = system.actorOf(Props(classOf[ResourceSiloControl], silo), "test-silo")
|
||||
silo.Actor ! "startup"
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"should activate on damage and trade NTU from the facility's resource silo for repairs" in {
|
||||
assert(silo.NtuCapacitor == silo.MaxNtuCapacitor)
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
var i = 0 //safety counter
|
||||
while(terminal.Health < terminal.MaxHealth && i < 100) {
|
||||
i += 1
|
||||
avatarProbe.receiveOne(max = 1000 milliseconds) //health update event
|
||||
}
|
||||
assert(silo.NtuCapacitor < silo.MaxNtuCapacitor)
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AutoRepairTowerIntegrationTest extends FreedContextActorTest {
|
||||
import akka.actor.typed.scaladsl.adapter._
|
||||
system.spawn(InterstellarClusterService(Nil), InterstellarClusterService.InterstellarClusterServiceKey.id)
|
||||
ServiceManager.boot(system) ! ServiceManager.Register(Props[GalaxyService](), "galaxy")
|
||||
expectNoMessage(200 milliseconds)
|
||||
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairIntegrationTest.terminal_definition)
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
|
||||
val building = Building.Structure(StructureType.Tower)(name = "test-building", guid = 6, map_id = 0, zone, context)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
building.Amenities = terminal
|
||||
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"should activate on damage and trade NTU from the tower for repairs" in {
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
var i = 0 //safety counter
|
||||
while(terminal.Health < terminal.MaxHealth && i < 100) {
|
||||
i += 1
|
||||
avatarProbe.receiveOne(max = 1000 milliseconds) //health update event
|
||||
}
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object AutoRepairIntegrationTest {
|
||||
val terminal_definition = new OrderTerminalDefinition(objId = 612) {
|
||||
Name = "order_terminal"
|
||||
MaxHealth = 500
|
||||
Damageable = true
|
||||
Repairable = true
|
||||
autoRepair = AutoRepairStats(1, 500, 500, 1)
|
||||
RepairIfDestroyed = true
|
||||
}
|
||||
}
|
||||
390
src/test/scala/objects/AutoRepairTest.scala
Normal file
390
src/test/scala/objects/AutoRepairTest.scala
Normal file
|
|
@ -0,0 +1,390 @@
|
|||
// Copyright (c) 2020 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.Props
|
||||
import akka.testkit.TestProbe
|
||||
import base.FreedContextActorTest
|
||||
import net.psforever.actors.commands.NtuCommand
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.avatar.Avatar
|
||||
import net.psforever.objects.ballistics.{Projectile, ProjectileResolution, ResolvedProjectile, SourceEntry}
|
||||
import net.psforever.objects.guid.NumberPoolHub
|
||||
import net.psforever.objects.guid.source.MaxNumberSource
|
||||
import net.psforever.objects.serverobject.structures.{AutoRepairStats, Building, StructureType}
|
||||
import net.psforever.objects.serverobject.terminals.{OrderTerminalDefinition, Terminal, TerminalControl}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.objects.vital.damage.DamageProfile
|
||||
import net.psforever.objects.zones.{Zone, ZoneMap}
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class AutoRepairRequestNtuTest extends FreedContextActorTest {
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
|
||||
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
val buildingProbe = new TestProbe(system)
|
||||
building.Actor = buildingProbe.ref
|
||||
building.Zone = zone
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
terminal.Owner = building
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"asks owning building for NTU after damage" in {
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
val buildingMsg = buildingProbe.receiveOne(max = 600 milliseconds)
|
||||
assert(buildingMsg match {
|
||||
case BuildingActor.Ntu(NtuCommand.Request(drain, _)) =>
|
||||
drain == terminal.Definition.autoRepair.get.drain
|
||||
case _ =>
|
||||
false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AutoRepairRequestNtuRepeatTest extends FreedContextActorTest {
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
|
||||
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
val buildingProbe = new TestProbe(system)
|
||||
building.Actor = buildingProbe.ref
|
||||
building.Zone = zone
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
terminal.Owner = building
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"repeatedly asks owning building for NTU after damage" in {
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
(0 to 3).foreach { _ =>
|
||||
val buildingMsg = buildingProbe.receiveOne(max = 1000 milliseconds)
|
||||
assert(buildingMsg match {
|
||||
case BuildingActor.Ntu(NtuCommand.Request(drain, _)) =>
|
||||
drain == terminal.Definition.autoRepair.get.drain
|
||||
case _ =>
|
||||
false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AutoRepairNoRequestNtuTest extends FreedContextActorTest {
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
|
||||
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
val buildingProbe = new TestProbe(system)
|
||||
building.Actor = buildingProbe.ref
|
||||
building.Zone = zone
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
terminal.Owner = building
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"not ask for NTU after damage if it expects no NTU" in {
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! BuildingActor.NtuDepleted()
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
buildingProbe.expectNoMessage(max = 2000 milliseconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AutoRepairRestoreRequestNtuTest extends FreedContextActorTest {
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
|
||||
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
val buildingProbe = new TestProbe(system)
|
||||
building.Actor = buildingProbe.ref
|
||||
building.Zone = zone
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
terminal.Owner = building
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"ask for NTU after damage if its expectation of NTU is restored" in {
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! BuildingActor.NtuDepleted()
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
buildingProbe.expectNoMessage(max = 2000 milliseconds)
|
||||
|
||||
terminal.Actor ! BuildingActor.SuppliedWithNtu()
|
||||
val buildingMsg = buildingProbe.receiveOne(max = 600 milliseconds)
|
||||
assert(buildingMsg match {
|
||||
case BuildingActor.Ntu(NtuCommand.Request(drain, _)) =>
|
||||
drain == terminal.Definition.autoRepair.get.drain
|
||||
case _ =>
|
||||
false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AutoRepairRepairWithNtuTest extends FreedContextActorTest {
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
|
||||
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
val buildingProbe = new TestProbe(system)
|
||||
building.Actor = buildingProbe.ref
|
||||
building.Zone = zone
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
terminal.Owner = building
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"repair some of the damage when it receives NTU" in {
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! BuildingActor.NtuDepleted() //don't worry about requests
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
val reducedHealth = terminal.Health
|
||||
buildingProbe.expectNoMessage(max = 2000 milliseconds)
|
||||
terminal.Actor ! NtuCommand.Grant(null, 1)
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health > reducedHealth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AutoRepairRepairWithNtuUntilDoneTest extends FreedContextActorTest {
|
||||
val player = Player(Avatar(0, "TestCharacter", PlanetSideEmpire.TR, CharacterGender.Male, 0, CharacterVoice.Mute))
|
||||
player.Spawn()
|
||||
val weapon = new Tool(GlobalDefinitions.suppressor)
|
||||
val terminal = new Terminal(AutoRepairTest.terminal_definition)
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(max = 10))
|
||||
val zone = new Zone("test", new ZoneMap("test"), 0) {
|
||||
override def SetupNumberPools() = {}
|
||||
GUID(guid)
|
||||
}
|
||||
val avatarProbe = new TestProbe(system)
|
||||
zone.AvatarEvents = avatarProbe.ref
|
||||
|
||||
guid.register(player, number = 1)
|
||||
guid.register(weapon, number = 2)
|
||||
guid.register(weapon.AmmoSlot.Box, number = 3)
|
||||
guid.register(terminal, number = 4)
|
||||
|
||||
val building = Building("test-building", 1, 1, zone, StructureType.Facility)
|
||||
building.Invalidate()
|
||||
guid.register(building, number = 6)
|
||||
val buildingProbe = new TestProbe(system)
|
||||
building.Actor = buildingProbe.ref
|
||||
building.Zone = zone
|
||||
terminal.Actor = context.actorOf(Props(classOf[TerminalControl], terminal), name = "test-terminal")
|
||||
terminal.Owner = building
|
||||
|
||||
val wep_fmode = weapon.FireMode
|
||||
val wep_prof = wep_fmode.Add
|
||||
val proj = weapon.Projectile
|
||||
val proj_prof = proj.asInstanceOf[DamageProfile]
|
||||
val projectile = Projectile(proj, weapon.Definition, wep_fmode, player, Vector3(2, 0, 0), Vector3.Zero)
|
||||
val resolved = ResolvedProjectile(
|
||||
ProjectileResolution.Hit,
|
||||
projectile,
|
||||
SourceEntry(terminal),
|
||||
terminal.DamageModel,
|
||||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
|
||||
"AutoRepair" should {
|
||||
"ask for NTU after damage and repair some of the damage when it receives NTU, until fully-repaired" in {
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
terminal.Actor ! Vitality.Damage(applyDamageTo)
|
||||
|
||||
avatarProbe.receiveOne(max = 200 milliseconds) //health update event
|
||||
assert(terminal.Health < terminal.MaxHealth)
|
||||
var i = 0
|
||||
while(terminal.Health < terminal.MaxHealth && i < 100) {
|
||||
i += 1 //safety counter
|
||||
val buildingMsg = buildingProbe.receiveOne(max = 1000 milliseconds)
|
||||
buildingMsg match {
|
||||
case BuildingActor.Ntu(NtuCommand.Request(_, _)) =>
|
||||
terminal.Actor ! NtuCommand.Grant(null, 1)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
assert(terminal.Health == terminal.MaxHealth)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object AutoRepairTest {
|
||||
val terminal_definition = new OrderTerminalDefinition(objId = 612) {
|
||||
Name = "order_terminal"
|
||||
MaxHealth = 500
|
||||
Damageable = true
|
||||
Repairable = true
|
||||
autoRepair = AutoRepairStats(1, 500, 500, 1)
|
||||
RepairIfDestroyed = true
|
||||
}
|
||||
}
|
||||
|
|
@ -25,22 +25,22 @@ class DoorTest extends Specification {
|
|||
|
||||
"starts as closed (false)" in {
|
||||
val door = Door(GlobalDefinitions.door)
|
||||
door.Open mustEqual None
|
||||
door.Open.isEmpty mustEqual true
|
||||
door.isOpen mustEqual false
|
||||
}
|
||||
|
||||
"be opened and closed (1; manual)" in {
|
||||
val door = Door(GlobalDefinitions.door)
|
||||
door.isOpen mustEqual false
|
||||
door.Open mustEqual None
|
||||
door.Open.isEmpty mustEqual true
|
||||
|
||||
door.Open = Some(player)
|
||||
door.isOpen mustEqual true
|
||||
door.Open mustEqual Some(player)
|
||||
door.Open.contains(player) mustEqual true
|
||||
|
||||
door.Open = None
|
||||
door.isOpen mustEqual false
|
||||
door.Open mustEqual None
|
||||
door.Open.isEmpty mustEqual true
|
||||
}
|
||||
|
||||
"be opened and closed (2; toggle)" in {
|
||||
|
|
@ -58,11 +58,11 @@ class DoorTest extends Specification {
|
|||
364
|
||||
)
|
||||
val door = Door(GlobalDefinitions.door)
|
||||
door.Open mustEqual None
|
||||
door.Open.isEmpty mustEqual true
|
||||
door.Use(player, msg)
|
||||
door.Open mustEqual Some(player)
|
||||
door.Open.contains(player) mustEqual true
|
||||
door.Use(player, msg)
|
||||
door.Open mustEqual None
|
||||
door.Open.isEmpty mustEqual true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -115,8 +115,7 @@ class DoorControl3Test extends ActorTest {
|
|||
assert(door.Open.isEmpty)
|
||||
|
||||
door.Actor ! "trash"
|
||||
val reply = receiveOne(Duration.create(500, "ms"))
|
||||
assert(reply.isInstanceOf[Door.NoEvent])
|
||||
expectNoMessage(Duration.create(500, "ms"))
|
||||
assert(door.Open.isEmpty)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ package objects
|
|||
import akka.actor.{ActorRef, Props}
|
||||
import akka.testkit.TestProbe
|
||||
import base.ActorTest
|
||||
import net.psforever.actors.zone.BuildingActor
|
||||
import net.psforever.objects.avatar.Avatar
|
||||
import net.psforever.objects.ballistics._
|
||||
import net.psforever.objects.{GlobalDefinitions, Player, Tool}
|
||||
|
|
@ -206,7 +207,7 @@ class GeneratorControlCriticalTest extends ActorTest {
|
|||
)
|
||||
assert(
|
||||
msg_building match {
|
||||
case Building.AmenityStateChange(o) => o eq gen
|
||||
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
|
|
@ -268,6 +269,7 @@ class GeneratorControlDestroyedTest extends ActorTest {
|
|||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
gen.Actor ! BuildingActor.NtuDepleted() //no auto-repair
|
||||
expectNoMessage(200 milliseconds)
|
||||
//we're not testing that the math is correct
|
||||
|
||||
|
|
@ -293,12 +295,11 @@ class GeneratorControlDestroyedTest extends ActorTest {
|
|||
assert(gen.Condition == PlanetSideGeneratorState.Normal)
|
||||
|
||||
avatarProbe.expectNoMessage(9 seconds)
|
||||
buildingProbe.expectNoMessage(50 milliseconds) //no prior messages
|
||||
val msg_avatar2 = avatarProbe.receiveN(3, 1000 milliseconds) //see DamageableEntity test file
|
||||
val msg_building = buildingProbe.receiveOne(200 milliseconds)
|
||||
assert(
|
||||
msg_building match {
|
||||
case Building.AmenityStateChange(o) => o eq gen
|
||||
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
|
|
@ -399,6 +400,7 @@ class GeneratorControlKillsTest extends ActorTest {
|
|||
Vector3(1, 0, 0)
|
||||
)
|
||||
val applyDamageTo = resolved.damage_model.Calculate(resolved)
|
||||
gen.Actor ! BuildingActor.NtuDepleted() //no auto-repair
|
||||
expectNoMessage(200 milliseconds)
|
||||
//we're not testing that the math is correct
|
||||
|
||||
|
|
@ -438,7 +440,7 @@ class GeneratorControlKillsTest extends ActorTest {
|
|||
player2Probe.expectNoMessage(200 milliseconds)
|
||||
assert(
|
||||
msg_building match {
|
||||
case Building.AmenityStateChange(o) => o eq gen
|
||||
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
|
|
@ -840,7 +842,7 @@ class GeneratorControlRepairPastRestorePoint extends ActorTest {
|
|||
)
|
||||
assert(
|
||||
msg_building match {
|
||||
case Building.AmenityStateChange(o) => o eq gen
|
||||
case BuildingActor.AmenityStateChange(o) => o eq gen
|
||||
case _ => false
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -87,12 +87,63 @@ class ResourceSiloControlStartupTest extends ActorTest {
|
|||
"Resource silo" should {
|
||||
"startup properly" in {
|
||||
expectNoMessage(500 milliseconds)
|
||||
system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo") ! "startup"
|
||||
expectNoMessage(1 seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlStartupMessageNoneTest extends ActorTest {
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||
val buildingEvents = TestProbe("test-building-events")
|
||||
obj.Owner =
|
||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||
Actor = buildingEvents.ref
|
||||
}
|
||||
obj.Owner.GUID = PlanetSideGUID(6)
|
||||
|
||||
"Resource silo" should {
|
||||
"report if it has no NTU on startup" in {
|
||||
assert(obj.NtuCapacitor == 0)
|
||||
obj.Actor ! "startup"
|
||||
val ownerMsg = buildingEvents.receiveOne(200 milliseconds)
|
||||
assert(ownerMsg match {
|
||||
case BuildingActor.NtuDepleted() => true
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlStartupMessageSomeTest extends ActorTest {
|
||||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||
val buildingEvents = TestProbe("test-building-events")
|
||||
obj.Owner =
|
||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||
Actor = buildingEvents.ref
|
||||
}
|
||||
obj.Owner.GUID = PlanetSideGUID(6)
|
||||
|
||||
"Resource silo" should {
|
||||
"report if it has any NTU on startup" in {
|
||||
obj.NtuCapacitor = 1
|
||||
assert(obj.NtuCapacitor == 1)
|
||||
obj.Actor ! "startup"
|
||||
val ownerMsg = buildingEvents.receiveOne(200 milliseconds)
|
||||
assert(ownerMsg match {
|
||||
case BuildingActor.SuppliedWithNtu() => true
|
||||
case _ => false
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ResourceSiloControlUseTest extends ActorTest {
|
||||
val guid = new NumberPoolHub(new MaxNumberSource(10))
|
||||
val map = new ZoneMap("test")
|
||||
|
|
@ -109,6 +160,7 @@ class ResourceSiloControlUseTest extends ActorTest {
|
|||
StructureType.Building,
|
||||
GlobalDefinitions.building
|
||||
) //guid=1
|
||||
building.Actor = TestProbe("building-actor").ref
|
||||
|
||||
val obj = ResourceSilo() //guid=2
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
|
|
@ -151,21 +203,23 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
|
|||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||
obj.Owner =
|
||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building) {
|
||||
Actor = TestProbe("building-events").ref
|
||||
}
|
||||
obj.Owner.GUID = PlanetSideGUID(6)
|
||||
|
||||
val zoneEvents = TestProbe("zone-events")
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
obj.Actor ! "startup"
|
||||
|
||||
"Resource silo" should {
|
||||
"announce high ntu" in {
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
assert(obj.LowNtuWarningOn)
|
||||
obj.Actor ! ResourceSilo.LowNtuWarning(false)
|
||||
|
||||
val reply = zoneEvents.receiveOne(500 milliseconds)
|
||||
assert(!obj.LowNtuWarningOn)
|
||||
val reply = zoneEvents.receiveOne(5000 milliseconds)
|
||||
assert(reply.isInstanceOf[AvatarServiceMessage])
|
||||
assert(reply.asInstanceOf[AvatarServiceMessage].forChannel == "nowhere")
|
||||
assert(reply.asInstanceOf[AvatarServiceMessage].actionMessage.isInstanceOf[AvatarAction.PlanetsideAttribute])
|
||||
|
|
@ -190,6 +244,7 @@ class ResourceSiloControlNtuWarningTest extends ActorTest {
|
|||
.asInstanceOf[AvatarAction.PlanetsideAttribute]
|
||||
.attribute_value == 0
|
||||
)
|
||||
assert(!obj.LowNtuWarningOn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -198,7 +253,6 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
|||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||
val bldg =
|
||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||
|
|
@ -206,12 +260,13 @@ class ResourceSiloControlUpdate1Test extends ActorTest {
|
|||
obj.Owner = bldg
|
||||
val zoneEvents = TestProbe("zone-events")
|
||||
val buildingEvents = TestProbe("building-events")
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
bldg.Actor = buildingEvents.ref
|
||||
obj.Actor ! "startup"
|
||||
|
||||
"Resource silo" should {
|
||||
"update the charge level and capacitor display (report high ntu, power restored)" in {
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
bldg.Actor = buildingEvents.ref
|
||||
|
||||
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
|
||||
assert(obj.NtuCapacitor == 0)
|
||||
assert(obj.CapacitorDisplay == 0)
|
||||
assert(obj.LowNtuWarningOn)
|
||||
|
|
@ -247,7 +302,6 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
|||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||
val bldg =
|
||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||
|
|
@ -255,12 +309,13 @@ class ResourceSiloControlUpdate2Test extends ActorTest {
|
|||
obj.Owner = bldg
|
||||
val zoneEvents = TestProbe("zone-events")
|
||||
val buildingEvents = TestProbe("building-events")
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
bldg.Actor = buildingEvents.ref
|
||||
obj.Actor ! "startup"
|
||||
|
||||
"Resource silo" should {
|
||||
"update the charge level and capacitor display (report good ntu)" in {
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
bldg.Actor = buildingEvents.ref
|
||||
|
||||
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
|
||||
obj.NtuCapacitor = 100
|
||||
obj.LowNtuWarningOn = true
|
||||
assert(obj.NtuCapacitor == 100)
|
||||
|
|
@ -333,7 +388,6 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
|||
val obj = ResourceSilo()
|
||||
obj.GUID = PlanetSideGUID(1)
|
||||
obj.Actor = system.actorOf(Props(classOf[ResourceSiloControl], obj), "test-silo")
|
||||
obj.Actor ! "startup"
|
||||
val zone = new Zone("nowhere", new ZoneMap("nowhere-map"), 0)
|
||||
val bldg =
|
||||
new Building("Building", building_guid = 6, map_id = 0, zone, StructureType.Building, GlobalDefinitions.building)
|
||||
|
|
@ -341,12 +395,13 @@ class ResourceSiloControlNoUpdateTest extends ActorTest {
|
|||
obj.Owner = bldg
|
||||
val zoneEvents = TestProbe("zone-events")
|
||||
val buildingEvents = TestProbe("building-events")
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
bldg.Actor = buildingEvents.ref
|
||||
obj.Actor ! "startup"
|
||||
|
||||
"Resource silo" should {
|
||||
"update, but not sufficiently to change the capacitor display" in {
|
||||
zone.AvatarEvents = zoneEvents.ref
|
||||
bldg.Actor = buildingEvents.ref
|
||||
|
||||
buildingEvents.receiveOne(500 milliseconds) //message caused by "startup"
|
||||
obj.NtuCapacitor = 250
|
||||
obj.LowNtuWarningOn = false
|
||||
assert(obj.NtuCapacitor == 250)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import scodec.Attempt.{Failure, Successful}
|
|||
import scodec.bits._
|
||||
|
||||
import scala.concurrent.duration.{DurationInt, FiniteDuration}
|
||||
import scala.util.control.Breaks._
|
||||
|
||||
object Client {
|
||||
Security.addProvider(new BouncyCastleProvider)
|
||||
|
|
@ -153,6 +152,7 @@ class Client(username: String, password: String) {
|
|||
socket.send(new DatagramPacket(payload, payload.length, host))
|
||||
case (None, Some(ref)) =>
|
||||
// ref ! Udp.Received(ByteString(payload), new InetSocketAddress(socket.getInetAddress, socket.getPort))
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@ import scala.collection.parallel.CollectionConverters._
|
|||
import scala.io.{Codec, Source}
|
||||
import scala.sys.process._
|
||||
import scala.util.Using
|
||||
import scala.util.control.Breaks._
|
||||
|
||||
case class Config(
|
||||
outDir: String = System.getProperty("user.dir"),
|
||||
|
|
|
|||
Loading…
Reference in a new issue