Implant Terminal Hack (#1221)

* preliminary functional implant hacking; am going to explore better hacking policies

* HackMessage now uses custom fields and a float value rather than integers (2, 32, 32); separate hack state and hack clear states; everything changes
This commit is contained in:
Fate-JH 2024-08-03 00:12:16 -04:00 committed by GitHub
parent 8afe7fa248
commit 02f95a293e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 488 additions and 204 deletions

View file

@ -13,7 +13,7 @@ import net.psforever.objects.avatar.scoring.{Assist, Death, EquipmentStat, KDASt
import net.psforever.objects.sourcing.{TurretSource, VehicleSource} import net.psforever.objects.sourcing.{TurretSource, VehicleSource}
import net.psforever.packet.game.ImplantAction import net.psforever.packet.game.ImplantAction
import net.psforever.services.avatar.AvatarServiceResponse import net.psforever.services.avatar.AvatarServiceResponse
import net.psforever.types.{ChatMessageType, StatisticalCategory, StatisticalElement, Vector3} import net.psforever.types.{ChatMessageType, StatisticalCategory, StatisticalElement}
import net.psforever.zones.Zones import net.psforever.zones.Zones
import org.joda.time.{LocalDateTime, Seconds} import org.joda.time.{LocalDateTime, Seconds}

View file

@ -7,7 +7,7 @@ import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.vehicles.MountableWeapons import net.psforever.objects.vehicles.MountableWeapons
import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable} import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage} import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, HackState1, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage}
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.local.LocalResponse import net.psforever.services.local.LocalResponse
import net.psforever.types.{ChatMessageType, PlanetSideGUID, Vector3} import net.psforever.types.{ChatMessageType, PlanetSideGUID, Vector3}
@ -136,7 +136,7 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect) DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect)
case LocalResponse.SendHackMessageHackCleared(targetGuid, unk1, unk2) => case LocalResponse.SendHackMessageHackCleared(targetGuid, unk1, unk2) =>
sendResponse(HackMessage(unk1=0, targetGuid, guid, progress=0, unk1, HackState.HackCleared, unk2)) sendResponse(HackMessage(HackState1.Unk0, targetGuid, guid, progress=0, unk1.toFloat, HackState.HackCleared, unk2))
case LocalResponse.HackObject(targetGuid, unk1, unk2) => case LocalResponse.HackObject(targetGuid, unk1, unk2) =>
sessionLogic.general.hackObject(targetGuid, unk1, unk2) sessionLogic.general.hackObject(targetGuid, unk1, unk2)

View file

@ -7,7 +7,7 @@ import net.psforever.objects.ce.Deployable
import net.psforever.objects.guid.{GUIDTask, TaskWorkflow} import net.psforever.objects.guid.{GUIDTask, TaskWorkflow}
import net.psforever.objects.vehicles.MountableWeapons import net.psforever.objects.vehicles.MountableWeapons
import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable} import net.psforever.objects.{BoomerDeployable, ExplosiveDeployable, TelepadDeployable, Tool, TurretDeployable}
import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage} import net.psforever.packet.game.{ChatMsg, DeployableObjectsInfoMessage, GenericActionMessage, GenericObjectActionMessage, GenericObjectStateMsg, HackMessage, HackState, HackState1, InventoryStateMessage, ObjectAttachMessage, ObjectCreateMessage, ObjectDeleteMessage, ObjectDetachMessage, OrbitalShuttleTimeMsg, PadAndShuttlePair, PlanetsideAttributeMessage, ProximityTerminalUseMessage, SetEmpireMessage, TriggerEffectMessage, TriggerSoundMessage, TriggeredSound, VehicleStateMessage}
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.local.LocalResponse import net.psforever.services.local.LocalResponse
import net.psforever.types.{ChatMessageType, PlanetSideGUID, Vector3} import net.psforever.types.{ChatMessageType, PlanetSideGUID, Vector3}
@ -125,7 +125,7 @@ class LocalHandlerLogic(val ops: SessionLocalHandlers, implicit val context: Act
DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect) DeconstructDeployable(obj, dguid, pos, obj.Orientation, effect)
case LocalResponse.SendHackMessageHackCleared(targetGuid, unk1, unk2) => case LocalResponse.SendHackMessageHackCleared(targetGuid, unk1, unk2) =>
sendResponse(HackMessage(unk1=0, targetGuid, guid, progress=0, unk1, HackState.HackCleared, unk2)) sendResponse(HackMessage(HackState1.Unk0, targetGuid, guid, progress=0, unk1.toFloat, HackState.HackCleared, unk2))
case LocalResponse.HackObject(targetGuid, unk1, unk2) => case LocalResponse.HackObject(targetGuid, unk1, unk2) =>
sessionLogic.general.hackObject(targetGuid, unk1, unk2) sessionLogic.general.hackObject(targetGuid, unk1, unk2)

View file

