Hacking fixes (#253)

* Remove QoL change to show faction colours on hacked objects as unfortunately it causes side effects like doors opening for the hacker but saying the door is locked

* Only send map updates if the resecured object is a capture terminal

* Centralise logic to check if a Capture Terminal is hacked for a Building object

* Fix hacking a terminal where the base CC has been hacked and add a bit of extra logging for possible edge cases

* Clear all hacks from hacked amenities when the CC is resecured

* Fix AMS terminals being broken

* Clear amenity hacks when CC is both hacked and resecured
This commit is contained in:
Mazo 2019-04-16 14:23:43 +01:00 committed by Fate-JH
parent 6c68bda97c
commit 473d4d14c5
4 changed files with 81 additions and 64 deletions

View file

@ -39,6 +39,14 @@ class Building(private val building_guid : Int, private val map_id : Int, privat
amenities
}
def CaptureConsoleIsHacked : Boolean = {
Amenities.filter(x => x.Definition == GlobalDefinitions.capture_terminal).headOption.asInstanceOf[Option[CaptureTerminal]] match {
case Some(obj: CaptureTerminal) =>
obj.HackedBy.isDefined
case None => false
}
}
def Zone : Zone = zone
def Info : (

View file

@ -4,7 +4,7 @@ package services.local
import akka.actor.{Actor, ActorRef, Props}
import net.psforever.objects.ce.Deployable
import net.psforever.objects.serverobject.resourcesilo.ResourceSilo
import net.psforever.objects.serverobject.structures.Building
import net.psforever.objects.serverobject.structures.{Amenity, Building}
import net.psforever.objects.serverobject.terminals.{CaptureTerminal, ProximityUnit, Terminal}
import net.psforever.objects.zones.{InterstellarCluster, Zone}
import net.psforever.objects._
@ -18,6 +18,7 @@ import services.{GenericEventBus, RemoverActor, Service, ServiceManager}
import scala.util.Success
import scala.concurrent.duration._
import akka.pattern.ask
import net.psforever.objects.serverobject.hackable.Hackable
import net.psforever.objects.vehicles.{Utility, UtilityType}
import services.ServiceManager.Lookup
import services.support.SupportActor
@ -95,6 +96,12 @@ class LocalService extends Actor {
hackClearer ! HackClearActor.ObjectIsResecured(target)
case LocalAction.HackCaptureTerminal(player_guid, zone, target, unk1, unk2, isResecured) =>
// When a CC is hacked (or resecured) all amenities for the base should be unhacked
val hackableAmenities = target.Owner.asInstanceOf[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 {

View file

@ -66,7 +66,8 @@ class HackCaptureActor extends Actor {
case HackCaptureActor.ClearHack(target, _) =>
hackedObjects = hackedObjects.filterNot(x => x.target == target)
target.Owner.Actor ! Building.SendMapUpdate(all_clients = true)
if(target.isInstanceOf[CaptureTerminal]) { target.Owner.Actor ! Building.SendMapUpdate(all_clients = true) }
// Restart the timer in case the object we just removed was the next one scheduled
RestartTimer()

View file

@ -1253,24 +1253,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
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))
// Set the object faction displayed back to it's original owner faction
continent.GUID(target_guid) match {
case Some(obj) =>
sendResponse(SetEmpireMessage(target_guid, obj.asInstanceOf[FactionAffinity].Faction))
case None => ;
}
case LocalResponse.HackObject(target_guid, unk1, unk2) =>
if(tplayer_guid != guid && continent.GUID(target_guid).get.asInstanceOf[Hackable].HackedBy.get.hackerFaction != player.Faction) {
// If the player is not in the faction that hacked this object then send the packet that it's been hacked, so they can either unhack it or use the hacked object
// Don't send this to the faction that hacked the object, otherwise it will interfere with the new SetEmpireMessage QoL change that changes the object colour to their faction (but only visible to that faction)
sendResponse(HackMessage(0, target_guid, guid, 100, unk1, HackState.Hacked, unk2))
}
if(continent.GUID(target_guid).get.asInstanceOf[Hackable].HackedBy.get.hackerFaction == player.Faction) {
// Make the hacked object look like it belongs to the hacking empire, but only for that empire's players (so that infiltrators on stealth missions won't be given away to opposing factions)
sendResponse(SetEmpireMessage(target_guid, player.Faction))
}
case LocalResponse.HackCaptureTerminal(target_guid, unk1, unk2, isResecured) =>
var value = 0L
if(isResecured) {
@ -3802,13 +3786,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
case Some(lock_guid) =>
val lock = continent.GUID(lock_guid).get.asInstanceOf[IFFLock]
var baseIsHacked = false
lock.Owner.asInstanceOf[Building].Amenities.filter(x => x.Definition == GlobalDefinitions.capture_terminal).headOption.asInstanceOf[Option[CaptureTerminal]] match {
case Some(obj: CaptureTerminal) =>
baseIsHacked = obj.HackedBy.isDefined
case None => ;
}
val playerIsOnInside = Vector3.ScalarProjection(lock.Outwards, player.Position - door.Position) < 0f
// If an IFF lock exists and the IFF lock faction doesn't match the current player and one of the following conditions are met open the door:
@ -3816,7 +3793,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
// A base is hacked
// The lock is hacked
// The player is on the inside of the door, determined by the lock orientation
lock.HackedBy.isDefined || baseIsHacked || lock.Faction == PlanetSideEmpire.NEUTRAL || playerIsOnInside
lock.HackedBy.isDefined || lock.Owner.asInstanceOf[Building].CaptureConsoleIsHacked || lock.Faction == PlanetSideEmpire.NEUTRAL || playerIsOnInside
case None => !door.isOpen // If there's no linked IFF lock just open the door if it's closed.
})) {
door.Actor ! Door.Use(player, msg)
@ -3861,6 +3838,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
case _ => ;
}
} else {
log.warn("IFF lock is being hacked, but don't know how to handle this state")
log.warn(s"Lock - HackedBy.isDefined: ${panel.HackedBy.isDefined} Faction: ${panel.Faction} HackedBy.isEmpty: ${panel.HackedBy.isEmpty}")
log.warn(s"Hacking player - Faction: ${player.Faction}")
}
case Some(obj : Player) =>
@ -4043,53 +4024,73 @@ class WorldSessionActor extends Actor with MDCContextAware {
case Some(terminal : Terminal) =>
val tdef = terminal.Definition
val owned = terminal.Faction == player.Faction
val hacked = terminal.HackedBy.nonEmpty
if(owned) {
if(tdef.isInstanceOf[MatrixTerminalDefinition]) {
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
sendResponse(BindPlayerMessage(BindStatus.Bind, "", true, true, SpawnGroup.Sanctuary, 0, 0, terminal.Position))
}
else if(tdef == GlobalDefinitions.multivehicle_rearm_terminal || tdef == GlobalDefinitions.bfr_rearm_terminal ||
tdef == GlobalDefinitions.air_rearm_terminal || tdef == GlobalDefinitions.ground_rearm_terminal) {
FindLocalVehicle match {
case Some(vehicle) =>
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
sendResponse(UseItemMessage(avatar_guid, item_used_guid, vehicle.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, vehicle.Definition.ObjectId))
case None =>
log.error("UseItem: expected seated vehicle, but found none")
}
}
else if(tdef == GlobalDefinitions.teleportpad_terminal) {
//explicit request
terminal.Actor ! Terminal.Request(
player,
ItemTransactionMessage(object_guid, TransactionType.Buy, 0, "router_telepad", 0, PlanetSideGUID(0))
)
}
else {
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
}
// If the base this terminal belongs to has been hacked the owning faction needs to be able to hack it to gain access
val ownerIsHacked = terminal.Owner match {
case b: Building => b.CaptureConsoleIsHacked
case _ => false
}
else if(hacked) {
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
}
else {
player.Slot(player.DrawnSlot).Equipment match {
case Some(tool: SimpleItem) =>
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
var playerIsHacking = false
player.Slot(player.DrawnSlot).Equipment match {
case Some(tool: SimpleItem) =>
if (tool.Definition == GlobalDefinitions.remote_electronics_kit) {
if (!terminal.HackedBy.isEmpty) {
log.warn("Player tried to hack a terminal that is already hacked")
log.warn(s"Player faction ${player.Faction} terminal faction: ${terminal.Faction} terminal hacked: ${terminal.HackedBy.isDefined} owner hacked: ${ownerIsHacked}")
}
else if (terminal.Faction != player.Faction || ownerIsHacked) {
val hackSpeed = GetPlayerHackSpeed(terminal)
if(hackSpeed > 0) {
if (hackSpeed > 0) {
progressBarValue = Some(-hackSpeed)
self ! WorldSessionActor.HackingProgress(progressType = 1, player, terminal, tool.GUID, hackSpeed, FinishHacking(terminal, 3212836864L))
playerIsHacking = true
log.info("Hacking a terminal")
}
}
case _ => ;
}
}
case _ => ;
}
if(!playerIsHacking) {
if (terminal.Faction == player.Faction) {
if (tdef.isInstanceOf[MatrixTerminalDefinition]) {
//TODO matrix spawn point; for now, just blindly bind to show work (and hope nothing breaks)
sendResponse(BindPlayerMessage(BindStatus.Bind, "", true, true, SpawnGroup.Sanctuary, 0, 0, terminal.Position))
}
else if (tdef == GlobalDefinitions.multivehicle_rearm_terminal || tdef == GlobalDefinitions.bfr_rearm_terminal ||
tdef == GlobalDefinitions.air_rearm_terminal || tdef == GlobalDefinitions.ground_rearm_terminal) {
FindLocalVehicle match {
case Some(vehicle) =>
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
sendResponse(UseItemMessage(avatar_guid, item_used_guid, vehicle.GUID, unk2, unk3, unk4, unk5, unk6, unk7, unk8, vehicle.Definition.ObjectId))
case None =>
log.error("UseItem: expected seated vehicle, but found none")
}
}
else if (tdef == GlobalDefinitions.teleportpad_terminal) {
//explicit request
terminal.Actor ! Terminal.Request(
player,
ItemTransactionMessage(object_guid, TransactionType.Buy, 0, "router_telepad", 0, PlanetSideGUID(0))
)
}
else if (!ownerIsHacked || (ownerIsHacked && terminal.HackedBy.isDefined)) {
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
}
else {
log.warn("Tried to use a terminal, but can't handle this case")
log.warn(s"Terminal - isHacked ${terminal.HackedBy.isDefined} ownerIsHacked ${ownerIsHacked}")
}
}
else if (terminal.HackedBy.isDefined) {
sendResponse(UseItemMessage(avatar_guid, item_used_guid, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
} else {
log.warn("Tried to use a terminal that doesn't belong to this faction and isn't hacked")
log.warn(s"Player faction ${player.Faction} terminal faction: ${terminal.Faction} terminal hacked: ${terminal.HackedBy.isDefined} owner hacked: ${ownerIsHacked}")
}
}
case Some(obj : SpawnTube) =>
//deconstruction
PlayerActionsToCancel()
@ -5157,7 +5158,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case term : CaptureTerminal =>
val isResecured = player.Faction == target.Faction
localService ! LocalServiceMessage(continent.Id, LocalAction.HackCaptureTerminal(player.GUID, continent, term, unk, 8L, isResecured))
case _ =>localService ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk, target.HackEffectDuration(GetPlayerHackLevel())))
case _ => localService ! LocalServiceMessage(continent.Id, LocalAction.HackTemporarily(player.GUID, continent, target, unk, target.HackEffectDuration(GetPlayerHackLevel())))
}
case scala.util.Failure(_) => log.warn(s"Hack message failed on target guid: ${target.GUID}")
}