diff --git a/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala b/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
index 2a1d09965..ff3c29155 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/structures/Building.scala
@@ -1,6 +1,8 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.structures
+import java.util.concurrent.TimeUnit
+
import akka.actor.ActorContext
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.definition.ObjectDefinition
@@ -66,12 +68,13 @@ class Building(private val building_guid : Int, private val map_id : Int, privat
case _ => //we have no silo; we have unlimited power
10
}
- //if we have a capture terminal, get the hack status & time from control console if it exists
+ //if we have a capture terminal, get the hack status & time (in milliseconds) from control console if it exists
val (hacking, hackingFaction, hackTime) : (Boolean, PlanetSideEmpire.Value, Long) = amenities.find(_.Definition == GlobalDefinitions.capture_terminal) match {
case Some(obj: CaptureTerminal with Hackable) =>
obj.HackedBy match {
case Some(Hackable.HackInfo(_, _, hfaction, _, start, length)) =>
- (true, hfaction, math.max(0, start + length - System.nanoTime))
+ val hack_time_remaining_ms = TimeUnit.MILLISECONDS.convert(math.max(0, start + length - System.nanoTime), TimeUnit.NANOSECONDS)
+ (true, hfaction, hack_time_remaining_ms)
case _ =>
(false, PlanetSideEmpire.NEUTRAL, 0L)
}
diff --git a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
index 4e10dca37..eec5c3124 100644
--- a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
@@ -66,6 +66,7 @@ import scodec.codecs._
*
196608 - 262143 - VS
* 17039360 - CC Resecured
*
+ *
These values seem to correspond to the following data structure: Time left - 2 bytes, faction - 1 byte (1-4), isResecured - 1 byte (0-1)
* `24 - Learn certifications with value :`
* 01 : Medium Assault
* 02 : Heavy Assault
diff --git a/common/src/main/scala/services/local/LocalService.scala b/common/src/main/scala/services/local/LocalService.scala
index 07f743877..d5907c2c3 100644
--- a/common/src/main/scala/services/local/LocalService.scala
+++ b/common/src/main/scala/services/local/LocalService.scala
@@ -208,9 +208,6 @@ class LocalService extends Actor {
case scala.util.Failure(_) => log.warn(s"LocalService Failed to get zone when hack timeout was reached")
}
- case HackCaptureActor.GetHackTimeRemainingNanos(capture_console_guid) =>
- hackCapturer forward HackCaptureActor.GetHackTimeRemainingNanos(capture_console_guid)
-
//message to Engineer
case LocalServiceMessage.Deployables(msg) =>
engineer forward msg
diff --git a/common/src/main/scala/services/local/support/HackCaptureActor.scala b/common/src/main/scala/services/local/support/HackCaptureActor.scala
index fd8966351..0a0246160 100644
--- a/common/src/main/scala/services/local/support/HackCaptureActor.scala
+++ b/common/src/main/scala/services/local/support/HackCaptureActor.scala
@@ -71,16 +71,6 @@ class HackCaptureActor extends Actor {
// Restart the timer in case the object we just removed was the next one scheduled
RestartTimer()
-
- case HackCaptureActor.GetHackTimeRemainingNanos(capture_console_guid) =>
- hackedObjects.find(_.target.GUID == capture_console_guid) match {
- case Some(obj: HackCaptureActor.HackEntry) =>
- val time_left: Long = obj.duration.toNanos - (System.nanoTime - obj.hack_timestamp)
- sender ! time_left
- case _ =>
- log.warn(s"Couldn't find capture terminal guid $capture_console_guid in hackedObjects list")
- sender ! 0L
- }
case _ => ;
}
@@ -110,9 +100,6 @@ object HackCaptureActor {
final case class ClearHack(target : CaptureTerminal, zone : Zone)
- final case class GetHackTimeRemainingNanos(capture_console_guid: PlanetSideGUID)
-
-
private final case class ProcessCompleteHacks()
private final case class HackEntry(target : PlanetSideServerObject with Hackable, zone : Zone, unk1 : Long, unk2 : Long, duration: FiniteDuration, hack_timestamp : Long)
diff --git a/common/src/main/scala/services/local/support/HackClearActor.scala b/common/src/main/scala/services/local/support/HackClearActor.scala
index 1399733d7..f1c9f6e1e 100644
--- a/common/src/main/scala/services/local/support/HackClearActor.scala
+++ b/common/src/main/scala/services/local/support/HackClearActor.scala
@@ -66,11 +66,17 @@ class HackClearActor() extends Actor {
if(hackedObjects.length != 0) {
val now = System.nanoTime()
val (unhackObjects, stillHackedObjects) = PartitionEntries(hackedObjects, now)
- val short_timeout : FiniteDuration = math.max(1, stillHackedObjects.head.duration - (now - stillHackedObjects.head.time)) nanoseconds
- log.warn(s"Still items left in hacked objects list. Checking again in ${short_timeout.toSeconds} seconds")
- import scala.concurrent.ExecutionContext.Implicits.global
- clearTrigger = context.system.scheduler.scheduleOnce(short_timeout, self, HackClearActor.TryClearHacks())
+ stillHackedObjects.headOption match {
+ case Some(hackEntry) =>
+ val short_timeout : FiniteDuration = math.max(1, hackEntry.duration - (now - hackEntry.time)) nanoseconds
+
+ log.info(s"HackClearActor: Still items left in hacked objects list. Checking again in ${short_timeout.toSeconds} seconds")
+ import scala.concurrent.ExecutionContext.Implicits.global
+ clearTrigger = context.system.scheduler.scheduleOnce(short_timeout, self, HackClearActor.TryClearHacks())
+ case None => log.info("HackClearActor: No objects left in hacked objects list. Not rescheduling check.")
+ }
+
}
}
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index 4a0e9e838..7b63bb88b 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -1284,23 +1284,27 @@ class WorldSessionActor extends Actor with MDCContextAware {
value = 17039360L
}
else {
- import scala.concurrent.ExecutionContext.Implicits.global
- val future = ask(localService, HackCaptureActor.GetHackTimeRemainingNanos(target_guid))(1 second)
- val time = Await.result(future, 1 second).asInstanceOf[Long]
- // todo: blocking call. Not good.
- val hack_time_remaining_ms = TimeUnit.MILLISECONDS.convert(time, TimeUnit.NANOSECONDS)
- val deciseconds_remaining = (hack_time_remaining_ms / 100)
- val hacking_faction = continent.GUID(target_guid).get.asInstanceOf[Hackable].HackedBy.get.hackerFaction
- // See PlanetSideAttributeMessage #20 documentation for an explanation of how the timer is calculated
- val start_num = hacking_faction match {
- case PlanetSideEmpire.TR => 65536L
- case PlanetSideEmpire.NC => 131072L
- case PlanetSideEmpire.VS => 196608L
- }
- value = start_num + deciseconds_remaining
- }
- sendResponse(PlanetsideAttributeMessage(target_guid, 20, value))
+ continent.GUID(target_guid) match {
+ case Some(capture_terminal: 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))
+ case _ => log.warn("LocalResponse.HackCaptureTerminal: HackedBy not defined")
+ }
+ case _ => log.warn(s"LocalResponse.HackCaptureTerminal: Couldn't find capture terminal with GUID ${target_guid} in zone ${continent.Id}")
+ }
+ }
case LocalResponse.ObjectDelete(object_guid, unk) =>
if(tplayer_guid != guid) {
sendResponse(ObjectDeleteMessage(object_guid, unk))
@@ -3211,7 +3215,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
case Some(container) => //just in case
if(vel.isDefined) {
val guid = player.GUID
- sendResponse(UnuseItemMessage(guid, container.GUID))
+ // If the container is a corpse and gets removed just as this runs it can cause a client disconnect, so we'll check the container has a GUID first.
+ if(container.HasGUID) {
+ sendResponse(UnuseItemMessage(guid, container.GUID))
+ }
sendResponse(UnuseItemMessage(guid, guid))
accessedContainer = None
}