@ -562,8 +562,8 @@ class GeneralOperations(
* @param unk1 na * @param unk1 na
* @param unk2 na * @param unk2 na
*/ */
def hackObject(targetGuid: PlanetSideGUID, unk1: Long, unk2: Long): Unit = { def hackObject(targetGuid: PlanetSideGUID, unk1: Long, unk2: HackState7): Unit = {
sendResponse(HackMessage(unk1=0, targetGuid, player_guid=Service.defaultPlayerGUID, progress=100, unk1, HackState.Hacked, unk2)) sendResponse(HackMessage(HackState1.Unk0, targetGuid, player_guid=Service.defaultPlayerGUID, progress=100, unk1, HackState.Hacked, unk2))
} }
/** /**

View file

@ -17,7 +17,7 @@ import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret import net.psforever.objects.serverobject.turret.auto.AutomatedTurret
import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource} import net.psforever.objects.sourcing.{PlayerSource, SourceEntry, VehicleSource}
import net.psforever.objects.vital.{InGameHistory, IncarnationActivity, ReconstructionActivity, SpawningActivity} import net.psforever.objects.vital.{InGameHistory, IncarnationActivity, ReconstructionActivity, SpawningActivity}
import net.psforever.packet.game.{CampaignStatistic, ChangeFireStateMessage_Start, MailMessage, ObjectDetectedMessage, SessionStatistic} import net.psforever.packet.game.{CampaignStatistic, ChangeFireStateMessage_Start, HackState7, MailMessage, ObjectDetectedMessage, SessionStatistic}
import net.psforever.services.chat.DefaultChannel import net.psforever.services.chat.DefaultChannel
import scala.collection.mutable import scala.collection.mutable
@ -1084,26 +1084,30 @@ class ZoningOperations(
* @param zone the zone being loaded * @param zone the zone being loaded
*/ */
def configZone(zone: Zone): Unit = { def configZone(zone: Zone): Unit = {
zone.Buildings.values.foreach(building => { zone
val guid = building.GUID .Buildings
sendResponse(SetEmpireMessage(guid, building.Faction)) .values
// power .foreach { building =>
building.Generator match { val guid = building.GUID
case Some(obj) if obj.Condition == PlanetSideGeneratorState.Destroyed || building.NtuLevel == 0 => sendResponse(SetEmpireMessage(guid, building.Faction))
sendResponse(PlanetsideAttributeMessage(guid, 48, 1)) //amenities disabled; red warning lights // power
sendResponse(PlanetsideAttributeMessage(guid, 38, 0)) //disable spawn target on deployment map building.Generator match {
case _ => () case Some(obj) if obj.Condition == PlanetSideGeneratorState.Destroyed || building.NtuLevel == 0 =>
sendResponse(PlanetsideAttributeMessage(guid, 48, 1)) //amenities disabled; red warning lights
sendResponse(PlanetsideAttributeMessage(guid, 38, 0)) //disable spawn target on deployment map
case _ => ()
}
// capitol force dome state
if (building.IsCapitol && building.ForceDomeActive) {
sendResponse(GenericObjectActionMessage(guid, 13))
}
// amenities
building.Amenities.collect {
case obj if obj.Destroyed => configAmenityAsDestroyed(obj)
case obj => configAmenityAsWorking(obj)
}
//sendResponse(HackMessage(HackState1.Unk3, guid, Service.defaultPlayerGUID, progress=0, -1f, HackState.HackCleared, HackState7.Unk8))
} }
// capitol force dome state
if (building.IsCapitol && building.ForceDomeActive) {
sendResponse(GenericObjectActionMessage(guid, 13))
}
// amenities
building.Amenities.collect {
case obj if obj.Destroyed => configAmenityAsDestroyed(obj)
case obj => configAmenityAsWorking(obj)
}
})
} }
/** /**
@ -1156,7 +1160,7 @@ class ZoningOperations(
HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false) HackCaptureActor.GetHackUpdateAttributeValue(amenity.asInstanceOf[CaptureTerminal], isResecured = false)
) )
case _ => case _ =>
sessionLogic.general.hackObject(amenity.GUID, 1114636288L, 8L) //generic hackable object sessionLogic.general.hackObject(amenity.GUID, unk1 = 1114636288L, HackState7.Unk8) //generic hackable object
} }
// sync capture flags // sync capture flags

View file

@ -11,6 +11,7 @@ import net.psforever.objects.serverobject.turret.{MountableTurret, WeaponTurrets
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.sourcing.SourceEntry import net.psforever.objects.sourcing.SourceEntry
import net.psforever.objects.vital.{InGameActivity, ShieldCharge} import net.psforever.objects.vital.{InGameActivity, ShieldCharge}
import net.psforever.packet.game.HackState1
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
@ -54,7 +55,7 @@ class FieldTurretControl(turret: TurretDeployable)
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, turret), GenericHackables.GetHackSpeed(player, turret),
WeaponTurrets.FinishHackingTurretDeployable(turret, player), WeaponTurrets.FinishHackingTurretDeployable(turret, player),
GenericHackables.HackingTickAction(progressType = 1, player, turret, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, turret, item.GUID)
) )
case CommonMessages.ChargeShields(amount, motivator) => case CommonMessages.ChargeShields(amount, motivator) =>

View file

@ -10,7 +10,7 @@ import net.psforever.objects.serverobject.transfer.TransferContainer
import net.psforever.objects.serverobject.structures.WarpGate import net.psforever.objects.serverobject.structures.WarpGate
import net.psforever.objects.vehicles._ import net.psforever.objects.vehicles._
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.TriggeredSound import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, TriggeredSound}
import net.psforever.types.{DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3} import net.psforever.types.{DriveState, PlanetSideEmpire, PlanetSideGUID, Vector3}
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
@ -73,7 +73,7 @@ object Vehicles {
} }
vehicle.AssignOwnership(None) vehicle.AssignOwnership(None)
val empire = VehicleLockState.Empire.id val empire = VehicleLockState.Empire.id
val factionChannel = s"${vehicle.Faction}" //val factionChannel = s"${vehicle.Faction}"
(0 to 2).foreach(group => { (0 to 2).foreach(group => {
vehicle.PermissionGroup(group, empire) vehicle.PermissionGroup(group, empire)
/*vehicle.Zone.VehicleEvents ! VehicleServiceMessage( /*vehicle.Zone.VehicleEvents ! VehicleServiceMessage(
@ -131,7 +131,7 @@ object Vehicles {
if (vehicle.OwnerGuid.contains(pguid)) { if (vehicle.OwnerGuid.contains(pguid)) {
vehicle.AssignOwnership(None) vehicle.AssignOwnership(None)
//vehicle.Zone.VehicleEvents ! VehicleServiceMessage(player.Name, VehicleAction.Ownership(pguid, PlanetSideGUID(0))) //vehicle.Zone.VehicleEvents ! VehicleServiceMessage(player.Name, VehicleAction.Ownership(pguid, PlanetSideGUID(0)))
val vguid = vehicle.GUID //val vguid = vehicle.GUID
val empire = VehicleLockState.Empire.id val empire = VehicleLockState.Empire.id
(0 to 2).foreach(group => { (0 to 2).foreach(group => {
vehicle.PermissionGroup(group, empire) vehicle.PermissionGroup(group, empire)
@ -230,11 +230,23 @@ object Vehicles {
* Change the faction of the vehicle to the hacker's faction and remove all occupants. * Change the faction of the vehicle to the hacker's faction and remove all occupants.
* @param target The `Vehicle` object that has been hacked/jacked * @param target The `Vehicle` object that has been hacked/jacked
* @param hacker the one whoi performed the hack and will inherit ownership of the target vehicle * @param hacker the one whoi performed the hack and will inherit ownership of the target vehicle
* @param unk na; used by `HackMessage` as `unk5`
*/ */
def FinishHackingVehicle(target: Vehicle, hacker: Player, unk: Long)(): Unit = { def FinishHackingVehicle(target: Vehicle, hacker: Player)(): Unit = {
log.info(s"${hacker.Name} has jacked a ${target.Definition.Name}") log.info(s"${hacker.Name} has jacked a ${target.Definition.Name}")
val tGuid = target.GUID
val hGuid = hacker.GUID
val hFaction = hacker.Faction
val zone = target.Zone val zone = target.Zone
val zoneid = zone.id
val vehicleEvents = zone.VehicleEvents
vehicleEvents ! VehicleServiceMessage(
zoneid,
VehicleAction.SendResponse(
Service.defaultPlayerGUID,
HackMessage(HackState1.Unk2, tGuid, hGuid, 100, 0f, HackState.Hacked, HackState7.Unk8)
)
)
target.Actor ! CommonMessages.Hack(hacker, target)
// Forcefully dismount any cargo // Forcefully dismount any cargo
target.CargoHolds.foreach { case (_, cargoHold) => target.CargoHolds.foreach { case (_, cargoHold) =>
cargoHold.occupant.collect { cargoHold.occupant.collect {
@ -244,18 +256,16 @@ object Vehicles {
// Forcefully dismount all seated occupants from the vehicle // Forcefully dismount all seated occupants from the vehicle
target.Seats.values.foreach(seat => { target.Seats.values.foreach(seat => {
seat.occupant.collect { seat.occupant.collect {
tplayer: Player => player: Player =>
seat.unmount(tplayer) seat.unmount(player)
tplayer.VehicleSeated = None player.VehicleSeated = None
if (tplayer.HasGUID) { vehicleEvents ! VehicleServiceMessage(
zone.VehicleEvents ! VehicleServiceMessage( zoneid,
zone.id, VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, tGuid)
VehicleAction.KickPassenger(tplayer.GUID, 4, unk2 = false, target.GUID) )
)
}
} }
}) })
// If the vehicle can fly and is flying deconstruct it, and well played to whomever managed to hack a plane in mid air. I'm impressed. // If the vehicle can fly and is flying: deconstruct it; and well played to whomever managed to hack a plane in mid air
if (target.Definition.CanFly && target.isFlying) { if (target.Definition.CanFly && target.isFlying) {
// todo: Should this force the vehicle to land in the same way as when a pilot bails with passengers on board? // todo: Should this force the vehicle to land in the same way as when a pilot bails with passengers on board?
target.Actor ! Vehicle.Deconstruct() target.Actor ! Vehicle.Deconstruct()
@ -273,19 +283,18 @@ object Vehicles {
Vehicles.Disown(tplayer, target) Vehicles.Disown(tplayer, target)
} }
// Now take ownership of the jacked vehicle // Now take ownership of the jacked vehicle
target.Actor ! CommonMessages.Hack(hacker, target) target.Faction = hFaction
target.Faction = hacker.Faction
Vehicles.Own(target, hacker) Vehicles.Own(target, hacker)
//todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary. //todo: Send HackMessage -> HackCleared to vehicle? can be found in packet captures. Not sure if necessary.
// And broadcast the faction change to other clients // And broadcast the faction change to other clients
zone.AvatarEvents ! AvatarServiceMessage( zone.AvatarEvents ! AvatarServiceMessage(
zone.id, zoneid,
AvatarAction.SetEmpire(Service.defaultPlayerGUID, target.GUID, hacker.Faction) AvatarAction.SetEmpire(Service.defaultPlayerGUID, tGuid, hFaction)
) )
} }
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! LocalServiceMessage(
zone.id, zoneid,
LocalAction.TriggerSound(hacker.GUID, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f) LocalAction.TriggerSound(hGuid, TriggeredSound.HackVehicle, target.Position, 30, 0.49803925f)
) )
// Clean up after specific vehicles, e.g. remove router telepads // Clean up after specific vehicles, e.g. remove router telepads
// If AMS is deployed, swap it to the new faction // If AMS is deployed, swap it to the new faction
@ -298,9 +307,17 @@ object Vehicles {
util.Actor ! TelepadLike.Activate(util) util.Actor ! TelepadLike.Activate(util)
} }
case GlobalDefinitions.ams if target.DeploymentState == DriveState.Deployed => case GlobalDefinitions.ams if target.DeploymentState == DriveState.Deployed =>
zone.VehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(zone) vehicleEvents ! VehicleServiceMessage.AMSDeploymentChange(zone)
case _ => () case _ => ()
} }
vehicleEvents ! VehicleServiceMessage(
zoneid,
VehicleAction.SendResponse(
Service.defaultPlayerGUID,
HackMessage(HackState1.Unk2, tGuid, tGuid, 0, 1L, HackState.HackCleared, HackState7.Unk8)
)
)
target.Actor ! CommonMessages.ClearHack()
} }
def FindANTChargingSource( def FindANTChargingSource(

View file

@ -165,7 +165,7 @@ object GlobalDefinitionsMiscellaneous {
cert_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.66405f, height = 1.09374f) cert_terminal.Geometry = GeometryForm.representByCylinder(radius = 0.66405f, height = 1.09374f)
implant_terminal_mech.Name = "implant_terminal_mech" implant_terminal_mech.Name = "implant_terminal_mech"
implant_terminal_mech.MaxHealth = 1500 //TODO 1000; right now, 1000 (mech) + 500 (interface) implant_terminal_mech.MaxHealth = 1000
implant_terminal_mech.Damageable = true implant_terminal_mech.Damageable = true
implant_terminal_mech.Repairable = true implant_terminal_mech.Repairable = true
implant_terminal_mech.autoRepair = AutoRepairStats(1.6f, 5000, 2400, 0.05f) implant_terminal_mech.autoRepair = AutoRepairStats(1.6f, 5000, 2400, 0.05f)
@ -176,7 +176,7 @@ object GlobalDefinitionsMiscellaneous {
implant_terminal_interface.Name = "implant_terminal_interface" implant_terminal_interface.Name = "implant_terminal_interface"
implant_terminal_interface.Tab += 0 -> ImplantPage(ImplantTerminalDefinition.implants) implant_terminal_interface.Tab += 0 -> ImplantPage(ImplantTerminalDefinition.implants)
implant_terminal_interface.MaxHealth = 500 implant_terminal_interface.MaxHealth = 500
implant_terminal_interface.Damageable = false //TODO true implant_terminal_interface.Damageable = false //true
implant_terminal_interface.Repairable = true implant_terminal_interface.Repairable = true
implant_terminal_interface.autoRepair = AutoRepairStats(1, 5000, 200, 1) implant_terminal_interface.autoRepair = AutoRepairStats(1, 5000, 200, 1)
implant_terminal_interface.RepairIfDestroyed = true implant_terminal_interface.RepairIfDestroyed = true

View file

@ -6,7 +6,7 @@ import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, Env
import net.psforever.objects.sourcing.SourceEntry import net.psforever.objects.sourcing.SourceEntry
import net.psforever.objects.vital.etc.SuicideReason import net.psforever.objects.vital.etc.SuicideReason
import net.psforever.objects.vital.interaction.DamageInteraction import net.psforever.objects.vital.interaction.DamageInteraction
import net.psforever.objects.vital.{IncarnationActivity, ReconstructionActivity, Vitality} import net.psforever.objects.vital.{IncarnationActivity, Vitality}
import net.psforever.objects.zones.InteractsWithZone import net.psforever.objects.zones.InteractsWithZone
import scala.annotation.unused import scala.annotation.unused

View file

@ -3,7 +3,7 @@ package net.psforever.objects.serverobject.hackable
import net.psforever.objects.{Player, Vehicle} import net.psforever.objects.{Player, Vehicle}
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.packet.game.{HackMessage, HackState} import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7}
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
@ -68,43 +68,34 @@ object GenericHackables {
* @see `HackState` * @see `HackState`
* @param progressType 1 - remote electronics kit hack (various ...); * @param progressType 1 - remote electronics kit hack (various ...);
* 2 - nano dispenser (upgrade canister) turret upgrade * 2 - nano dispenser (upgrade canister) turret upgrade
* @param tplayer the player performing the action * @param hacker the player performing the action
* @param target the object being affected * @param target the object being affected
* @param tool_guid the tool being used to affest the object * @param tool_guid the tool being used to affest the object
* @param progress the current progress value * @param progress the current progress value
* @return `true`, if the next cycle of progress should occur; * @return `true`, if the next cycle of progress should occur;
* `false`, otherwise * `false`, otherwise
*/ */
def HackingTickAction(progressType: Int, tplayer: Player, target: PlanetSideServerObject, tool_guid: PlanetSideGUID)( def HackingTickAction(progressType: HackState1, hacker: Player, target: PlanetSideServerObject, tool_guid: PlanetSideGUID)(
progress: Float progress: Float
): Boolean = { ): Boolean = {
//hack state for progress bar visibility //hack state for progress bar visibility
val vis = if (progress <= 0L) { val (progressState, progressGrade) = if (progress <= 0L) {
HackState.Start (HackState.Start, 0)
} else if (progress >= 100L) { } else if (progress >= 100L) {
HackState.Finished (HackState.Finished, 100)
} else if (target.isMoving(test = 1f)) { } else if (target.isMoving(test = 1f) || target.Destroyed || !target.HasGUID) {
// If the object is moving (more than slightly to account for things like magriders rotating, or the last velocity reported being the magrider dipping down on dismount) then cancel the hack (HackState.Cancelled, 0)
HackState.Cancelled
} else { } else {
HackState.Ongoing (HackState.Ongoing, progress.toInt)
} }
target.Zone.AvatarEvents ! AvatarServiceMessage( target.Zone.AvatarEvents ! AvatarServiceMessage(
tplayer.Name, hacker.Name,
AvatarAction.SendResponse( AvatarAction.SendResponse(
Service.defaultPlayerGUID, Service.defaultPlayerGUID,
if (!target.HasGUID) { HackMessage(progressType, target.GUID, hacker.GUID, progressGrade, 0L, progressState, HackState7.Unk8)
//cancel the hack (target is gone)
HackMessage(progressType, target.GUID, tplayer.GUID, 0, 0L, HackState.Cancelled, 8L)
} else if (vis == HackState.Cancelled) {
//cancel the hack (e.g. vehicle drove away)
HackMessage(progressType, target.GUID, tplayer.GUID, 0, 0L, vis, 8L)
} else {
HackMessage(progressType, target.GUID, tplayer.GUID, progress.toInt, 0L, vis, 8L)
}
) )
) )
vis != HackState.Cancelled progressState != HackState.Cancelled
} }
/** /**
@ -112,12 +103,12 @@ object GenericHackables {
* Pass the message onto the hackable object and onto the local events system. * Pass the message onto the hackable object and onto the local events system.
* @param target the `Hackable` object that has been hacked * @param target the `Hackable` object that has been hacked
* @param user the player that is performing this hacking task * @param user the player that is performing this hacking task
* @param unk na; * @param hackValue na;
* used by `HackMessage` as `unk5` * @param hackClearValue na
* @see `HackMessage` * @see `HackMessage`
*/ */
//TODO add params here depending on which params in HackMessage are important //TODO add params here depending on which params in HackMessage are important
def FinishHacking(target: PlanetSideServerObject with Hackable, user: Player, unk: Long)(): Unit = { def FinishHacking(target: PlanetSideServerObject with Hackable, user: Player, hackValue: Int, hackClearValue: Int)(): Unit = {
import akka.pattern.ask import akka.pattern.ask
import scala.concurrent.duration._ import scala.concurrent.duration._
// Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly // Wait for the target actor to set the HackedBy property, otherwise LocalAction.HackTemporarily will not complete properly
@ -138,7 +129,7 @@ object GenericHackables {
zone.LocalEvents ! LocalServiceMessage( zone.LocalEvents ! LocalServiceMessage(
zoneId, zoneId,
LocalAction LocalAction
.HackTemporarily(pguid, zone, target, unk, target.HackEffectDuration(user.avatar.hackingSkillLevel())) .HackTemporarily(pguid, zone, target, hackValue, hackClearValue, target.HackEffectDuration(user.avatar.hackingSkillLevel()))
) )
case Failure(_) => case Failure(_) =>
log.warn(s"Hack message failed on target: ${target.Definition.Name}@${target.GUID.guid}") log.warn(s"Hack message failed on target: ${target.Definition.Name}@${target.GUID.guid}")

View file

@ -4,9 +4,10 @@ package net.psforever.objects.serverobject.locks
import akka.actor.Actor import akka.actor.Actor
import net.psforever.objects.{GlobalDefinitions, SimpleItem} import net.psforever.objects.{GlobalDefinitions, SimpleItem}
import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior} import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
import net.psforever.objects.serverobject.structures.Building import net.psforever.objects.serverobject.structures.Building
import net.psforever.packet.game.HackState1
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
/** /**
@ -18,8 +19,8 @@ class IFFLockControl(lock: IFFLock)
extends Actor extends Actor
with FactionAffinityBehavior.Check with FactionAffinityBehavior.Check
with HackableBehavior.GenericHackable { with HackableBehavior.GenericHackable {
def FactionObject: FactionAffinity = lock def FactionObject: IFFLock = lock
def HackableObject = lock def HackableObject: IFFLock = lock
def receive: Receive = def receive: Receive =
checkBehavior checkBehavior
@ -28,16 +29,17 @@ class IFFLockControl(lock: IFFLock)
case CommonMessages.Use(player, Some(item: SimpleItem)) case CommonMessages.Use(player, Some(item: SimpleItem))
if item.Definition == GlobalDefinitions.remote_electronics_kit => if item.Definition == GlobalDefinitions.remote_electronics_kit =>
if (lock.Faction != player.Faction) { if (lock.Faction != player.Faction) {
// 300 / 1
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, lock), GenericHackables.GetHackSpeed(player, lock),
GenericHackables.FinishHacking(lock, player, 1114636288L), GenericHackables.FinishHacking(lock, player, hackValue = 60, hackClearValue = 60),
GenericHackables.HackingTickAction(progressType = 1, player, lock, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, lock, item.GUID)
) )
} else if (lock.Faction == player.Faction && lock.HackedBy.nonEmpty) { } else if (lock.Faction == player.Faction && lock.HackedBy.nonEmpty) {
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, lock), GenericHackables.GetHackSpeed(player, lock),
IFFLocks.FinishResecuringIFFLock(lock), IFFLocks.FinishResecuringIFFLock(lock),
GenericHackables.HackingTickAction(progressType = 1, player, lock, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, lock, item.GUID)
) )
} else { } else {
val log = org.log4s.getLogger val log = org.log4s.getLogger

View file

@ -4,8 +4,9 @@ package net.psforever.objects.serverobject.mblocker
import akka.actor.Actor import akka.actor.Actor
import net.psforever.objects.{GlobalDefinitions, SimpleItem} import net.psforever.objects.{GlobalDefinitions, SimpleItem}
import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior} import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
import net.psforever.packet.game.HackState1
/** /**
* An `Actor` that handles messages being dispatched to a specific `Locker`. * An `Actor` that handles messages being dispatched to a specific `Locker`.
@ -15,8 +16,8 @@ class LockerControl(locker: Locker)
extends Actor extends Actor
with FactionAffinityBehavior.Check with FactionAffinityBehavior.Check
with HackableBehavior.GenericHackable { with HackableBehavior.GenericHackable {
def FactionObject: FactionAffinity = locker def FactionObject: Locker = locker
def HackableObject = locker def HackableObject: Locker = locker
def receive: Receive = def receive: Receive =
checkBehavior checkBehavior
@ -28,8 +29,8 @@ class LockerControl(locker: Locker)
if (locker.Faction != player.Faction && locker.HackedBy.isEmpty) { if (locker.Faction != player.Faction && locker.HackedBy.isEmpty) {
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, locker), GenericHackables.GetHackSpeed(player, locker),
GenericHackables.FinishHacking(locker, player, 3212836864L), GenericHackables.FinishHacking(locker, player, hackValue = -1, hackClearValue = -1),
GenericHackables.HackingTickAction(progressType = 1, player, locker, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, locker, item.GUID)
) )
} }
case _ => ; case _ => ;

View file

@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.terminals
import akka.actor.{ActorRef, Cancellable} import akka.actor.{ActorRef, Cancellable}
import net.psforever.objects.sourcing.AmenitySource import net.psforever.objects.sourcing.AmenitySource
import net.psforever.packet.game.HackState1
import org.log4s.Logger import org.log4s.Logger
import scala.annotation.unused import scala.annotation.unused
@ -73,8 +74,8 @@ class ProximityTerminalControl(term: Terminal with ProximityUnit)
case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && term.HackedBy.isEmpty => case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && term.HackedBy.isEmpty =>
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, term), GenericHackables.GetHackSpeed(player, term),
GenericHackables.FinishHacking(term, player, 3212836864L), GenericHackables.FinishHacking(term, player, hackValue = -1, hackClearValue = -1),
GenericHackables.HackingTickAction(progressType = 1, player, term, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, term, item.GUID)
) )
case _ => ; case _ => ;
} }

View file

@ -11,6 +11,7 @@ import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBe
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity} import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity}
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl} import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl}
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.HackState1
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.{LocalAction, LocalServiceMessage}
@ -48,10 +49,11 @@ class TerminalControl(term: Terminal)
//TODO setup certifications check //TODO setup certifications check
term.Owner match { term.Owner match {
case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && term.HackedBy.isEmpty => case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && term.HackedBy.isEmpty =>
//order terminals are 90 / 1, or 60 / ?
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, term), GenericHackables.GetHackSpeed(player, term),
GenericHackables.FinishHacking(term, player, 3212836864L), GenericHackables.FinishHacking(term, player, hackValue = -1, hackClearValue = -1),
GenericHackables.HackingTickAction(progressType = 1, player, term, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, term, item.GUID)
) )
case _ => () case _ => ()
} }

View file

@ -1,9 +1,7 @@
package net.psforever.objects.serverobject.terminals.capture package net.psforever.objects.serverobject.terminals.capture
import akka.actor.Actor.Receive import akka.actor.Actor.Receive
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.structures.Amenity import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import scala.annotation.unused import scala.annotation.unused
@ -24,28 +22,7 @@ trait CaptureTerminalAwareBehavior {
protected def captureTerminalIsResecured(@unused terminal: CaptureTerminal): Unit = { /* intentionally blank */ } protected def captureTerminalIsResecured(@unused terminal: CaptureTerminal): Unit = { /* intentionally blank */ }
protected def captureTerminalIsHacked(@unused terminal: CaptureTerminal): Unit = { protected def captureTerminalIsHacked(@unused terminal: CaptureTerminal): Unit = { /* intentionally blank */ }
// Remove seated occupants for mountables
CaptureTerminalAwareObject match {
case mountable: Mountable =>
val guid = mountable.GUID
val zone = mountable.Zone
val zoneId = zone.id
val events = zone.VehicleEvents
mountable.Seats.values.zipWithIndex.foreach {
case (seat, seat_num) =>
seat.occupant.collect {
case player =>
seat.unmount(player)
player.VehicleSeated = None
if (player.HasGUID) {
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, seat_num, unk2=true, guid))
}
}
}
case _ => ()
}
}
} }
object CaptureTerminalAwareBehavior { object CaptureTerminalAwareBehavior {

View file

@ -3,16 +3,17 @@ package net.psforever.objects.serverobject.terminals.capture
import akka.actor.Actor import akka.actor.Actor
import net.psforever.objects.serverobject.CommonMessages import net.psforever.objects.serverobject.CommonMessages
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior} import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior} import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior}
import net.psforever.objects.{GlobalDefinitions, SimpleItem} import net.psforever.objects.{GlobalDefinitions, SimpleItem}
import net.psforever.packet.game.HackState1
class CaptureTerminalControl(terminal: CaptureTerminal) class CaptureTerminalControl(terminal: CaptureTerminal)
extends Actor extends Actor
with FactionAffinityBehavior.Check with FactionAffinityBehavior.Check
with HackableBehavior.GenericHackable { with HackableBehavior.GenericHackable {
def FactionObject: FactionAffinity = terminal def FactionObject: CaptureTerminal = terminal
def HackableObject = terminal def HackableObject: CaptureTerminal = terminal
def receive: Receive = def receive: Receive =
checkBehavior checkBehavior
@ -27,11 +28,11 @@ class CaptureTerminalControl(terminal: CaptureTerminal)
if (canHack) { if (canHack) {
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, terminal), GenericHackables.GetHackSpeed(player, terminal),
CaptureTerminals.FinishHackingCaptureConsole(terminal, player, 3212836864L), CaptureTerminals.FinishHackingCaptureConsole(terminal, player, unk = -1),
GenericHackables.HackingTickAction(progressType = 1, player, terminal, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, terminal, item.GUID)
) )
} }
case _ => ; //no default message case _ => () //no default message
} }
} }

