From 98fc9f5fbad7c53331dcaf673ed07601192e7edb Mon Sep 17 00:00:00 2001 From: FateJH Date: Thu, 17 May 2018 00:19:12 -0400 Subject: [PATCH] more petience with VehicleSeated; added independent DeadState variable (temporary?); changed conditions of vehicle deconstruction scheduler --- pslogin/src/main/scala/Maps.scala | 8 +-- .../src/main/scala/WorldSessionActor.scala | 72 +++++++++++-------- .../support/DelayedDeconstructionActor.scala | 38 ++++++---- 3 files changed, 71 insertions(+), 47 deletions(-) diff --git a/pslogin/src/main/scala/Maps.scala b/pslogin/src/main/scala/Maps.scala index 4c750b62..64f8e22f 100644 --- a/pslogin/src/main/scala/Maps.scala +++ b/pslogin/src/main/scala/Maps.scala @@ -460,8 +460,6 @@ object Maps { def Building2() : Unit = { //HART building C LocalBuilding(2, FoundationBuilder(Building.Structure(StructureType.Building))) - LocalObject(12, ProximityTerminal.Constructor(repair_silo)) //repair terminal A - LocalObject(13, Terminal.Constructor(repair_silo)) //rearm terminal A //ItemTransaction: ItemTransactionMessage(PlanetSideGUID(2050),Buy,3,25mmbullet,0,PlanetSideGUID(0)) LocalObject(186, Terminal.Constructor(cert_terminal)) LocalObject(187, Terminal.Constructor(cert_terminal)) LocalObject(188, Terminal.Constructor(cert_terminal)) @@ -509,8 +507,6 @@ object Maps { LocalObject(1087, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct LocalObject(1088, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct LocalObject(1089, Terminal.Constructor(implant_terminal_interface)) //TODO guid not correct - ObjectToBuilding(12, 2) - ObjectToBuilding(13, 2) ObjectToBuilding(186, 2) ObjectToBuilding(187, 2) ObjectToBuilding(188, 2) @@ -652,11 +648,15 @@ object Maps { def Building51() : Unit = { //air terminal west of HART C + LocalObject(12, ProximityTerminal.Constructor(repair_silo)) //repair terminal + LocalObject(13, Terminal.Constructor(repair_silo)) //rearm terminal LocalBuilding(51, FoundationBuilder(Building.Structure(StructureType.Platform))) LocalObject(304, Terminal.Constructor(dropship_vehicle_terminal)) LocalObject(292, VehicleSpawnPad.Constructor(Vector3(3508.9844f, 2895.961f, 92.296875f), Vector3(0f, 0f, 90.0f)) ) + ObjectToBuilding(12, 51) + ObjectToBuilding(13, 51) ObjectToBuilding(304, 51) ObjectToBuilding(292, 51) TerminalToSpawnPad(304, 292) diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala index bc4d076f..8776e322 100644 --- a/pslogin/src/main/scala/WorldSessionActor.scala +++ b/pslogin/src/main/scala/WorldSessionActor.scala @@ -73,10 +73,12 @@ class WorldSessionActor extends Actor with MDCContextAware { var delayedProximityTerminalResets : Map[PlanetSideGUID, Cancellable] = Map.empty var controlled : Option[Int] = None //keep track of avatar's ServerVehicleOverride state var traveler : Traveler = null + var deadState : DeadState.Value = DeadState.Dead var clientKeepAlive : Cancellable = DefaultCancellable.obj var progressBarUpdate : Cancellable = DefaultCancellable.obj var reviveTimer : Cancellable = DefaultCancellable.obj + var respawnTimer : Cancellable = DefaultCancellable.obj /** * Convert a boolean value into an integer value. @@ -89,6 +91,7 @@ class WorldSessionActor extends Actor with MDCContextAware { override def postStop() = { clientKeepAlive.cancel reviveTimer.cancel + respawnTimer.cancel PlayerActionsToCancel() localService ! Service.Leave() vehicleService ! Service.Leave() @@ -111,12 +114,7 @@ class WorldSessionActor extends Actor with MDCContextAware { if(player.isAlive) { //actually being alive or manually deconstructing - player.VehicleSeated match { - case Some(vehicle_guid) => - DismountVehicleOnLogOut(vehicle_guid, player_guid) - case None => ; - } - + DismountVehicleOnLogOut() continent.Population ! Zone.Population.Release(avatar) player.Position = Vector3.Zero //save character before doing this avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.ObjectDelete(player_guid, player_guid)) @@ -148,7 +146,7 @@ class WorldSessionActor extends Actor with MDCContextAware { player.Position = Vector3.Zero //save character before doing this avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid, 0)) taskResolver ! GUIDTask.UnregisterAvatar(player)(continent.GUID) - DismountVehicleOnLogOut(vehicle_guid, player_guid) + DismountVehicleOnLogOut() } } @@ -170,26 +168,27 @@ class WorldSessionActor extends Actor with MDCContextAware { /** * Vehicle cleanup that is specific to log out behavior. - * @param vehicle_guid the vehicle being occupied - * @param player_guid the player */ - def DismountVehicleOnLogOut(vehicle_guid : PlanetSideGUID, player_guid : PlanetSideGUID) : Unit = { - // Use mountable type instead of Vehicle type to ensure mountables such as implant terminals are correctly dismounted on logout - val mountable = continent.GUID(vehicle_guid).get.asInstanceOf[Mountable] - mountable.Seat(mountable.PassengerInSeat(player).get).get.Occupant = None - - // If this is a player constructed vehicle then start deconstruction timer - // todo: Will base guns implement Vehicle type? Don't want those to deconstruct - continent.GUID(vehicle_guid) match { + def DismountVehicleOnLogOut() : Unit = { + //TODO Will base guns implement Vehicle type? Don't want those to deconstruct + (player.VehicleSeated match { + case Some(vehicle_guid) => + continent.GUID(vehicle_guid) + case None => + None + }) match { case Some(vehicle : Vehicle) => - if(vehicle.Seats.values.count(_.isOccupied) == 0) { - vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(vehicle, continent, 600L) //start vehicle decay (10m) - } + vehicle.Seat(vehicle.PassengerInSeat(player).get).get.Occupant = None + if(vehicle.Seats.values.count(_.isOccupied) == 0) { + vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(vehicle, continent, 600L) //start vehicle decay (10m) + } + vehicleService ! Service.Leave(Some(s"${vehicle.Actor}")) + + case Some(mobj : Mountable) => + mobj.Seat(mobj.PassengerInSeat(player).get).get.Occupant = None + case _ => ; } - - vehicleService ! Service.Leave(Some(s"${mountable.Actor}")) - vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, 0, true, vehicle_guid)) } def receive = Initializing @@ -1235,11 +1234,13 @@ class WorldSessionActor extends Actor with MDCContextAware { case Zone.Lattice.SpawnPoint(zone_id, building, spawn_tube) => log.info(s"Zone.Lattice.SpawnPoint: spawn point on $zone_id in ${building.Id} @ ${spawn_tube.GUID.guid} selected") + respawnTimer.cancel reviveTimer.cancel val sameZone = zone_id == continent.Id val backpack = player.isBackpack val respawnTime : Long = if(sameZone) { 10 } else { 0 } //s val respawnTimeMillis = respawnTime * 1000 //ms + deadState = DeadState.RespawnTime sendResponse(AvatarDeadStateMessage(DeadState.RespawnTime, respawnTimeMillis, respawnTimeMillis, Vector3.Zero, player.Faction, true)) val tplayer = if(backpack) { RespawnClone(player) //new player @@ -1279,7 +1280,7 @@ class WorldSessionActor extends Actor with MDCContextAware { } import scala.concurrent.duration._ import scala.concurrent.ExecutionContext.Implicits.global - context.system.scheduler.scheduleOnce(respawnTime seconds, target, msg) + respawnTimer = context.system.scheduler.scheduleOnce(respawnTime seconds, target, msg) case Zone.Lattice.NoValidSpawnPoint(zone_number, None) => log.warn(s"Zone.Lattice.SpawnPoint: zone $zone_number could not be accessed as requested") @@ -1304,6 +1305,9 @@ class WorldSessionActor extends Actor with MDCContextAware { case InterstellarCluster.GiveWorld(zoneId, zone) => log.info(s"Zone $zoneId will now load") + avatarService ! Service.Leave(Some(continent.Id)) + localService ! Service.Leave(Some(continent.Id)) + vehicleService ! Service.Leave(Some(continent.Id)) player.Continent = zoneId continent = zone continent.Population ! Zone.Population.Join(avatar) @@ -1362,6 +1366,7 @@ class WorldSessionActor extends Actor with MDCContextAware { sendResponse(ChangeShortcutBankMessage(guid, 0)) //FavoritesMessage sendResponse(SetChatFilterMessage(ChatChannel.Local, false, ChatChannel.values.toList)) //TODO will not always be "on" like this + deadState = DeadState.Alive sendResponse(AvatarDeadStateMessage(DeadState.Alive, 0,0, tplayer.Position, player.Faction, true)) sendResponse(PlanetsideAttributeMessage(guid, 53, 1)) sendResponse(AvatarSearchCriteriaMessage(guid, List(0,0,0,0,0,0))) @@ -1545,6 +1550,9 @@ class WorldSessionActor extends Actor with MDCContextAware { log.info("Reticulating splines ...") traveler.zone = continent.Id StartBundlingPackets() + avatarService ! Service.Join(continent.Id) + localService ! Service.Join(continent.Id) + vehicleService ! Service.Join(continent.Id) configZone(continent) sendResponse(TimeOfDayMessage(1191182336)) @@ -1619,9 +1627,6 @@ class WorldSessionActor extends Actor with MDCContextAware { } }) StopBundlingPackets() - avatarService ! Service.Join(player.Continent) - localService ! Service.Join(player.Continent) - vehicleService ! Service.Join(player.Continent) self ! SetCurrentAvatar(player) case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, unk4, is_cloaking, unk5, unk6) => @@ -1703,6 +1708,7 @@ class WorldSessionActor extends Actor with MDCContextAware { log.info(s"ReleaseAvatarRequest: ${player.GUID} on ${continent.Id} has released") reviveTimer.cancel player.Release + deadState = DeadState.Release sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, true)) continent.Population ! Zone.Population.Release(avatar) player.VehicleSeated match { @@ -1808,7 +1814,9 @@ class WorldSessionActor extends Actor with MDCContextAware { } if(messagetype == ChatMessageType.CMT_SUICIDE) { - KillPlayer(player) + if(player.isAlive && deadState != DeadState.Release) { + KillPlayer(player) + } } if(messagetype == ChatMessageType.CMT_DESTROY) { @@ -2404,6 +2412,7 @@ class WorldSessionActor extends Actor with MDCContextAware { PlayerActionsToCancel() CancelAllProximityUnits() player.Release + deadState = DeadState.Release sendResponse(AvatarDeadStateMessage(DeadState.Release, 0, 0, player.Position, player.Faction, true)) continent.Population ! Zone.Population.Release(avatar) @@ -3972,14 +3981,19 @@ class WorldSessionActor extends Actor with MDCContextAware { val pos = tplayer.Position val respawnTimer = 300000 //milliseconds tplayer.Die + deadState = DeadState.Dead sendResponse(PlanetsideAttributeMessage(player_guid, 0, 0)) sendResponse(PlanetsideAttributeMessage(player_guid, 2, 0)) avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0)) sendResponse(DestroyMessage(player_guid, player_guid, PlanetSideGUID(0), pos)) //how many players get this message? sendResponse(AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, pos, player.Faction, true)) if(tplayer.VehicleSeated.nonEmpty) { + continent.GUID(tplayer.VehicleSeated.get) match { + case Some(obj : Vehicle) => + TotalDriverVehicleControl(obj) + case _ => ; + } //make player invisible (if not, the cadaver sticks out the side in a seated position) - TotalDriverVehicleControl(continent.GUID(tplayer.VehicleSeated.get).get.asInstanceOf[Vehicle]) sendResponse(PlanetsideAttributeMessage(player_guid, 29, 1)) avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 29, 1)) } diff --git a/pslogin/src/main/scala/services/vehicle/support/DelayedDeconstructionActor.scala b/pslogin/src/main/scala/services/vehicle/support/DelayedDeconstructionActor.scala index 2c508ad8..7756b415 100644 --- a/pslogin/src/main/scala/services/vehicle/support/DelayedDeconstructionActor.scala +++ b/pslogin/src/main/scala/services/vehicle/support/DelayedDeconstructionActor.scala @@ -33,37 +33,47 @@ class DelayedDeconstructionActor extends Actor { def receive : Receive = { case DelayedDeconstructionActor.ScheduleDeconstruction(vehicle, zone, timeAlive) => trace(s"delayed deconstruction order for $vehicle in $timeAlive") - vehicles = vehicles :+ DelayedDeconstructionActor.VehicleEntry(vehicle, zone, timeAlive * 1000000000L) - if(vehicles.size == 1) { //we were the only entry so the event must be started from scratch - import scala.concurrent.ExecutionContext.Implicits.global - monitor = context.system.scheduler.scheduleOnce(DelayedDeconstructionActor.periodicTest, self, DelayedDeconstructionActor.PeriodicTaskCulling) + val oldHead = vehicles.headOption + val now : Long = System.nanoTime + vehicles = (vehicles :+ DelayedDeconstructionActor.VehicleEntry(vehicle, zone, timeAlive * 1000000000L)) + .sortBy(entry => entry.survivalTime - (now - entry.logTime)) + if(vehicles.size == 1 || oldHead != vehicles.headOption) { //we were the only entry so the event must be started from scratch + RetimePeriodicTest() } case DelayedDeconstructionActor.UnscheduleDeconstruction(vehicle_guid) => //all tasks for this vehicle are cleared from the queue //clear any task that is no longer valid by determination of unregistered GUID val before = vehicles.length - vehicles = vehicles.filter(entry => { !entry.vehicle.HasGUID || entry.vehicle.GUID != vehicle_guid }) + val now : Long = System.nanoTime + vehicles = vehicles.filter(entry => { entry.vehicle.HasGUID && entry.vehicle.GUID != vehicle_guid }) + .sortBy(entry => entry.survivalTime - (now - entry.logTime)) trace(s"attempting to clear deconstruction order for vehicle $vehicle_guid, found ${before - vehicles.length}") - if(vehicles.isEmpty) { - monitor.cancel - } + RetimePeriodicTest() case DelayedDeconstructionActor.PeriodicTaskCulling => //filter the list of deconstruction tasks for any that are need to be triggered monitor.cancel val now : Long = System.nanoTime val (vehiclesToDecon, vehiclesRemain) = vehicles.partition(entry => { now - entry.logTime >= entry.survivalTime }) - vehicles = vehiclesRemain - trace(s"vehicle culling - ${vehiclesToDecon.length} deconstruction tasks found") + vehicles = vehiclesRemain.sortBy(_.survivalTime) + trace(s"vehicle culling - ${vehiclesToDecon.length} deconstruction tasks found; ${vehiclesRemain.length} tasks remain") vehiclesToDecon.foreach(entry => { context.parent ! VehicleServiceMessage.RequestDeleteVehicle(entry.vehicle, entry.zone) }) - if(vehiclesRemain.nonEmpty) { - import scala.concurrent.ExecutionContext.Implicits.global - monitor = context.system.scheduler.scheduleOnce(DelayedDeconstructionActor.periodicTest, self, DelayedDeconstructionActor.PeriodicTaskCulling) - } + RetimePeriodicTest() case _ => ; } + + def RetimePeriodicTest() : Unit = { + monitor.cancel + vehicles.headOption match { + case None => ; + case Some(entry) => + val retime = math.max(1, entry.survivalTime - (System.nanoTime - entry.logTime)) nanoseconds + import scala.concurrent.ExecutionContext.Implicits.global + monitor = context.system.scheduler.scheduleOnce(retime, self, DelayedDeconstructionActor.PeriodicTaskCulling) + } + } } object DelayedDeconstructionActor {