Merge pull request #676 from Mazo/capture-terminal-refactor

Capture terminal logic refactor
This commit is contained in:
Fate-JH 2021-02-27 07:29:59 -05:00 committed by GitHub
commit ab354e49df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
32 changed files with 363 additions and 259 deletions

View file

@ -6,8 +6,8 @@ import akka.actor.typed.scaladsl.adapter._
import akka.actor.{Actor, ActorRef, Cancellable, MDCContextAware}
import akka.pattern.ask
import akka.util.Timeout
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeUnit
import net.psforever.actors.net.MiddlewareActor
import net.psforever.services.ServiceManager.Lookup
import net.psforever.objects.locker.LockerContainer
@ -37,7 +37,6 @@ import net.psforever.objects.serverobject.deploy.Deployment
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.generator.Generator
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.mblocker.Locker
import net.psforever.objects.serverobject.mount.Mountable
@ -45,6 +44,8 @@ import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
import net.psforever.objects.serverobject.terminals._
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminals}
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.{FacilityTurret, WeaponTurret}
import net.psforever.objects.serverobject.zipline.ZipLinePath
@ -57,6 +58,7 @@ import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.projectile.ProjectileReason
import net.psforever.objects.zones.{Zone, ZoneHotSpotProjector, Zoning}
import net.psforever.packet._
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.game.{HotSpotInfo => PacketHotSpotInfo, _}
import net.psforever.packet.game.objectcreate._
import net.psforever.services.ServiceManager.LookupResult
@ -64,7 +66,7 @@ import net.psforever.services.account.{AccountPersistenceService, PlayerToken, R
import net.psforever.services.avatar.{AvatarAction, AvatarResponse, AvatarServiceMessage, AvatarServiceResponse}
import net.psforever.services.chat.ChatService
import net.psforever.services.galaxy.{GalaxyAction, GalaxyResponse, GalaxyServiceMessage, GalaxyServiceResponse}
import net.psforever.services.local.support.RouterTelepadActivation
import net.psforever.services.local.support.{HackCaptureActor, RouterTelepadActivation}
import net.psforever.services.local.{LocalAction, LocalResponse, LocalServiceMessage, LocalServiceResponse}
import net.psforever.services.properties.PropertyOverrideManager
import net.psforever.services.support.SupportActor
@ -2296,7 +2298,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
DeconstructDeployable(obj, guid, pos, obj.Orientation, 2)
}
case LocalResponse.HackClear(target_guid, unk1, unk2) =>
case LocalResponse.SendHackMessageHackCleared(target_guid, unk1, unk2) =>
log.trace(s"Clearing hack for ${target_guid}")
// Reset hack state for all players
sendResponse(HackMessage(0, target_guid, guid, 0, unk1, HackState.HackCleared, unk2))
@ -2304,8 +2306,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case LocalResponse.HackObject(target_guid, unk1, unk2) =>
HackObject(target_guid, unk1, unk2)
case LocalResponse.HackCaptureTerminal(target_guid, unk1, unk2, isResecured) =>
HackCaptureTerminal(target_guid, unk1, unk2, isResecured)
case LocalResponse.SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value) =>
SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value)
case LocalResponse.ObjectDelete(object_guid, unk) =>
if (tplayer_guid != guid) {
@ -2657,6 +2659,7 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case VehicleResponse.KickPassenger(seat_num, wasKickedByDriver, vehicle_guid) =>
// seat_num seems to be correct if passenger is kicked manually by driver, but always seems to return 4 if user is kicked by seat permissions
sendResponse(DismountVehicleMsg(guid, BailType.Kicked, wasKickedByDriver))
player.VehicleSeated = None
if (tplayer_guid == guid) {
continent.GUID(vehicle_guid) match {
case Some(obj: Vehicle) =>
@ -6698,7 +6701,10 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
case obj: Hackable if obj.HackedBy.nonEmpty =>
amenity.Definition match {
case GlobalDefinitions.capture_terminal =>
HackCaptureTerminal(amenity.GUID, 0L, 0L, false)
SendPlanetsideAttributeMessage(
amenity.GUID,
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false))
case _ =>
HackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object
}
@ -6742,51 +6748,13 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
}
/**
* na
* @param target_guid na
* @param unk1 na
* @param unk2 na
* @param isResecured na
* Send a PlanetsideAttributeMessage packet to the client
* @param target_guid The target of the attribute
* @param attribute_number The attribute number
* @param attribute_value The attribute value
*/
def HackCaptureTerminal(target_guid: PlanetSideGUID, unk1: Long, unk2: Long, isResecured: Boolean): Unit = {
var value = 0L
if (isResecured) {
value = 17039360L
sendResponse(PlanetsideAttributeMessage(target_guid, 20, value))
} else {
continent.GUID(target_guid) match {
case Some(capture_terminal: Amenity with Hackable) =>
capture_terminal.HackedBy match {
case Some(Hackable.HackInfo(_, _, hfaction, _, start, length)) =>
val hack_time_remaining_ms =
TimeUnit.MILLISECONDS.convert(math.max(0, start + length - System.nanoTime), TimeUnit.NANOSECONDS)
val deciseconds_remaining = (hack_time_remaining_ms / 100)
//See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
val start_num = hfaction match {
case PlanetSideEmpire.TR => 65536L
case PlanetSideEmpire.NC => 131072L
case PlanetSideEmpire.VS => 196608L
}
value = start_num + deciseconds_remaining
sendResponse(PlanetsideAttributeMessage(target_guid, 20, value))
GetMountableAndSeat(None, player, continent) match {
case (Some(mountable: Amenity), Some(seat)) if mountable.Owner.GUID == capture_terminal.Owner.GUID =>
mountable.Seats(seat).Occupant = None
player.VehicleSeated = None
continent.VehicleEvents ! VehicleServiceMessage(
continent.id,
VehicleAction.KickPassenger(player.GUID, seat, true, mountable.GUID)
)
case _ => ;
}
case _ => log.warn("HackCaptureTerminal: hack state monitor not defined")
}
case _ =>
log.warn(
s"HackCaptureTerminal: couldn't find capture terminal with GUID ${target_guid} in zone ${continent.id}"
)
}
}
def SendPlanetsideAttributeMessage(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long): Unit = {
sendResponse(PlanetsideAttributeMessage(target_guid, attribute_number, attribute_value))
}
/**

View file

@ -1,5 +1,6 @@
package net.psforever.actors.zone
import akka.actor.Actor
import akka.actor.typed.receptionist.Receptionist
import akka.actor.typed.scaladsl.{ActorContext, Behaviors, StashBuffer}
import akka.actor.typed.{ActorRef, Behavior, SupervisorStrategy}
@ -8,11 +9,14 @@ import net.psforever.actors.commands.NtuCommand
import net.psforever.objects.NtuContainer
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.structures.{Amenity, Building, StructureType, WarpGate}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAware, CaptureTerminalAwareBehavior}
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretControl}
import net.psforever.objects.zones.Zone
import net.psforever.persistence
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGeneratorState}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState}
import net.psforever.util.Database._
import net.psforever.services.galaxy.{GalaxyAction, GalaxyServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
@ -201,6 +205,25 @@ class BuildingActor(
}
Behaviors.same
case AmenityStateChange(terminal: CaptureTerminal, data) =>
// Notify amenities that listen for CC hack state changes, e.g. wall turrets to dismount seated players
building.Amenities.filter(x => x.isInstanceOf[CaptureTerminalAware]).foreach(amenity => {
data match {
case Some(isResecured: Boolean) => amenity.Actor ! CaptureTerminalAwareBehavior.TerminalStatusChanged(terminal, isResecured)
case _ => log.warn("CaptureTerminal AmenityStateChange was received with no attached data.")
}
})
// When a CC is hacked (or resecured) all currently hacked amenities for the base should return to their default unhacked state
building.HackableAmenities.foreach(amenity => {
if (amenity.HackedBy.isDefined) {
zone.LocalEvents ! LocalServiceMessage(amenity.Zone.id,LocalAction.ClearTemporaryHack(PlanetSideGUID(0), amenity))
}
})
// No map update needed - will be sent by `HackCaptureActor` when required
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

View file

@ -12,7 +12,6 @@ import net.psforever.objects.inventory.InventoryTile
import net.psforever.objects.serverobject.aura.Aura
import net.psforever.objects.serverobject.doors.DoorDefinition
import net.psforever.objects.serverobject.generator.GeneratorDefinition
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMechDefinition
import net.psforever.objects.serverobject.locks.IFFLockDefinition
import net.psforever.objects.serverobject.mblocker.LockerDefinition
import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition
@ -21,6 +20,8 @@ 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.{AutoRepairStats, BuildingDefinition, WarpGateDefinition}
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalDefinition
import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalDefinition, ImplantTerminalMechDefinition}
import net.psforever.objects.serverobject.turret.{FacilityTurretDefinition, TurretUpgrade}
import net.psforever.objects.vehicles.{DestroyedVehicle, InternalTelepadDefinition, SeatArmorRestriction, UtilityType}
import net.psforever.objects.vital.base.DamageType

View file

@ -521,7 +521,7 @@ class Player(var avatar: Avatar)
} else {
""
}
s"${avatar.name}$guid ${Health}/${MaxHealth} ${Armor}/${MaxArmor}"
s"${avatar.name}$guid ${avatar.faction} H: ${Health}/${MaxHealth} A: ${Armor}/${MaxArmor}"
}
}

View file

@ -24,7 +24,7 @@ class PainboxControl(painbox: Painbox) extends PoweredAmenityControl {
if (painbox.Owner.Continent.matches("c[0-9]")) {
//are we in a safe zone?
// todo: handle non-radius painboxes in caverns properly
log.warn(s"Skipping initialization of ${painbox.GUID} on ${painbox.Owner.Continent} - ${painbox.Position}")
log.info(s"Skipping initialization of ${painbox.GUID} on ${painbox.Owner.Continent} - ${painbox.Position}")
disabled = true
} else {
if (painbox.Definition.HasNearestDoorDependency) {

View file

@ -2,7 +2,6 @@
package net.psforever.objects.serverobject.structures
import java.util.concurrent.TimeUnit
import akka.actor.ActorContext
import net.psforever.actors.zone.BuildingActor
import net.psforever.objects.{GlobalDefinitions, NtuContainer, Player}
@ -11,13 +10,13 @@ import net.psforever.objects.serverobject.generator.Generator
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.painbox.Painbox
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.terminals.CaptureTerminal
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.BuildingInfoUpdateMessage
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, PlanetSideGeneratorState, Vector3}
import scalax.collection.{Graph, GraphEdge}
import akka.actor.typed.scaladsl.adapter._
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
class Building(
private val name: String,
@ -123,6 +122,10 @@ class Building(
}
}
def HackableAmenities: List[Amenity with Hackable] = {
Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable])
}
def CaptureTerminalIsHacked: Boolean = {
CaptureTerminal match {
case Some(obj: CaptureTerminal) =>

View file

@ -1,45 +0,0 @@
// Copyright (c) 2020 PSForever
package net.psforever.objects.serverobject.terminals
import net.psforever.objects.Player
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import scala.util.{Failure, Success}
object CaptureTerminals {
private val log = org.log4s.getLogger("CaptureTerminals")
/**
* The process of hacking an object is completed.
* Pass the message onto the hackable object and onto the local events system.
* @param target the `Hackable` object that has been hacked
* @param unk na;
* used by `HackMessage` as `unk5`
* @see `HackMessage`
*/
//TODO add params here depending on which params in HackMessage are important
def FinishHackingCaptureConsole(target: CaptureTerminal, user: Player, unk: Long)(): Unit = {
import akka.pattern.ask
import scala.concurrent.duration._
log.info(s"Hacked a $target")
// Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly
import scala.concurrent.ExecutionContext.Implicits.global
val tplayer = user
ask(target.Actor, CommonMessages.Hack(tplayer, target))(1 second).mapTo[Boolean].onComplete {
case Success(_) =>
val zone = target.Zone
val zoneId = zone.id
val pguid = tplayer.GUID
zone.LocalEvents ! LocalServiceMessage(
zoneId,
LocalAction.TriggerSound(pguid, target.HackSound, tplayer.Position, 30, 0.49803925f)
)
zone.LocalEvents ! LocalServiceMessage(
zoneId,
LocalAction.HackCaptureTerminal(pguid, zone, target, unk, 8L, tplayer.Faction == target.Faction)
)
case Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
}
}
}

View file

@ -1,4 +1,4 @@
package net.psforever.objects.serverobject.terminals
package net.psforever.objects.serverobject.terminals.capture
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.structures.Amenity
@ -9,6 +9,15 @@ class CaptureTerminal(private val idef: CaptureTerminalDefinition) extends Ameni
def Definition: CaptureTerminalDefinition = idef
HackDuration = Array(60, 40, 20, 15)
HackSound = TriggeredSound.HackTerminal
override def toString: String = {
val guid = if (HasGUID) {
s" ${Continent}-${GUID.guid}"
} else {
""
}
s"${this.getClass.getName}: $guid ($Faction)"
}
}
object CaptureTerminal {

View file

@ -0,0 +1,10 @@
package net.psforever.objects.serverobject.terminals.capture
/**
* A trait to mark an Amenity as being aware that a capture terminal exists on the parent object
* and that it is interested in status updates about that capture terminal, for example mountables to kick players out once the CC is hacked
* @see CaptureTerminalAwareBehavior
*/
trait CaptureTerminalAware {
}

View file

@ -0,0 +1,37 @@
package net.psforever.objects.serverobject.terminals.capture
import akka.actor.Actor.Receive
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
/**
* The behaviours corresponding to an Amenity that is marked as being CaptureTerminalAware
* @see CaptureTerminalAware
*/
trait CaptureTerminalAwareBehavior {
def CaptureTerminalAwareObject : Amenity with CaptureTerminalAware
val captureTerminalAwareBehaviour: Receive = {
case CaptureTerminalAwareBehavior.TerminalStatusChanged(terminal, isResecured) =>
isResecured match {
case true => ; // CC is resecured
case false => // CC is hacked
// Remove seated occupants for mountables
if (CaptureTerminalAwareObject.isInstanceOf[Mountable]) {
CaptureTerminalAwareObject.asInstanceOf[Mountable].Seats.filter(x => x._2.isOccupied).foreach(x => {
val (seat_num, seat) = x
CaptureTerminalAwareObject.Zone.VehicleEvents ! VehicleServiceMessage(
CaptureTerminalAwareObject.Zone.id,
VehicleAction.KickPassenger(seat.Occupant.get.GUID, seat_num, true, CaptureTerminalAwareObject.GUID))
seat.Occupant = None
})
}
}
}
}
object CaptureTerminalAwareBehavior {
final case class TerminalStatusChanged(terminal: CaptureTerminal, isResecured: Boolean)
}

View file

@ -1,11 +1,11 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.terminals
package net.psforever.objects.serverobject.terminals.capture
import akka.actor.Actor
import net.psforever.objects.{GlobalDefinitions, SimpleItem}
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
import net.psforever.objects.{GlobalDefinitions, SimpleItem}
class CaptureTerminalControl(terminal: CaptureTerminal)
extends Actor

View file

@ -1,4 +1,4 @@
package net.psforever.objects.serverobject.terminals
package net.psforever.objects.serverobject.terminals.capture
import net.psforever.objects.serverobject.structures.AmenityDefinition

View file

@ -0,0 +1,65 @@
package net.psforever.objects.serverobject.terminals.capture
import net.psforever.actors.zone.BuildingActor
import net.psforever.objects.Player
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.packet.game.PlanetsideAttributeEnum
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import net.psforever.types.PlanetSideEmpire
import java.util.concurrent.TimeUnit
import scala.util.{Failure, Success}
object CaptureTerminals {
private val log = org.log4s.getLogger("CaptureTerminals")
/**
* The process of hacking an object is completed.
* Pass the message onto the hackable object and onto the local events system.
* @param target the `Hackable` object that has been hacked
* @param hackingPlayer The player that hacked the control console
* @param unk na;
* used by `HackMessage` as `unk5`
* @see `HackMessage`
*/
//TODO add params here depending on which params in HackMessage are important
def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Long)(): Unit = {
import akka.pattern.ask
import scala.concurrent.duration._
log.info(s"${hackingPlayer.toString} Hacked a ${target.toString}")
// Wait for the target actor to set the HackedBy property
import scala.concurrent.ExecutionContext.Implicits.global
ask(target.Actor, CommonMessages.Hack(hackingPlayer, target))(1 second).mapTo[Boolean].onComplete {
case Success(_) =>
target.Zone.LocalEvents ! LocalServiceMessage(
target.Zone.id,
LocalAction.TriggerSound(hackingPlayer.GUID, target.HackSound, hackingPlayer.Position, 30, 0.49803925f)
)
val isResecured = hackingPlayer.Faction == target.Faction
if (isResecured) {
// Resecure the CC
target.Zone.LocalEvents ! LocalServiceMessage(
target.Zone.id,
LocalAction.ResecureCaptureTerminal(
target
)
)
} else {
// Start the CC hack timer
target.Zone.LocalEvents ! LocalServiceMessage(
target.Zone.id,
LocalAction.StartCaptureTerminalHack(
target
)
)
}
case Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
}
}
}