View file

@ -20,16 +20,16 @@ object CaptureTerminals {import scala.concurrent.duration._
* @see `HackMessage` * @see `HackMessage`
*/ */
//TODO add params here depending on which params in HackMessage are important //TODO add params here depending on which params in HackMessage are important
def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Long)(): Unit = { def FinishHackingCaptureConsole(target: CaptureTerminal, hackingPlayer: Player, unk: Int)(): Unit = {
import akka.pattern.ask import akka.pattern.ask
log.info(s"${hackingPlayer.toString} hacked a ${target.Definition.Name}")
// Wait for the target actor to set the HackedBy property // Wait for the target actor to set the HackedBy property
import scala.concurrent.ExecutionContext.Implicits.global import scala.concurrent.ExecutionContext.Implicits.global
ask(target.Actor, CommonMessages.Hack(hackingPlayer, target))(timeout = 2 second) ask(target.Actor, CommonMessages.Hack(hackingPlayer, target))(timeout = 2 second)
.mapTo[CommonMessages.EntityHackState] .mapTo[CommonMessages.EntityHackState]
.onComplete { .onComplete {
case Success(_) => case Success(_) =>
log.info(s"${hackingPlayer.toString} hacked a ${target.Definition.Name}")
val zone = target.Zone val zone = target.Zone
val zoneid = zone.id val zoneid = zone.id
val events = zone.LocalEvents val events = zone.LocalEvents

View file

@ -0,0 +1,39 @@
// Copyright (c) 2024 PSForever
package net.psforever.objects.serverobject.terminals.implant
import akka.actor.ActorRef
import net.psforever.objects.Player
import net.psforever.objects.serverobject.hackable.{GenericHackables, Hackable}
import net.psforever.objects.serverobject.structures.Amenity
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl}
import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideGUID
object ImplantInterfaceControl {
private def FindPairedTerminalMech(
zone: Zone,
interfaceGuid: PlanetSideGUID
): Option[Amenity with Hackable] = {
zone
.map
.terminalToInterface
.find { case (_, guid) => guid == interfaceGuid.guid }
.flatMap { case (mechGuid, _) => zone.GUID(mechGuid) }
.collect { case mech: ImplantTerminalMech if !mech.Destroyed && mech.HackedBy.isEmpty => mech }
}
}
class ImplantInterfaceControl(private val terminal: Terminal)
extends TerminalControl(terminal) {
override def performHack(player: Player, data: Option[Any], replyTo: ActorRef): Unit = {
HackableObject.HackedBy
.orElse {
super.performHack(player, data, replyTo)
ImplantInterfaceControl
.FindPairedTerminalMech(terminal.Zone, terminal.GUID)
.foreach(GenericHackables.FinishHacking(_, player, hackValue = -1, hackClearValue = -1)())
None
}
}
}

View file

@ -0,0 +1,25 @@
// Copyright (c) 2024 PSForever
package net.psforever.objects.serverobject.terminals.implant
import akka.actor.ActorContext
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalDefinition}
import net.psforever.types.Vector3
object ImplantTerminalInterface {
/**
* Instantiate and configure a `Terminal` object
* @param pdef `ObjectDefinition` that constructs this object and maintains some of its immutable fields
* @param pos position
* @param id the unique id that will be assigned to this entity
* @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `Terminal` object
*/
def Constructor(pos: Vector3, pdef: TerminalDefinition)(id: Int, context: ActorContext): Terminal = {
import akka.actor.Props
val obj = Terminal(pdef)
obj.Position = pos
obj.Actor = context.actorOf(Props(classOf[ImplantInterfaceControl], obj), s"${obj.Definition.Name}_$id")
obj
}
}

View file

@ -1,25 +1,47 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.terminals.implant package net.psforever.objects.serverobject.terminals.implant
import akka.actor.ActorRef
import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior import net.psforever.objects.serverobject.affinity.FactionAffinityBehavior
import net.psforever.objects.serverobject.damage.Damageable.Target import net.psforever.objects.serverobject.damage.Damageable.Target
import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity, DamageableMountable} import net.psforever.objects.serverobject.damage.{Damageable, DamageableEntity, DamageableMountable}
import net.psforever.objects.serverobject.hackable.{GenericHackables, HackableBehavior} import net.psforever.objects.serverobject.hackable.{GenericHackables, Hackable, HackableBehavior}
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior} import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity, RepairableEntity} import net.psforever.objects.serverobject.repair.{AmenityAutoRepair, RepairableAmenity, RepairableEntity}
import net.psforever.objects.serverobject.structures.{Building, PoweredAmenityControl} import net.psforever.objects.serverobject.structures.{Amenity, Building, PoweredAmenityControl}
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminalAwareBehavior import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, CaptureTerminalAwareBehavior}
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.objects.zones.Zone
import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem} import net.psforever.objects.{GlobalDefinitions, Player, SimpleItem}
import net.psforever.packet.game.HackState1
import net.psforever.services.local.{LocalAction, LocalServiceMessage}
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID}
import scala.annotation.unused
object ImplantTerminalMechControl {
private def FindPairedTerminalInterface(
zone: Zone,
mechGuid: PlanetSideGUID
): Option[Amenity with Hackable] = {
zone
.map
.terminalToInterface
.find { case (guid, _) => guid == mechGuid.guid }
.flatMap { case (_, interfaceGuid) => zone.GUID(interfaceGuid) }
.collect { case terminal: Terminal if !terminal.Destroyed && terminal.HackedBy.isEmpty => terminal }
}
}
/** /**
* An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`. * An `Actor` that handles messages being dispatched to a specific `ImplantTerminalMech`.
* @param mech the "mech" object being governed * @param mech the "mech" object being governed
*/ */
class ImplantTerminalMechControl(mech: ImplantTerminalMech) class ImplantTerminalMechControl(mech: ImplantTerminalMech)
extends PoweredAmenityControl extends PoweredAmenityControl
with FactionAffinityBehavior.Check with FactionAffinityBehavior.Check
with MountableBehavior with MountableBehavior
with HackableBehavior.GenericHackable with HackableBehavior.GenericHackable
@ -41,9 +63,11 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
.orElse(takesDamage) .orElse(takesDamage)
.orElse(canBeRepairedByNanoDispenser) .orElse(canBeRepairedByNanoDispenser)
.orElse(autoRepairBehavior) .orElse(autoRepairBehavior)
.orElse(captureTerminalAwareBehaviour)
def poweredStateLogic : Receive = def poweredStateLogic : Receive =
commonBehavior commonBehavior
.orElse(hackableBehavior)
.orElse(mountBehavior) .orElse(mountBehavior)
.orElse { .orElse {
case CommonMessages.Use(player, Some(item: SimpleItem)) case CommonMessages.Use(player, Some(item: SimpleItem))
@ -53,18 +77,19 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && mech.HackedBy.isEmpty => case b: Building if (b.Faction != player.Faction || b.CaptureTerminalIsHacked) && mech.HackedBy.isEmpty =>
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, mech), GenericHackables.GetHackSpeed(player, mech),
GenericHackables.FinishHacking(mech, player, 3212836864L), GenericHackables.FinishHacking(mech, player, hackValue = -1, hackClearValue = -1),
GenericHackables.HackingTickAction(progressType = 1, player, mech, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, mech, item.GUID)
) )
case _ => ; case _ => ()
} }
case _ => ; case _ => ()
} }
def unpoweredStateLogic: Receive = def unpoweredStateLogic: Receive =
commonBehavior commonBehavior
.orElse(hackableBehavior)
.orElse { .orElse {
case _ => ; case _ => ()
} }
override protected def mountTest( override protected def mountTest(
@ -120,14 +145,11 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
val zoneId = zone.id val zoneId = zone.id
val events = zone.VehicleEvents val events = zone.VehicleEvents
mech.Seats.values.foreach(seat => mech.Seats.values.foreach(seat =>
seat.occupant match { seat.occupant.collect {
case Some(player) => case player =>
seat.unmount(player) seat.unmount(player)
player.VehicleSeated = None player.VehicleSeated = None
if (player.HasGUID) { events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2=false, guid))
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, guid))
}
case None => ;
} }
) )
} }
@ -140,4 +162,123 @@ class ImplantTerminalMechControl(mech: ImplantTerminalMech)
super.Restoration(obj) super.Restoration(obj)
RepairableAmenity.RestorationOfHistory(obj) RepairableAmenity.RestorationOfHistory(obj)
} }
override def performHack(player: Player, data: Option[Any], replyTo: ActorRef): Unit = {
//todo don't now how to properly hack this amenity
super.performHack(player, data, replyTo)
val zone = HackableObject.Zone
val guid = HackableObject.GUID
val localFaction = mech.Faction
val events = zone.LocalEvents
if (player.Faction == localFaction) {
if (mech.Owner.asInstanceOf[Building].CaptureTerminalIsHacked) {
//this is actually futile, as a hacked base does not grant access to the terminal
events ! LocalServiceMessage(localFaction.toString, LocalAction.SetEmpire(guid, localFaction))
}
kickAllOccupantsNotOfFaction(zone, guid, mech, localFaction)
} else {
opposingFactionsMayAccess(zone, guid, localFaction)
kickAllOccupantsOfFaction(zone, guid, mech, localFaction)
}
ImplantTerminalMechControl
.FindPairedTerminalInterface(zone, guid)
.foreach(GenericHackables.FinishHacking(_, player, hackValue = -1, hackClearValue = -1)())
}
override def performClearHack(data: Option[Any], replyTo: ActorRef): Unit = {
//todo don't now how to properly unhack this amenity
HackableObject.HackedBy.collect { _ =>
super.performClearHack(data, replyTo)
val toFaction = HackableObject.Faction
val zone = HackableObject.Zone
val guid = HackableObject.GUID
noAccessByOpposingFactions(zone, guid, toFaction)
kickAllOccupantsNotOfFaction(zone, guid, mech, toFaction)
}
}
override protected def captureTerminalIsHacked(@unused terminal: CaptureTerminal): Unit = {
//todo don't now how to properly handle a hacked mech
super.captureTerminalIsHacked(terminal)
val zone = HackableObject.Zone
val guid = HackableObject.GUID
kickAllOccupantsNotOfFactionWithTest(zone, guid, mech, (_: PlanetSideEmpire.Value) => { true })
}
override protected def captureTerminalIsResecured(terminal: CaptureTerminal): Unit = {
//todo don't now how to properly handle a hacked mech
super.captureTerminalIsResecured(terminal)
//if hacked, correct
val zone = HackableObject.Zone
val guid = HackableObject.GUID
val toFaction = HackableObject.Faction
HackableObject.HackedBy.collect {
case hackInfo if hackInfo.hackerFaction != toFaction =>
opposingFactionsMayAccess(zone, guid, toFaction)
}
}
private def opposingFactionsMayAccess(
zone: Zone,
guid: PlanetSideGUID,
setToFaction: PlanetSideEmpire.Value
): Unit = {
val events = zone.LocalEvents
opposingFactionsAre(setToFaction).foreach { faction =>
events ! LocalServiceMessage(faction.toString, LocalAction.SetEmpire(guid, faction))
}
}
private def noAccessByOpposingFactions(
zone: Zone,
guid: PlanetSideGUID,
setToFaction: PlanetSideEmpire.Value
): Unit = {
val events = zone.LocalEvents
opposingFactionsAre(setToFaction).foreach { faction =>
events ! LocalServiceMessage(faction.toString, LocalAction.SetEmpire(guid, setToFaction))
}
}
private def opposingFactionsAre(faction: PlanetSideEmpire.Value): PlanetSideEmpire.ValueSet = {
PlanetSideEmpire
.values
.filterNot { f => f == PlanetSideEmpire.NEUTRAL && f == faction }
}
private def kickAllOccupantsOfFaction(
zone: Zone,
guid: PlanetSideGUID,
obj: Mountable,
isFaction: PlanetSideEmpire.Value
): Unit = {
kickAllOccupantsNotOfFactionWithTest(zone, guid, obj, (a: PlanetSideEmpire.Value) => { a == isFaction })
}
private def kickAllOccupantsNotOfFaction(
zone: Zone,
guid: PlanetSideGUID,
obj: Mountable,
isFaction: PlanetSideEmpire.Value
): Unit = {
kickAllOccupantsNotOfFactionWithTest(zone, guid, obj, (a: PlanetSideEmpire.Value) => { a != isFaction })
}
private def kickAllOccupantsNotOfFactionWithTest(
zone: Zone,
guid: PlanetSideGUID,
obj: Mountable,
test: PlanetSideEmpire.Value => Boolean
): Unit = {
val zoneId = zone.id
val events = zone.LocalEvents
obj.Seats.values.foreach(seat =>
seat.occupant.collect {
case player if test(player.Faction) =>
seat.unmount(player)
player.VehicleSeated = None
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = false, guid))
}
)
}
} }

