mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-01-20 02:54:46 +00:00
door hacking now clears in 60s
This commit is contained in:
parent
74b718c536
commit
0a4bac8ab5
|
|
@ -3,7 +3,6 @@ package net.psforever.objects.serverobject.locks
|
|||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.serverobject.CommonMessages
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
|
||||
class IFFLockControl(lock : IFFLock) extends Actor {
|
||||
def receive : Receive = {
|
||||
|
|
@ -11,8 +10,7 @@ class IFFLockControl(lock : IFFLock) extends Actor {
|
|||
lock.HackedBy = player
|
||||
case CommonMessages.ClearHack() =>
|
||||
lock.HackedBy = None
|
||||
case _ =>
|
||||
sender ! Door.NoEvent()
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.zones
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class HackClearActor() extends Actor {
|
||||
import HackClearActor._
|
||||
private var clearTrigger : Cancellable = DefaultClearer
|
||||
private var hackedObjects : List[HackEntry] = Nil
|
||||
//private[this] val log = org.log4s.getLogger
|
||||
|
||||
def receive : Receive = {
|
||||
case ObjectIsHacked(door, zone, unk1, unk2, time) =>
|
||||
hackedObjects = hackedObjects :+ HackEntry(door, zone, unk1, unk2, time)
|
||||
if(hackedObjects.size == 1) {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
clearTrigger = context.system.scheduler.scheduleOnce(timeout, self, HackClearActor.TryClearHacks())
|
||||
}
|
||||
|
||||
case TryClearHacks() =>
|
||||
clearTrigger.cancel
|
||||
val now : Long = System.nanoTime
|
||||
//TODO we can just walk across the list of doors and extract only the first few entries
|
||||
val (unhackObjects, stillHackedObjects) = recursivePartitionHacks(hackedObjects.iterator, now)
|
||||
hackedObjects = stillHackedObjects
|
||||
unhackObjects.foreach(entry => {
|
||||
entry.target.Actor ! CommonMessages.ClearHack()
|
||||
context.parent ! HackClearActor.ClearTheHack(entry.target.GUID, entry.zone.Id, entry.unk1, entry.unk2)
|
||||
})
|
||||
|
||||
if(stillHackedObjects.nonEmpty) {
|
||||
val short_timeout : FiniteDuration = math.max(1, timeout_time - (now - stillHackedObjects.head.hacked_at_time)) nanoseconds
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
clearTrigger = context.system.scheduler.scheduleOnce(short_timeout, self, HackClearActor.TryClearHacks())
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
/**
|
||||
* na
|
||||
* @param iter na
|
||||
* @param now na
|
||||
* @param list na
|
||||
* @see `List.partition`
|
||||
* @return a `Tuple` of two `Lists`:
|
||||
* the entries for all objects that are no longer hacked,
|
||||
* and the entries for all objects that are still hacked
|
||||
*/
|
||||
@tailrec private def recursivePartitionHacks(iter : Iterator[HackEntry], now : Long, list : List[HackEntry] = Nil) : (List[HackEntry], List[HackEntry]) = {
|
||||
if(!iter.hasNext) {
|
||||
(list, iter.toList)
|
||||
}
|
||||
else {
|
||||
val entry = iter.next()
|
||||
if(now - entry.hacked_at_time >= timeout_time) {
|
||||
recursivePartitionHacks(iter, now, list :+ entry)
|
||||
}
|
||||
else {
|
||||
(list, entry +: iter.toList)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object HackClearActor {
|
||||
private final val timeout_time : Long = 60000000000L //nanoseconds (1 minute)
|
||||
private final val timeout : FiniteDuration = timeout_time nanoseconds
|
||||
|
||||
private final val DefaultClearer : Cancellable = new Cancellable() {
|
||||
override def cancel : Boolean = true
|
||||
override def isCancelled : Boolean = true
|
||||
}
|
||||
|
||||
final case class ObjectIsHacked(target : PlanetSideServerObject, zone : Zone, unk1 : Long, unk2 : Long, hacked_at_time : Long = System.nanoTime())
|
||||
|
||||
final case class ClearTheHack(door_guid : PlanetSideGUID, zone_id : String, unk1 : Long, unk2 : Long)
|
||||
|
||||
private final case class HackEntry(target : PlanetSideServerObject, zone : Zone, unk1 : Long, unk2 : Long, hacked_at_time : Long)
|
||||
|
||||
private final case class TryClearHacks()
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
import akka.actor.Actor
|
||||
import net.psforever.objects.equipment.Equipment
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.packet.game.objectcreate.ConstructorData
|
||||
import net.psforever.types.ExoSuitType
|
||||
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
|
||||
|
|
@ -14,7 +13,6 @@ object AvatarAction {
|
|||
//final case class DropItem(pos : Vector3, orient : Vector3, item : PlanetSideGUID) extends Action
|
||||
final case class EquipmentInHand(player_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action
|
||||
final case class EquipmentOnGround(player_guid : PlanetSideGUID, pos : Vector3, orient : Vector3, item : Equipment) extends Action
|
||||
final case class Hack(player_guid : PlanetSideGUID, target : PlanetSideServerObject, unk1 : Long, unk2 : Long = 8L) extends Action
|
||||
final case class LoadPlayer(player_guid : PlanetSideGUID, pdata : ConstructorData) extends Action
|
||||
// final case class LoadMap(msg : PlanetSideGUID) extends Action
|
||||
// final case class unLoadMap(msg : PlanetSideGUID) extends Action
|
||||
|
|
@ -36,7 +34,6 @@ object AvatarServiceResponse {
|
|||
//final case class DropItem(pos : Vector3, orient : Vector3, item : PlanetSideGUID) extends Response
|
||||
final case class EquipmentInHand(slot : Int, item : Equipment) extends Response
|
||||
final case class EquipmentOnGround(pos : Vector3, orient : Vector3, item : Equipment) extends Response
|
||||
final case class Hack(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long = 8L) extends Response
|
||||
final case class LoadPlayer(pdata : ConstructorData) extends Response
|
||||
// final case class unLoadMap() extends Response
|
||||
// final case class LoadMap() extends Response
|
||||
|
|
@ -96,10 +93,6 @@ class AvatarService extends Actor {
|
|||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.EquipmentOnGround(pos, orient, obj))
|
||||
)
|
||||
case AvatarAction.Hack(player_guid, target, unk1, unk2) =>
|
||||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.Hack(target.GUID, unk1, unk2))
|
||||
)
|
||||
case AvatarAction.LoadPlayer(player_guid, pdata) =>
|
||||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarServiceResponse.LoadPlayer(pdata))
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
import akka.actor.{Actor, Props}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.zones.{DoorCloseActor, Zone}
|
||||
import net.psforever.objects.zones.{DoorCloseActor, HackClearActor, Zone}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
||||
object LocalAction {
|
||||
|
|
@ -9,6 +10,8 @@ object LocalAction {
|
|||
|
||||
final case class DoorOpens(player_guid : PlanetSideGUID, continent : Zone, door : Door) extends Action
|
||||
final case class DoorCloses(player_guid : PlanetSideGUID, door_guid : PlanetSideGUID) extends Action
|
||||
final case class HackClear(player_guid : PlanetSideGUID, target : PlanetSideServerObject, unk1 : Long, unk2 : Long = 8L) extends Action
|
||||
final case class HackTemporarily(player_guid : PlanetSideGUID, continent : Zone, target : PlanetSideServerObject, unk1 : Long, unk2 : Long = 8L) extends Action
|
||||
}
|
||||
|
||||
object LocalServiceResponse {
|
||||
|
|
@ -16,6 +19,8 @@ object LocalServiceResponse {
|
|||
|
||||
final case class DoorOpens(door_guid : PlanetSideGUID) extends Response
|
||||
final case class DoorCloses(door_guid : PlanetSideGUID) extends Response
|
||||
final case class HackClear(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long) extends Response
|
||||
final case class HackObject(target_guid : PlanetSideGUID, unk1 : Long, unk2 : Long) extends Response
|
||||
}
|
||||
|
||||
final case class LocalServiceMessage(forChannel : String, actionMessage : LocalAction.Action)
|
||||
|
|
@ -29,6 +34,7 @@ final case class LocalServiceResponse(toChannel : String, avatar_guid : PlanetSi
|
|||
class LocalService extends Actor {
|
||||
//import LocalService._
|
||||
private val doorCloser = context.actorOf(Props[DoorCloseActor], "local-door-closer")
|
||||
private val hackClearer = context.actorOf(Props[HackClearActor], "local-hack-clearer")
|
||||
private [this] val log = org.log4s.getLogger
|
||||
|
||||
override def preStart = {
|
||||
|
|
@ -55,21 +61,39 @@ class LocalService extends Actor {
|
|||
LocalEvents.publish(
|
||||
LocalServiceResponse(s"/$forChannel/LocalEnvironment", player_guid, LocalServiceResponse.DoorOpens(door.GUID))
|
||||
)
|
||||
|
||||
case LocalAction.DoorCloses(player_guid, door_guid) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(s"/$forChannel/LocalEnvironment", player_guid, LocalServiceResponse.DoorCloses(door_guid))
|
||||
)
|
||||
case LocalAction.HackClear(player_guid, target, unk1, unk2) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(s"/$forChannel/LocalEnvironment", player_guid, LocalServiceResponse.HackClear(target.GUID, unk1, unk2))
|
||||
)
|
||||
case LocalAction.HackTemporarily(player_guid, zone, target, unk1, unk2) =>
|
||||
hackClearer ! HackClearActor.ObjectIsHacked(target, zone, unk1, unk2)
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(s"/$forChannel/Avatar", player_guid, LocalServiceResponse.HackObject(target.GUID, unk1, unk2))
|
||||
)
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
//response from DoorCloseActor
|
||||
case DoorCloseActor.CloseTheDoor(door_guid, zone_id) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(s"/$zone_id/LocalEnvironment", PlanetSideGUID(0), LocalServiceResponse.DoorCloses(door_guid))
|
||||
LocalServiceResponse(s"/$zone_id/LocalEnvironment", LocalService.defaultPlayerGUID, LocalServiceResponse.DoorCloses(door_guid))
|
||||
)
|
||||
|
||||
//response from HackClearActor
|
||||
case HackClearActor.ClearTheHack(target_guid, zone_id, unk1, unk2) =>
|
||||
LocalEvents.publish(
|
||||
LocalServiceResponse(s"/$zone_id/LocalEnvironment", LocalService.defaultPlayerGUID, LocalServiceResponse.HackClear(target_guid, unk1, unk2))
|
||||
)
|
||||
|
||||
case msg =>
|
||||
log.info(s"Unhandled message $msg from $sender")
|
||||
}
|
||||
}
|
||||
|
||||
object LocalService {
|
||||
final val defaultPlayerGUID : PlanetSideGUID = PlanetSideGUID(0)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -144,11 +144,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
)
|
||||
}
|
||||
|
||||
case AvatarServiceResponse.Hack(target_guid, unk1, unk2) =>
|
||||
if(player.GUID != guid) {
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, HackMessage(0, target_guid.guid, guid.guid, 100, unk1, 6, unk2)))
|
||||
}
|
||||
|
||||
case AvatarServiceResponse.LoadPlayer(pdata) =>
|
||||
if(player.GUID != guid) {
|
||||
sendResponse(
|
||||
|
|
@ -232,6 +227,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case LocalServiceResponse.DoorCloses(door_guid) => //door closes for everyone
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, GenericObjectStateMsg(door_guid, 17)))
|
||||
|
||||
case LocalServiceResponse.HackClear(target_guid, unk1, unk2) =>
|
||||
log.info(s"Clear hack of $target_guid")
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, HackMessage(0, target_guid.guid, guid.guid, 0, unk1, 7, unk2)))
|
||||
|
||||
case LocalServiceResponse.HackObject(target_guid, unk1, unk2) =>
|
||||
if(player.GUID != guid) {
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, HackMessage(0, target_guid.guid, guid.guid, 100, unk1, 6, unk2)))
|
||||
}
|
||||
}
|
||||
|
||||
case Door.DoorMessage(tplayer, msg, order) =>
|
||||
|
|
@ -241,7 +245,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
continent.GUID(door_guid) match {
|
||||
case Some(door : Door) =>
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, GenericObjectStateMsg(door_guid, 16)))
|
||||
localService ! LocalServiceMessage (continent.Id, LocalAction.DoorOpens (tplayer.GUID, continent, door) )
|
||||
localService ! LocalServiceMessage(continent.Id, LocalAction.DoorOpens (tplayer.GUID, continent, door) )
|
||||
|
||||
case _ =>
|
||||
log.warn(s"door $door_guid wanted to be opened but could not be found")
|
||||
|
|
@ -578,7 +582,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
continent.Actor ! Zone.DropItemOnGround(item, item.Position, item.Orientation) //restore
|
||||
}
|
||||
|
||||
case ItemHacking(tplayer, target, tool_guid, delta) =>
|
||||
case ItemHacking(tplayer, target, tool_guid, delta, completeAction, tickAction) =>
|
||||
progressBarUpdate.cancel
|
||||
if(progressBarValue.isDefined) {
|
||||
val progressBarVal : Float = progressBarValue.get + delta
|
||||
|
|
@ -594,17 +598,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(PacketCoding.CreateGamePacket(0, HackMessage(1, target.GUID.guid, player.GUID.guid, progressBarVal.toInt, 0L, vis, 8L)))
|
||||
if(progressBarVal > 100) {
|
||||
progressBarValue = None
|
||||
log.info(s"We've hacked the item $target! Now what?")
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, HackMessage(0, target.GUID.guid, player.GUID.guid, 100, 1114636288, 6, 8L)))
|
||||
target.Actor ! CommonMessages.Hack(tplayer)
|
||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.Hack(tplayer.GUID, target, 1114636288))
|
||||
//TODO now what?
|
||||
log.info(s"Hacked a $target")
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, HackMessage(0, target.GUID.guid, player.GUID.guid, 100, 1114636288L, 6, 8L)))
|
||||
completeAction()
|
||||
}
|
||||
else {
|
||||
tickAction.getOrElse(() => Unit)()
|
||||
progressBarValue = Some(progressBarVal)
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
progressBarUpdate = context.system.scheduler.scheduleOnce(250 milliseconds, self, ItemHacking(tplayer, target, tool_guid, delta))
|
||||
progressBarUpdate = context.system.scheduler.scheduleOnce(250 milliseconds, self, ItemHacking(tplayer, target, tool_guid, delta, completeAction))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1052,7 +1055,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Some(tool : SimpleItem) =>
|
||||
if(tool.Definition == GlobalDefinitions.remote_electronics_kit) {
|
||||
progressBarValue = Some(-2.66f)
|
||||
self ! WorldSessionActor.ItemHacking(player, panel, tool.GUID, 2.66f)
|
||||
self ! WorldSessionActor.ItemHacking(player, panel, tool.GUID, 2.66f, HackTemporary(panel))
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
|
|
@ -1622,6 +1625,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
}
|
||||
|
||||
private def HackTemporary(target : PlanetSideServerObject)() : Unit = {
|
||||
target.Actor ! CommonMessages.Hack(player)
|
||||
localService ! LocalServiceMessage(player.Continent, LocalAction.HackTemporarily(player.GUID, continent, target, 1114636288L))
|
||||
}
|
||||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
sendResponse(PacketCoding.CreateControlPacket(ConnectionClose()))
|
||||
|
|
@ -1652,8 +1660,12 @@ object WorldSessionActor {
|
|||
private final case class PlayerFailedToLoad(tplayer : Player)
|
||||
private final case class ListAccountCharacters()
|
||||
private final case class SetCurrentAvatar(tplayer : Player)
|
||||
private final case class ItemHacking(tplayer : Player, target : PlanetSideServerObject, tool_guid : PlanetSideGUID, delta : Float)
|
||||
|
||||
private final case class ItemHacking(tplayer : Player,
|
||||
target : PlanetSideServerObject,
|
||||
tool_guid : PlanetSideGUID,
|
||||
delta : Float,
|
||||
completeAction : () => Unit,
|
||||
tickAction : Option[() => Unit] = None)
|
||||
/**
|
||||
* A placeholder `Cancellable` object.
|
||||
*/
|
||||
|
|
|
|||
Loading…
Reference in a new issue