View file

@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.terminals
package net.psforever.objects.serverobject.terminals.implant
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.definition.ImplantDefinition

View file

@ -1,10 +1,11 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.implantmech
package net.psforever.objects.serverobject.terminals.implant
import net.psforever.objects.Player
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
import net.psforever.objects.vehicles.Seat
import net.psforever.packet.game.TriggeredSound
import net.psforever.types.Vector3
@ -17,7 +18,8 @@ import net.psforever.types.Vector3
class ImplantTerminalMech(private val idef: ImplantTerminalMechDefinition)
extends Amenity
with Mountable
with Hackable {
with Hackable
with CaptureTerminalAware {
private val seats: Map[Int, Seat] = Map(0 -> new Seat(idef.Seats(0)))
HackSound = TriggeredSound.HackTerminal

View file

@ -1,16 +1,17 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.implantmech
package net.psforever.objects.serverobject.terminals.implant
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
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.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableEntity}
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
/**
@ -25,13 +26,15 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
with HackableBehavior.GenericHackable
with DamageableEntity
with RepairableEntity
with AmenityAutoRepair {
with AmenityAutoRepair
with CaptureTerminalAwareBehavior {
def MountableObject = mech
def HackableObject = mech
def FactionObject = mech
def DamageableObject = mech
def RepairableObject = mech
def AutoRepairObject = mech
def CaptureTerminalAwareObject = mech
def commonBehavior: Receive =
checkBehavior

View file

@ -1,5 +1,5 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.implantmech
package net.psforever.objects.serverobject.terminals.implant
import net.psforever.objects.definition.SeatDefinition
import net.psforever.objects.serverobject.structures.AmenityDefinition

View file

@ -3,9 +3,14 @@ package net.psforever.objects.serverobject.turret
import net.psforever.objects.equipment.JammableUnit
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAware
import net.psforever.types.Vector3
class FacilityTurret(tDef: FacilityTurretDefinition) extends Amenity with WeaponTurret with JammableUnit {
class FacilityTurret(tDef: FacilityTurretDefinition)
extends Amenity
with WeaponTurret
with JammableUnit
with CaptureTerminalAware {
WeaponTurret.LoadDefinition(this)
def MountPoints: Map[Int, Int] = Definition.MountPoints.toMap

View file

@ -10,6 +10,7 @@ import net.psforever.objects.serverobject.damage.{Damageable, DamageableWeaponTu
import net.psforever.objects.serverobject.hackable.GenericHackables
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableWeaponTurret}
import net.psforever.objects.serverobject.structures.PoweredAmenityControl
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior
import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
@ -35,13 +36,15 @@ class FacilityTurretControl(turret: FacilityTurret)
with DamageableWeaponTurret
with RepairableWeaponTurret
with AmenityAutoRepair
with JammableMountedWeapons {
with JammableMountedWeapons
with CaptureTerminalAwareBehavior {
def FactionObject = turret
def MountableObject = turret
def JammableObject = turret
def DamageableObject = turret
def RepairableObject = turret
def AutoRepairObject = turret
def CaptureTerminalAwareObject = turret
// Used for timing ammo recharge for vanu turrets in caves
var weaponAmmoRechargeTimer = Default.Cancellable
@ -59,6 +62,7 @@ class FacilityTurretControl(turret: FacilityTurret)
.orElse(takesDamage)
.orElse(canBeRepairedByNanoDispenser)
.orElse(autoRepairBehavior)
.orElse(captureTerminalAwareBehaviour)
def poweredStateLogic: Receive =
commonBehavior
@ -113,7 +117,6 @@ class FacilityTurretControl(turret: FacilityTurret)
weaponAmmoRechargeTimer.cancel()
weaponAmmoRechargeTimer = Default.Cancellable
}
case _ => ;
}

View file

@ -40,6 +40,7 @@ import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.geometry.Geometry3D
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.vehicles.UtilityType
import net.psforever.objects.vital.etc.{EmpReason, ExplodingEntityReason}
@ -257,7 +258,7 @@ class Zone(val id: String, val map: ZoneMap, zoneNumber: Int) {
case (mechGuid, interfaceGuid) =>
validateObject(
mechGuid,
(x: PlanetSideGameObject) => x.isInstanceOf[serverobject.implantmech.ImplantTerminalMech],
(x: PlanetSideGameObject) => x.isInstanceOf[ImplantTerminalMech],
"implant terminal mech"
)
validateObject(

View file

@ -1,6 +1,7 @@
// Copyright (c) 2016 PSForever.net to present
package net.psforever.packet.game
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket}
import net.psforever.types.PlanetSideGUID
import scodec.Codec
@ -71,11 +72,11 @@ import scodec.codecs._
* Format is: Time left - 2 bytes, faction - 1 byte (1-4), isResecured - 1 byte (0-1)`<br>
* <ul>
* <li>65535 segments per faction in deciseconds (seconds * 10)</li>
* <li>0-65535 = Neutral 0 seconds to 1h 49m 14s - 0x 00 00 00 00 to 0x FF FF 00 00</li>
* <li>65536 - 131071 - TR - 0x 00 00 01 00</li>
* <li>131072 - 196607 - NC - 0x 00 00 02 00</li>
* <li>196608 - 262143 - VS - 0x 00 00 03 00</li>
* <li>17039360 - CC Resecured - 0x 00 00 04 01</li>
* <li>0-65535 = Neutral 0 seconds to 1h 49m 14s - 0x0000 to 0xFFFF</li>
* <li>65536 (0x10000) - 131071 (0x1FFFF) - TR</li>
* <li>131072 (0x20000) - 196607 (0x2FFFF) - NC</li>
* <li>196608 (0x30000) - 262143 (0x3FFFF) - VS</li>
* <li>17039360 (0x1040000) - CC Resecured</li>
* </ul>
* `24 - Learn certification:`<br>
* <ul>
@ -215,9 +216,23 @@ object PlanetsideAttributeMessage extends Marshallable[PlanetsideAttributeMessag
PlanetsideAttributeMessage(guid, attribute_type, attribute_value.guid)
}
def apply(guid: PlanetSideGUID, attribute_type: PlanetsideAttributeEnum, attribute_value: Int): PlanetsideAttributeMessage = {
PlanetsideAttributeMessage(guid, attribute_type.id, attribute_value.toLong)
}
def apply(guid: PlanetSideGUID, attribute_type: PlanetsideAttributeEnum, attribute_value: Long): PlanetsideAttributeMessage = {
PlanetsideAttributeMessage(guid, attribute_type.id, attribute_value)
}
implicit val codec: Codec[PlanetsideAttributeMessage] = (
("guid" | PlanetSideGUID.codec) ::
("attribute_type" | uint8L) ::
("attribute_value" | uint32L)
).as[PlanetsideAttributeMessage]
}
object PlanetsideAttributeEnum extends Enumeration {
type PlanetsideAttributeEnum = Value
val ControlConsoleHackUpdate = Value(20)
}

View file

@ -1,7 +1,7 @@
package net.psforever.persistence
import net.psforever.objects.definition.ImplantDefinition
import net.psforever.objects.serverobject.terminals.ImplantTerminalDefinition
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalDefinition
case class Implant(
name: String,

View file

@ -2,13 +2,15 @@
package net.psforever.services.local
import akka.actor.{Actor, ActorRef, Props}
import akka.pattern.Patterns
import akka.util.Timeout
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.structures.{Amenity, Building}
import net.psforever.objects.serverobject.terminals.{CaptureTerminal, Terminal}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.zones.Zone
import net.psforever.objects._
import net.psforever.packet.game.{TriggeredEffect, TriggeredEffectLocation}
import net.psforever.packet.game.{PlanetsideAttributeEnum, TriggeredEffect, TriggeredEffectLocation}
import net.psforever.objects.vital.Vitality
import net.psforever.types.{PlanetSideGUID, Vector3}
import net.psforever.services.local.support._
@ -20,6 +22,8 @@ import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.vehicles.{Utility, UtilityType}
import net.psforever.services.support.SupportActor
import java.util.concurrent.TimeUnit
import scala.concurrent.Await
import scala.concurrent.duration.Duration
class LocalService(zone: Zone) extends Actor {
@ -89,7 +93,7 @@ class LocalService(zone: Zone) extends Actor {
)
case LocalAction.HackClear(player_guid, target, unk1, unk2) =>
LocalEvents.publish(
LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.HackClear(target.GUID, unk1, unk2))
LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.SendHackMessageHackCleared(target.GUID, unk1, unk2))
)
case LocalAction.HackTemporarily(player_guid, _, target, unk1, duration, unk2) =>
hackClearer ! HackClearActor.ObjectIsHacked(target, zone, unk1, unk2, duration)
@ -98,43 +102,18 @@ class LocalService(zone: Zone) extends Actor {
)
case LocalAction.ClearTemporaryHack(_, target) =>
hackClearer ! HackClearActor.ObjectIsResecured(target)
case LocalAction.HackCaptureTerminal(player_guid, _, target, unk1, unk2, isResecured) =>
// When a CC is hacked (or resecured) all amenities for the base should be unhacked
val building = target.Owner.asInstanceOf[Building]
val hackableAmenities =
building.Amenities.filter(x => x.isInstanceOf[Hackable]).map(x => x.asInstanceOf[Amenity with Hackable])
hackableAmenities.foreach(amenity =>
if (amenity.HackedBy.isDefined) { hackClearer ! HackClearActor.ObjectIsResecured(amenity) }
)
if (isResecured) {
hackCapturer ! HackCaptureActor.ClearHack(target, zone)
} else {
target.Definition match {
case GlobalDefinitions.capture_terminal =>
// Base CC
hackCapturer ! HackCaptureActor.ObjectIsHacked(target, zone, unk1, unk2, duration = 15 minutes)
case GlobalDefinitions.secondary_capture =>
// Tower CC
hackCapturer ! HackCaptureActor.ObjectIsHacked(target, zone, unk1, unk2, duration = 1 nanosecond)
case GlobalDefinitions.vanu_control_console =>
hackCapturer ! HackCaptureActor.ObjectIsHacked(target, zone, unk1, unk2, duration = 10 minutes)
}
}
case LocalAction.ResecureCaptureTerminal(target) =>
hackCapturer ! HackCaptureActor.ResecureCaptureTerminal(target, zone)
case LocalAction.StartCaptureTerminalHack(target) =>
hackCapturer ! HackCaptureActor.StartCaptureTerminalHack(target, zone, 0, 8L)
case LocalAction.SendPlanetsideAttributeMessage(player_guid, target_guid, attribute_number, attribute_value) =>
LocalEvents.publish(
LocalServiceResponse(
s"/$forChannel/Local",
player_guid,
LocalResponse.HackCaptureTerminal(target.GUID, unk1, unk2, isResecured)
LocalResponse.SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value)
)
)
// If the owner of this capture terminal is on the lattice trigger a zone wide map update to update lattice benefits
zone.Lattice find building match {
case Some(_) => building.Zone.actor ! ZoneActor.ZoneMapUpdate()
case None => ;
}
case LocalAction.RouterTelepadTransport(player_guid, passenger_guid, src_guid, dest_guid) =>
LocalEvents.publish(
LocalServiceResponse(
@ -214,13 +193,13 @@ class LocalService(zone: Zone) extends Actor {
)
//response from HackClearActor
case HackClearActor.ClearTheHack(target_guid, _, unk1, unk2) =>
case HackClearActor.SendHackMessageHackCleared(target_guid, _, unk1, unk2) =>
log.info(s"Clearing hack for $target_guid")
LocalEvents.publish(
LocalServiceResponse(
s"/${zone.id}/Local",
Service.defaultPlayerGUID,
LocalResponse.HackClear(target_guid, unk1, unk2)
LocalResponse.SendHackMessageHackCleared(target_guid, unk1, unk2)
)
)
@ -242,29 +221,6 @@ class LocalService(zone: Zone) extends Actor {
)
)
case HackCaptureActor.HackTimeoutReached(capture_terminal_guid, _, _, _, hackedByFaction) =>
val terminal = zone.GUID(capture_terminal_guid).get.asInstanceOf[CaptureTerminal]
val building = terminal.Owner.asInstanceOf[Building]
if (building.NtuLevel > 0) {
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
building.Actor ! BuildingActor.SetFaction(hackedByFaction)
} else {
log.info("Base hack completed, but base was out of NTU.")
}
// FIXME shitty workaround so we don't get a "resecured by owner" message
// SetFaction must be processed before we can keep going
Thread.sleep(1000)
// Reset CC back to normal operation
self ! LocalServiceMessage(
zone.id,
LocalAction.HackCaptureTerminal(PlanetSideGUID(-1), zone, terminal, 0, 8L, isResecured = true)
)
//todo: this appears to be the way to reset the base warning lights after the hack finishes but it doesn't seem to work. The attribute above is a workaround
self ! HackClearActor.ClearTheHack(building.GUID, zone.id, 3212836864L, 8L)
//message to Engineer
case LocalServiceMessage.Deployables(msg) =>
engineer forward msg

View file

@ -6,9 +6,10 @@ import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.terminals.CaptureTerminal
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
import net.psforever.objects.vehicles.Utility
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.game.{DeployableInfo, DeploymentAction, TriggeredSound}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
@ -45,13 +46,13 @@ object LocalAction {
) extends Action
final case class ClearTemporaryHack(player_guid: PlanetSideGUID, target: PlanetSideServerObject with Hackable)
extends Action
final case class HackCaptureTerminal(
final case class ResecureCaptureTerminal(target: CaptureTerminal) extends Action
final case class StartCaptureTerminalHack(target: CaptureTerminal) extends Action
final case class SendPlanetsideAttributeMessage(
player_guid: PlanetSideGUID,
continent: Zone,
target: CaptureTerminal,
unk1: Long,
unk2: Long = 8L,
isResecured: Boolean
target: PlanetSideGUID,
attribute_number: PlanetsideAttributeEnum,
attribute_value: Long
) extends Action
final case class RouterTelepadTransport(
player_guid: PlanetSideGUID,

View file

@ -5,6 +5,7 @@ import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.terminals.{ProximityUnit, Terminal}
import net.psforever.objects.vehicles.Utility
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.game._
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
import net.psforever.services.GenericEventBusMsg
@ -28,9 +29,9 @@ object LocalResponse {
object_guid: PlanetSideGUID,
pos: Vector3
) extends Response
final case class HackClear(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response
final case class SendHackMessageHackCleared(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response
final case class HackObject(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response
final case class HackCaptureTerminal(target_guid: PlanetSideGUID, unk1: Long, unk2: Long, isResecured: Boolean)
final case class SendPlanetsideAttributeMessage(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long)
extends Response
final case class ObjectDelete(item_guid: PlanetSideGUID, unk: Int) extends Response
final case class ProximityTerminalAction(terminal: Terminal with ProximityUnit, target: PlanetSideGameObject)

View file

@ -1,15 +1,18 @@
package net.psforever.services.local.support
import akka.actor.{Actor, Cancellable}
import net.psforever.actors.zone.ZoneActor
import net.psforever.objects.Default
import net.psforever.actors.zone.{BuildingActor, ZoneActor}
import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.terminals.CaptureTerminal
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
import net.psforever.objects.zones.Zone
import net.psforever.objects.{Default, GlobalDefinitions}
import net.psforever.packet.game.PlanetsideAttributeEnum
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import java.util.concurrent.TimeUnit
import scala.concurrent.duration.{FiniteDuration, _}
class HackCaptureActor extends Actor {
@ -21,8 +24,21 @@ class HackCaptureActor extends Actor {
private var hackedObjects: List[HackCaptureActor.HackEntry] = Nil
def receive: Receive = {
case HackCaptureActor.ObjectIsHacked(target, zone, unk1, unk2, duration, time) =>
case HackCaptureActor.StartCaptureTerminalHack(target, zone, unk1, unk2, startTime) =>
log.trace(s"${target.GUID} is hacked.")
val duration = target.Definition match {
case GlobalDefinitions.capture_terminal =>
// Base CC
15 minutes
case GlobalDefinitions.secondary_capture =>
// Tower CC
1 nanosecond
case GlobalDefinitions.vanu_control_console =>
// Cavern CC
10 minutes
}
target.HackedBy match {
case Some(hackInfo) =>
target.HackedBy = hackInfo.Duration(duration.toNanos)
@ -36,56 +52,81 @@ class HackCaptureActor extends Actor {
s"${target.GUID} was already hacked - removing it from the hacked objects list before re-adding it."
)
hackedObjects = hackedObjects.filterNot(x => x.target == target)
log.warn(s"len: ${hackedObjects.length}")
case _ => ;
}
hackedObjects = hackedObjects :+ HackCaptureActor.HackEntry(target, zone, unk1, unk2, duration, time)
hackedObjects = hackedObjects :+ HackCaptureActor.HackEntry(target, zone, unk1, unk2, duration, startTime)
// Restart the timer, in case this is the first object in the hacked objects list or the object was removed and re-added
RestartTimer()
if (target.isInstanceOf[CaptureTerminal]) {
target.Owner.asInstanceOf[Building].Zone.actor ! ZoneActor.ZoneMapUpdate()
}
NotifyHackStateChange(target, isResecured = false)
case HackCaptureActor.ProcessCompleteHacks() =>
log.trace("Processing complete hacks")
clearTrigger.cancel()
val now: Long = System.nanoTime
val stillHacked = hackedObjects.filter(x => now - x.hack_timestamp <= x.duration.toNanos)
val unhackObjects = hackedObjects.filter(x => now - x.hack_timestamp >= x.duration.toNanos)
val finishedHacks = hackedObjects.filter(x => now - x.hack_timestamp >= x.duration.toNanos)
hackedObjects = stillHacked
unhackObjects.foreach(entry => {
finishedHacks.foreach(entry => {
log.trace(s"Capture terminal hack timeout reached for terminal ${entry.target.GUID}")
val hackedByFaction = entry.target.HackedBy.get.hackerFaction
entry.target.Actor ! CommonMessages.ClearHack()
context.parent ! HackCaptureActor.HackTimeoutReached(
entry.target.GUID,
entry.zone.id,
entry.unk1,
entry.unk2,
hackedByFaction
) //call up to the main event system
HackCompleted(entry.target, hackedByFaction)
})
// If there's hacked objects left in the list restart the timer with the shortest hack time left
RestartTimer()
case HackCaptureActor.ClearHack(target, _) =>
case HackCaptureActor.ResecureCaptureTerminal(target, _) =>
hackedObjects = hackedObjects.filterNot(x => x.target == target)
if (target.isInstanceOf[CaptureTerminal]) {
target.Owner.asInstanceOf[Building].Zone.actor ! ZoneActor.ZoneMapUpdate()
}
NotifyHackStateChange(target, isResecured = true)
// Restart the timer in case the object we just removed was the next one scheduled
RestartTimer()
case _ => ;
}
private def NotifyHackStateChange(target: CaptureTerminal, isResecured: Boolean): Unit = {
val attribute_value = HackCaptureActor.GetHackUpdateAttributeValue(target, isResecured)
// Notify all clients that CC has been hacked
target.Zone.LocalEvents ! LocalServiceMessage(
target.Zone.id,
LocalAction.SendPlanetsideAttributeMessage(
PlanetSideGUID(-1),
target.GUID,
PlanetsideAttributeEnum.ControlConsoleHackUpdate,
attribute_value
)
)
// Notify parent building that state has changed
target.Owner.Actor ! BuildingActor.AmenityStateChange(target, Some(isResecured))
// Push map update to clients
target.Owner.asInstanceOf[Building].Zone.actor ! ZoneActor.ZoneMapUpdate()
}
private def HackCompleted(terminal: CaptureTerminal with Hackable, hackedByFaction: PlanetSideEmpire.Value): Unit = {
val building = terminal.Owner.asInstanceOf[Building]
if (building.NtuLevel > 0) {
log.info(s"Setting base ${building.GUID} / MapId: ${building.MapId} as owned by $hackedByFaction")
building.Actor! BuildingActor.SetFaction(hackedByFaction)
} else {
log.info("Base hack completed, but base was out of NTU.")
}
NotifyHackStateChange(terminal, isResecured = true)
// todo: this appears to be the way to reset the base warning lights after the hack finishes but it doesn't seem to work.
context.parent ! HackClearActor.SendHackMessageHackCleared(building.GUID, terminal.Zone.id, 3212836864L, 8L) //call up to the `LocalService`
}
private def RestartTimer(): Unit = {
if (hackedObjects.nonEmpty) {
val now = System.nanoTime()
@ -110,33 +151,49 @@ class HackCaptureActor extends Actor {
}
object HackCaptureActor {
final case class ObjectIsHacked(
target: CaptureTerminal,
zone: Zone,
unk1: Long,
unk2: Long,
duration: FiniteDuration,
time: Long = System.nanoTime()
final case class StartCaptureTerminalHack(
target: CaptureTerminal,
zone: Zone,
unk1: Long,
unk2: Long,
startTime: Long = System.nanoTime()
)
final case class HackTimeoutReached(
capture_terminal_guid: PlanetSideGUID,
zone_id: String,
unk1: Long,
unk2: Long,
hackedByFaction: PlanetSideEmpire.Value
)
final case class ClearHack(target: CaptureTerminal, zone: Zone)
final case class ResecureCaptureTerminal(target: CaptureTerminal, zone: Zone)
private final case class ProcessCompleteHacks()
private final case class HackEntry(
target: PlanetSideServerObject with Hackable,
target: CaptureTerminal with Hackable,
zone: Zone,
unk1: Long,
unk2: Long,
duration: FiniteDuration,
hack_timestamp: Long
)
def GetHackUpdateAttributeValue(target: CaptureTerminal, isResecured: Boolean): Long = {
if (isResecured) {
17039360L
} else {
target.HackedBy match {
case Some(Hackable.HackInfo(_, _, hackingFaction, _, start, length)) =>
// See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
val hack_time_remaining_ms =
TimeUnit.MILLISECONDS.convert(math.max(0, start + length - System.nanoTime), TimeUnit.NANOSECONDS)
val start_num = hackingFaction match {
case PlanetSideEmpire.TR => 0x10000
case PlanetSideEmpire.NC => 0x20000
case PlanetSideEmpire.VS => 0x30000
}
start_num + (hack_time_remaining_ms / 100) // Add time remaining as deciseconds
case _ =>
0
}
}
}
}

View file

@ -43,7 +43,7 @@ class HackClearActor() extends Actor {
hackedObjects = stillHackedObjects
unhackObjects.foreach(entry => {
entry.target.Actor ! CommonMessages.ClearHack()
context.parent ! HackClearActor.ClearTheHack(
context.parent ! HackClearActor.SendHackMessageHackCleared(
entry.target.GUID,
entry.zone.id,
entry.unk1,
@ -59,7 +59,7 @@ class HackClearActor() extends Actor {
case Some(entry: HackClearActor.HackEntry) =>
hackedObjects = hackedObjects.filterNot(x => x.target == target)
entry.target.Actor ! CommonMessages.ClearHack()
context.parent ! HackClearActor.ClearTheHack(
context.parent ! HackClearActor.SendHackMessageHackCleared(
entry.target.GUID,
entry.zone.id,
entry.unk1,
@ -173,7 +173,7 @@ object HackClearActor {
* @param obj the server object
* @param zone_id the zone in which the object resides
*/
final case class ClearTheHack(obj: PlanetSideGUID, zone_id: String, unk1: Long, unk2: Long)
final case class SendHackMessageHackCleared(obj: PlanetSideGUID, zone_id: String, unk1: Long, unk2: Long)
/**
* Internal message used to signal a test of the queued door information.

View file

@ -1,18 +1,10 @@
package net.psforever.zones
import java.io.FileNotFoundException
import net.psforever.objects.serverobject.terminals.{
CaptureTerminal,
CaptureTerminalDefinition,
ProximityTerminal,
ProximityTerminalDefinition,
Terminal,
TerminalDefinition
}
import net.psforever.objects.serverobject.terminals.{ProximityTerminal, ProximityTerminalDefinition, Terminal, TerminalDefinition}
import net.psforever.objects.serverobject.mblocker.Locker
import java.util.concurrent.atomic.AtomicInteger
import java.util.concurrent.atomic.AtomicInteger
import akka.actor.ActorContext
import io.circe._
import io.circe.parser._
@ -21,18 +13,13 @@ import net.psforever.objects.ballistics.Projectile
import net.psforever.objects.definition.BasicDefinition
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.generator.Generator
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.pad.{VehicleSpawnPad, VehicleSpawnPadDefinition}
import net.psforever.objects.serverobject.painbox.{Painbox, PainboxDefinition}
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.structures.{
Building,
BuildingDefinition,
FoundationBuilder,
StructureType,
WarpGate
}
import net.psforever.objects.serverobject.structures.{Building, BuildingDefinition, FoundationBuilder, StructureType, WarpGate}
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalDefinition}
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition}
import net.psforever.objects.serverobject.zipline.ZipLinePath
@ -246,7 +233,7 @@ object Zones {
val structureType =
if (towerTypes.contains(structure.objectType) || structure.objectType == "redoubt")
StructureType.Tower
else if (facilityTypes.contains(structure.objectType))
else if (facilityTypes.contains(structure.objectType) || cavernBuildingTypes.contains(structure.objectType))
StructureType.Facility
else if (bunkerTypes.contains(structure.objectType))
StructureType.Bunker

View file

@ -11,7 +11,6 @@ import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.MaxNumberSource
import net.psforever.objects.serverobject.damage.Damageable
import net.psforever.objects.serverobject.generator.{Generator, GeneratorControl}
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl, TerminalDefinition}
import net.psforever.objects.serverobject.tube.SpawnTube
@ -30,6 +29,7 @@ import org.specs2.mutable.Specification
import scala.concurrent.duration._
import net.psforever.objects.avatar.Avatar
import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalMech, ImplantTerminalMechControl}
import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.base.DamageResolution
import net.psforever.objects.vital.projectile.ProjectileReason

View file

@ -83,7 +83,9 @@ class IFFLockObjectBuilderTest extends FreedContextActorTest {
}
class ImplantTerminalMechObjectBuilderTest extends FreedContextActorTest {
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech
"Implant terminal mech object" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub

View file

@ -9,9 +9,9 @@ import net.psforever.objects.definition.SeatDefinition
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.objects.guid.source.MaxNumberSource
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl}
import net.psforever.objects.serverobject.structures.{Building, StructureType}
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalMech, ImplantTerminalMechControl}
import net.psforever.objects.vehicles.Seat
import net.psforever.objects.zones.{Zone, ZoneMap}
import net.psforever.types.{CharacterGender, CharacterVoice, PlanetSideEmpire, Vector3}

View file

@ -152,7 +152,7 @@ class HackClearTest extends ActorTest {
service ! Service.Join("test")
service ! LocalServiceMessage("test", LocalAction.HackClear(PlanetSideGUID(10), obj, 0L, 1000L))
expectMsg(
LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.HackClear(PlanetSideGUID(40), 0L, 1000L))
LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.SendHackMessageHackCleared(PlanetSideGUID(40), 0L, 1000L))
)
}
}