View file

@ -13,7 +13,7 @@ import net.psforever.objects.serverobject.terminals.capture.{CaptureTerminal, Ca
import net.psforever.objects.serverobject.turret.auto.AutomatedTurret.Target import net.psforever.objects.serverobject.turret.auto.AutomatedTurret.Target
import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret, AutomatedTurretBehavior} import net.psforever.objects.serverobject.turret.auto.{AffectedByAutomaticTurretFire, AutomatedTurret, AutomatedTurretBehavior}
import net.psforever.objects.vital.interaction.DamageResult import net.psforever.objects.vital.interaction.DamageResult
import net.psforever.packet.game.ChangeFireModeMessage import net.psforever.packet.game.{ChangeFireModeMessage, HackState1}
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.vehicle.support.TurretUpgrader import net.psforever.services.vehicle.support.TurretUpgrader
import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage} import net.psforever.services.vehicle.{VehicleAction, VehicleServiceMessage}
@ -67,7 +67,7 @@ class FacilityTurretControl(turret: FacilityTurret)
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
1.25f, 1.25f,
WeaponTurrets.FinishUpgradingMannedTurret(TurretObject, player, item, upgrade), WeaponTurrets.FinishUpgradingMannedTurret(TurretObject, player, item, upgrade),
WeaponTurrets.TurretUpgradingTickAction(progressType = 2, player, TurretObject, item.GUID) WeaponTurrets.TurretUpgradingTickAction(HackState1.Unk2, player, TurretObject, item.GUID)
) )
} }
case TurretUpgrader.UpgradeCompleted(_) => case TurretUpgrader.UpgradeCompleted(_) =>
@ -330,6 +330,21 @@ class FacilityTurretControl(turret: FacilityTurret)
} }
override protected def captureTerminalIsHacked(terminal: CaptureTerminal): Unit = { override protected def captureTerminalIsHacked(terminal: CaptureTerminal): Unit = {
super.captureTerminalIsHacked(terminal)
// Remove seated occupants
val guid = turret.GUID
val zone = turret.Zone
val zoneId = zone.id
val events = zone.VehicleEvents
turret.Seats.values.zipWithIndex.foreach {
case (seat, seat_num) =>
seat.occupant.collect {
case player =>
seat.unmount(player)
player.VehicleSeated = None
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, seat_num, unk2=true, guid))
}
}
captureTerminalChanges(terminal, super.captureTerminalIsHacked, actionDelays = 3000L) captureTerminalChanges(terminal, super.captureTerminalIsHacked, actionDelays = 3000L)
} }

View file

@ -5,7 +5,7 @@ import net.psforever.objects.avatar.Certification
import net.psforever.objects.ce.Deployable import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.hackable.GenericHackables.updateTurretUpgradeTime import net.psforever.objects.serverobject.hackable.GenericHackables.updateTurretUpgradeTime
import net.psforever.objects.{Player, Tool, TurretDeployable} import net.psforever.objects.{Player, Tool, TurretDeployable}
import net.psforever.packet.game.{HackMessage, HackState, InventoryStateMessage} import net.psforever.packet.game.{HackMessage, HackState, HackState1, HackState7, InventoryStateMessage}
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage} import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
import net.psforever.services.local.{LocalAction, LocalServiceMessage} import net.psforever.services.local.{LocalAction, LocalServiceMessage}
@ -73,26 +73,27 @@ object WeaponTurrets {
* @return `true`, if the next cycle of progress should occur; * @return `true`, if the next cycle of progress should occur;
* `false`, otherwise * `false`, otherwise
*/ */
def TurretUpgradingTickAction(progressType: Int, tplayer: Player, turret: FacilityTurret, tool_guid: PlanetSideGUID)( def TurretUpgradingTickAction(progressType: HackState1, tplayer: Player, turret: FacilityTurret, tool_guid: PlanetSideGUID)(
progress: Float progress: Float
): Boolean = { ): Boolean = {
//hack state for progress bar visibility val (progressState, progressGrade) = if (progress <= 0L) {
val vis = if (progress <= 0L) { (HackState.Start, 0)
HackState.Start
} else if (progress >= 100L) { } else if (progress >= 100L) {
HackState.Finished (HackState.Finished, 100)
} else if (turret.Destroyed) {
(HackState.Cancelled, 0)
} else { } else {
updateTurretUpgradeTime() updateTurretUpgradeTime()
HackState.Ongoing (HackState.Ongoing, progress.toInt)
} }
turret.Zone.AvatarEvents ! AvatarServiceMessage( turret.Zone.AvatarEvents ! AvatarServiceMessage(
tplayer.Name, tplayer.Name,
AvatarAction.SendResponse( AvatarAction.SendResponse(
Service.defaultPlayerGUID, Service.defaultPlayerGUID,
HackMessage(progressType, turret.GUID, tplayer.GUID, progress.toInt, 0L, vis, 8L) HackMessage(progressType, turret.GUID, tplayer.GUID, progressGrade, -1f, progressState, HackState7.Unk8)
) )
) )
vis != HackState.Cancelled progressState != HackState.Cancelled
} }
def FinishHackingTurretDeployable(target: TurretDeployable, hacker: Player)(): Unit = { def FinishHackingTurretDeployable(target: TurretDeployable, hacker: Player)(): Unit = {

View file

@ -179,8 +179,8 @@ class VehicleControl(vehicle: Vehicle)
if (vehicle.Faction != player.Faction) { if (vehicle.Faction != player.Faction) {
sender() ! CommonMessages.Progress( sender() ! CommonMessages.Progress(
GenericHackables.GetHackSpeed(player, vehicle), GenericHackables.GetHackSpeed(player, vehicle),
Vehicles.FinishHackingVehicle(vehicle, player, 3212836864L), Vehicles.FinishHackingVehicle(vehicle, player),
GenericHackables.HackingTickAction(progressType = 1, player, vehicle, item.GUID) GenericHackables.HackingTickAction(HackState1.Unk1, player, vehicle, item.GUID)
) )
} }

View file

@ -1,10 +1,52 @@
// Copyright (c) 2017 PSForever // Copyright (c) 2017 PSForever
package net.psforever.packet.game package net.psforever.packet.game
import enumeratum.values.{IntEnum, IntEnumEntry}
import net.psforever.packet.GamePacketOpcode.Type
import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket}
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import scodec.Codec import scodec.bits.BitVector
import scodec.{Attempt, Codec}
import scodec.codecs._ import scodec.codecs._
import shapeless.{::, HNil}
sealed abstract class HackState1(val value: Int) extends IntEnumEntry
object HackState1 extends IntEnum[HackState1] {
val values: IndexedSeq[HackState1] = findValues
case object Unk0 extends HackState1(value = 0)
case object Unk1 extends HackState1(value = 1)
case object Unk2 extends HackState1(value = 2)
case object Unk3 extends HackState1(value = 3)
implicit val codec: Codec[HackState1] = PacketHelpers.createIntEnumCodec(this, uint2)
}
sealed abstract class HackState7(val value: Int) extends IntEnumEntry
object HackState7 extends IntEnum[HackState7] {
val values: IndexedSeq[HackState7] = findValues
case object Unk0 extends HackState7(value = 0)
case object Unk1 extends HackState7(value = 1)
case object Unk2 extends HackState7(value = 2)
case object Unk3 extends HackState7(value = 3)
case object Unk4 extends HackState7(value = 4)
case object Unk5 extends HackState7(value = 5)
case object Unk6 extends HackState7(value = 6)
case object Unk7 extends HackState7(value = 7)
case object Unk8 extends HackState7(value = 8)
implicit val codec: Codec[HackState7] = (PacketHelpers.createIntEnumCodec(this, uint8) :: ignore(size = 24)).xmap[HackState7](
{
case a :: _ :: HNil => a
},
{
a => a :: () :: HNil
}
)
}
/** /**
* An `Enumeration` of the various states and activities of the hacking process. * An `Enumeration` of the various states and activities of the hacking process.
@ -16,12 +58,21 @@ import scodec.codecs._
* `Hacked` modifies the target of the hack.<br> * `Hacked` modifies the target of the hack.<br>
* `HackCleared` modifies the target of the hack, opposite of `Hacked`. * `HackCleared` modifies the target of the hack, opposite of `Hacked`.
*/ */
object HackState extends Enumeration { sealed abstract class HackState(val value: Int) extends IntEnumEntry
type Type = Value
val Unknown0, Start, Cancelled, Ongoing, Finished, Unknown5, Hacked, HackCleared = Value object HackState extends IntEnum[HackState] {
val values: IndexedSeq[HackState] = findValues
implicit val codec = PacketHelpers.createEnumerationCodec(this, uint8L) case object Unknown0 extends HackState(value = 0)
case object Start extends HackState(value = 1)
case object Cancelled extends HackState(value = 2)
case object Ongoing extends HackState(value = 3)
case object Finished extends HackState(value = 4)
case object Unknown5 extends HackState(value = 5)
case object Hacked extends HackState(value = 6)
case object HackCleared extends HackState(value = 7)
implicit val codec: Codec[HackState] = PacketHelpers.createIntEnumCodec(this, uint8L)
} }
/** /**
@ -44,11 +95,12 @@ object HackState extends Enumeration {
* As mentioned, one of the unexpected uses of this message * As mentioned, one of the unexpected uses of this message
* will assist the conversion of allied facility turreted weapons to their upgraded armaments. * will assist the conversion of allied facility turreted weapons to their upgraded armaments.
* @param unk1 na; * @param unk1 na;
* 0 commonly; * 0 commonly;
* 2 when performing (phalanx) upgrades; * 1 unknown;
* 3 for building objects during login phase; * 2 when performing (phalanx) upgrades;
* hack type? * 3 for building objects during login phase;
* possibly player hacking level 0-3? * hack type?
* possibly player hacking level 0-3?
* @param target_guid the target of the hack * @param target_guid the target of the hack
* @param player_guid the player * @param player_guid the player
* @param progress the amount of progress visible; * @param progress the amount of progress visible;
@ -58,31 +110,44 @@ object HackState extends Enumeration {
* doesn't seem to be `char_id`? * doesn't seem to be `char_id`?
* @param hack_state hack state * @param hack_state hack state
* @param unk7 na; * @param unk7 na;
* usually 8;
* values 3-7 noted for the Hacked state;
* 5 - boost pain field at matrixing terminal? * 5 - boost pain field at matrixing terminal?
* usually, 8?
*/ */
final case class HackMessage( final case class HackMessage(
unk1: Int, unk1: HackState1,
target_guid: PlanetSideGUID, target_guid: PlanetSideGUID,
player_guid: PlanetSideGUID, player_guid: PlanetSideGUID,
progress: Int, progress: Int,
unk5: Long, unk5: Float,
hack_state: HackState.Value, hack_state: HackState,
unk7: Long unk7: HackState7
) extends PlanetSideGamePacket { ) extends PlanetSideGamePacket {
type Packet = HackMessage type Packet = HackMessage
def opcode = GamePacketOpcode.HackMessage def opcode: Type = GamePacketOpcode.HackMessage
def encode = HackMessage.encode(this) def encode: Attempt[BitVector] = HackMessage.encode(this)
} }
object HackMessage extends Marshallable[HackMessage] { object HackMessage extends Marshallable[HackMessage] {
def apply(
unk1: HackState1,
target_guid: PlanetSideGUID,
player_guid: PlanetSideGUID,
progress: Int,
unk5: Int,
hack_state: HackState,
unk7: HackState7
): HackMessage = {
new HackMessage(unk1, target_guid, player_guid, progress, unk5.toFloat, hack_state, unk7)
}
implicit val codec: Codec[HackMessage] = ( implicit val codec: Codec[HackMessage] = (
("unk1" | uint2L) :: ("unk1" | HackState1.codec) ::
("object_guid" | PlanetSideGUID.codec) :: ("object_guid" | PlanetSideGUID.codec) ::
("player_guid" | PlanetSideGUID.codec) :: ("player_guid" | PlanetSideGUID.codec) ::
("progress" | uint8L) :: ("progress" | uint8L) ::
("unk5" | uint32L) :: ("unk5" | floatL) ::
("hack_state" | HackState.codec) :: ("hack_state" | HackState.codec) ::
("unk7" | uint32L) ("unk7" | HackState7.codec)
).as[HackMessage] ).as[HackMessage]
} }

View file

@ -96,10 +96,10 @@ class LocalService(zone: Zone) extends Actor {
LocalResponse.SendHackMessageHackCleared(target.GUID, unk1, unk2) LocalResponse.SendHackMessageHackCleared(target.GUID, unk1, unk2)
) )
) )
case LocalAction.HackTemporarily(player_guid, _, target, unk1, duration, unk2) => case LocalAction.HackTemporarily(player_guid, _, target, hackValue, hackClear, duration, unk2) =>
hackClearer ! HackClearActor.ObjectIsHacked(target, zone, unk1, unk2, duration) hackClearer ! HackClearActor.ObjectIsHacked(target, zone, hackClear, unk2, duration)
LocalEvents.publish( LocalEvents.publish(
LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.HackObject(target.GUID, unk1, unk2)) LocalServiceResponse(s"/$forChannel/Local", player_guid, LocalResponse.HackObject(target.GUID, hackValue, unk2))
) )
case LocalAction.ClearTemporaryHack(_, target) => case LocalAction.ClearTemporaryHack(_, target) =>
hackClearer ! HackClearActor.ObjectIsResecured(target) hackClearer ! HackClearActor.ObjectIsResecured(target)

View file

@ -14,7 +14,7 @@ import net.psforever.objects.{PlanetSideGameObject, TelepadDeployable, Vehicle}
import net.psforever.packet.PlanetSideGamePacket import net.psforever.packet.PlanetSideGamePacket
import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum import net.psforever.packet.game.GenericObjectActionEnum.GenericObjectActionEnum
import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum import net.psforever.packet.game.PlanetsideAttributeEnum.PlanetsideAttributeEnum
import net.psforever.packet.game.{ChatMsg, DeployableInfo, DeploymentAction, GenericAction, TriggeredSound} import net.psforever.packet.game.{ChatMsg, DeployableInfo, DeploymentAction, GenericAction, HackState7, TriggeredSound}
import net.psforever.services.hart.HartTimer.OrbitalShuttleEvent import net.psforever.services.hart.HartTimer.OrbitalShuttleEvent
import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3} import net.psforever.types.{PlanetSideEmpire, PlanetSideGUID, Vector3}
@ -43,15 +43,16 @@ object LocalAction {
pos: Vector3, pos: Vector3,
deletionEffect: Int deletionEffect: Int
) extends Action ) extends Action
final case class HackClear(player_guid: PlanetSideGUID, target: PlanetSideServerObject, unk1: Long, unk2: Long = 8L) final case class HackClear(player_guid: PlanetSideGUID, target: PlanetSideServerObject, unk1: Long, unk2: HackState7 = HackState7.Unk8)
extends Action extends Action
final case class HackTemporarily( final case class HackTemporarily(
player_guid: PlanetSideGUID, player_guid: PlanetSideGUID,
continent: Zone, continent: Zone,
target: PlanetSideServerObject, target: PlanetSideServerObject,
unk1: Long, hackValue: Long,
hackClearValue: Long,
duration: Int, duration: Int,
unk2: Long = 8L unk2: HackState7 = HackState7.Unk8
) extends Action ) extends Action
final case class ClearTemporaryHack(player_guid: PlanetSideGUID, target: PlanetSideServerObject with Hackable) final case class ClearTemporaryHack(player_guid: PlanetSideGUID, target: PlanetSideServerObject with Hackable)
extends Action extends Action

View file

@ -34,8 +34,8 @@ object LocalResponse {
pos: Vector3, pos: Vector3,
deletionEffect: Int deletionEffect: Int
) extends Response ) extends Response
final case class SendHackMessageHackCleared(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response final case class SendHackMessageHackCleared(target_guid: PlanetSideGUID, unk1: Long, unk2: HackState7) extends Response
final case class HackObject(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response final case class HackObject(target_guid: PlanetSideGUID, unk1: Long, unk2: HackState7) extends Response
final case class SendPacket(packet: PlanetSideGamePacket) extends Response final case class SendPacket(packet: PlanetSideGamePacket) extends Response
final case class PlanetsideAttribute(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long) final case class PlanetsideAttribute(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long)

View file

@ -10,7 +10,7 @@ import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal import net.psforever.objects.serverobject.terminals.capture.CaptureTerminal
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.objects.Default import net.psforever.objects.Default
import net.psforever.packet.game.{GenericAction, PlanetsideAttributeEnum} import net.psforever.packet.game.{GenericAction, HackState7, PlanetsideAttributeEnum}
import net.psforever.objects.sourcing.PlayerSource import net.psforever.objects.sourcing.PlayerSource
import net.psforever.services.Service import net.psforever.services.Service
import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction import net.psforever.services.local.support.HackCaptureActor.GetHackingFaction
@ -231,7 +231,7 @@ class HackCaptureActor extends Actor {
} }
NotifyHackStateChange(terminal, isResecured = true) 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. // 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 context.parent ! HackClearActor.SendHackMessageHackCleared(building.GUID, terminal.Zone.id, 3212836864L, HackState7.Unk8) //call up
} }
private def RestartTimer(): Unit = { private def RestartTimer(): Unit = {

View file

@ -2,12 +2,12 @@
package net.psforever.services.local.support package net.psforever.services.local.support
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import akka.actor.{Actor, Cancellable} import akka.actor.{Actor, Cancellable}
import net.psforever.objects.Default import net.psforever.objects.Default
import net.psforever.objects.serverobject.hackable.Hackable import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject} import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
import net.psforever.objects.zones.Zone import net.psforever.objects.zones.Zone
import net.psforever.packet.game.HackState7
import net.psforever.types.PlanetSideGUID import net.psforever.types.PlanetSideGUID
import scala.annotation.tailrec import scala.annotation.tailrec
@ -156,7 +156,7 @@ object HackClearActor {
target: PlanetSideServerObject, target: PlanetSideServerObject,
zone: Zone, zone: Zone,
unk1: Long, unk1: Long,
unk2: Long, unk2: HackState7,
duration: Int, duration: Int,
time: Long = System.currentTimeMillis() time: Long = System.currentTimeMillis()
) )
@ -172,7 +172,7 @@ object HackClearActor {
* @param obj the server object * @param obj the server object
* @param zone_id the zone in which the object resides * @param zone_id the zone in which the object resides
*/ */
final case class SendHackMessageHackCleared(obj: PlanetSideGUID, zone_id: String, unk1: Long, unk2: Long) final case class SendHackMessageHackCleared(obj: PlanetSideGUID, zone_id: String, unk1: Long, unk2: HackState7)
/** /**
* Internal message used to signal a test of the queued door information. * Internal message used to signal a test of the queued door information.
@ -192,7 +192,7 @@ object HackClearActor {
target: PlanetSideServerObject, target: PlanetSideServerObject,
zone: Zone, zone: Zone,
unk1: Long, unk1: Long,
unk2: Long, unk2: HackState7,
time: Long, time: Long,
duration: Long duration: Long
) )

View file

@ -21,7 +21,7 @@ import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad import net.psforever.objects.serverobject.shuttle.OrbitalShuttlePad
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.capture.{CaptureTerminal, CaptureTerminalDefinition}
import net.psforever.objects.serverobject.terminals.implant.ImplantTerminalMech import net.psforever.objects.serverobject.terminals.implant.{ImplantTerminalInterface, ImplantTerminalMech}
import net.psforever.objects.serverobject.tube.SpawnTube import net.psforever.objects.serverobject.tube.SpawnTube
import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition, VanuSentry} import net.psforever.objects.serverobject.turret.{FacilityTurret, FacilityTurretDefinition, VanuSentry}
import net.psforever.objects.serverobject.zipline.ZipLinePath import net.psforever.objects.serverobject.zipline.ZipLinePath
@ -637,7 +637,7 @@ object Zones {
zoneMap.addLocalObject( zoneMap.addLocalObject(
closestTerminal.guid, closestTerminal.guid,
Terminal.Constructor(closestTerminal.position, GlobalDefinitions.implant_terminal_interface), ImplantTerminalInterface.Constructor(closestTerminal.position, GlobalDefinitions.implant_terminal_interface),
owningBuildingGuid = ownerGuid owningBuildingGuid = ownerGuid
) )

View file

@ -14,20 +14,20 @@ class HackMessageTest extends Specification {
"decode" in { "decode" in {
PacketCoding.decodePacket(string).require match { PacketCoding.decodePacket(string).require match {
case HackMessage(unk1, target_guid, player_guid, progress, unk5, hack_state, unk7) => case HackMessage(unk1, target_guid, player_guid, progress, unk5, hack_state, unk7) =>
unk1 mustEqual 0 unk1 mustEqual HackState1.Unk0
target_guid mustEqual PlanetSideGUID(1024) target_guid mustEqual PlanetSideGUID(1024)
player_guid mustEqual PlanetSideGUID(3607) player_guid mustEqual PlanetSideGUID(3607)
progress mustEqual 0 progress mustEqual 0
unk5 mustEqual 3212836864L unk5 mustEqual -1.0f
hack_state mustEqual HackState.Start hack_state mustEqual HackState.Start
unk7 mustEqual 8L unk7 mustEqual HackState7.Unk8
case _ => case _ =>
ko ko
} }
} }
"encode" in { "encode" in {
val msg = HackMessage(0, PlanetSideGUID(1024), PlanetSideGUID(3607), 0, 3212836864L, HackState.Start, 8L) val msg = HackMessage(HackState1.Unk0, PlanetSideGUID(1024), PlanetSideGUID(3607), 0, -1.0f, HackState.Start, HackState7.Unk8)
val pkt = PacketCoding.encodePacket(msg).require.toByteVector val pkt = PacketCoding.encodePacket(msg).require.toByteVector
pkt mustEqual string pkt mustEqual string
} }

View file

@ -136,9 +136,9 @@ class HackClearTest extends ActorTest {
"pass HackClear" in { "pass HackClear" in {
val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service") val service = system.actorOf(Props(classOf[LocalService], Zone.Nowhere), "l_service")
service ! Service.Join("test") service ! Service.Join("test")
service ! LocalServiceMessage("test", LocalAction.HackClear(PlanetSideGUID(10), obj, 0L, 1000L)) service ! LocalServiceMessage("test", LocalAction.HackClear(PlanetSideGUID(10), obj, 0L, HackState7.Unk8))
expectMsg( expectMsg(
LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.SendHackMessageHackCleared(PlanetSideGUID(40), 0L, 1000L)) LocalServiceResponse("/test/Local", PlanetSideGUID(10), LocalResponse.SendHackMessageHackCleared(PlanetSideGUID(40), 0L, HackState7.Unk8))
) )
} }
} }