mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-03-03 20:20:22 +00:00
Operational vehicle terminals:
Vehicles can now be pulled from assigned and initialized terminals. The vehicle's chosen spawn pad controls (or paces) all aspects of the spawning process. Support Actors ensure that a fully-realized Vehicle will be unloaded and unregistered if left alone, either right after spawning on the pad or after an extended period of time. The latter half of the procedure used for spawning vehicles is a temporary workaround until future analysis and functionality of the server vehicle override packet is incorporated. Weapons: Weapons will now construct their own default magazines thanks to a switch from Ammo.Value to AmmoBoxDefinition in the ToolDefinition. GenericObjectActionMessage : The only thing this packet does, at the moment, is obscure the player when he is being promoted into the owner of a vehicle.
This commit is contained in:
parent
73d0553b2c
commit
5428bbbfbf
57 changed files with 2957 additions and 538 deletions
|
|
@ -14,7 +14,8 @@ import com.typesafe.config.ConfigFactory
|
|||
import net.psforever.crypto.CryptoInterface
|
||||
import net.psforever.objects.zones._
|
||||
import net.psforever.objects.guid.TaskResolver
|
||||
import net.psforever.objects.serverobject.builders.{DoorObjectBuilder, IFFLockObjectBuilder, TerminalObjectBuilder}
|
||||
import net.psforever.objects.serverobject.builders.{DoorObjectBuilder, IFFLockObjectBuilder, TerminalObjectBuilder, VehicleSpawnPadObjectBuilder}
|
||||
import net.psforever.types.Vector3
|
||||
import org.slf4j
|
||||
import org.fusesource.jansi.Ansi._
|
||||
import org.fusesource.jansi.Ansi.Color._
|
||||
|
|
@ -244,6 +245,10 @@ object PsLogin {
|
|||
LocalObject(TerminalObjectBuilder(order_terminal, 853))
|
||||
LocalObject(TerminalObjectBuilder(order_terminal, 855))
|
||||
LocalObject(TerminalObjectBuilder(order_terminal, 860))
|
||||
LocalObject(TerminalObjectBuilder(ground_vehicle_terminal, 1063))
|
||||
LocalObject(VehicleSpawnPadObjectBuilder(spawn_pad, 500)) //TODO guid not correct
|
||||
LocalObject(TerminalObjectBuilder(dropship_vehicle_terminal, 304))
|
||||
LocalObject(VehicleSpawnPadObjectBuilder(spawn_pad, 501)) //TODO guid not correct
|
||||
|
||||
LocalBases = 30
|
||||
|
||||
|
|
@ -251,8 +256,14 @@ object PsLogin {
|
|||
ObjectToBase(332, 29)
|
||||
ObjectToBase(556, 29)
|
||||
ObjectToBase(558, 29)
|
||||
ObjectToBase(1063, 29) //TODO unowned courtyard terminal?
|
||||
ObjectToBase(500, 29) //TODO unowned courtyard spawnpad?
|
||||
ObjectToBase(304, 29) //TODO unowned courtyard terminal?
|
||||
ObjectToBase(501, 29) //TODO unowned courtyard spawnpad?
|
||||
DoorToLock(330, 558)
|
||||
DoorToLock(332, 556)
|
||||
TerminalToSpawnPad(1063, 500)
|
||||
TerminalToSpawnPad(304, 501)
|
||||
}
|
||||
val home3 = new Zone("home3", map13, 13) {
|
||||
override def Init(implicit context : ActorContext) : Unit = {
|
||||
|
|
@ -261,6 +272,19 @@ object PsLogin {
|
|||
import net.psforever.types.PlanetSideEmpire
|
||||
Base(2).get.Faction = PlanetSideEmpire.VS //HART building C
|
||||
Base(29).get.Faction = PlanetSideEmpire.NC //South Villa Gun Tower
|
||||
|
||||
GUID(500) match {
|
||||
case Some(pad) =>
|
||||
pad.Position = Vector3(3506.0f, 2820.0f, 92.0f)
|
||||
pad.Orientation = Vector3(0f, 0f, 270.0f)
|
||||
case None => ;
|
||||
}
|
||||
GUID(501) match {
|
||||
case Some(pad) =>
|
||||
pad.Position = Vector3(3508.9844f, 2895.961f, 92.296875f)
|
||||
pad.Orientation = Vector3(0f, 0f, 270.0f)
|
||||
case None => ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ import net.psforever.objects.inventory.{GridInventory, InventoryItem}
|
|||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.serverobject.locks.IFFLock
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.serverobject.terminals.Terminal
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, Seat, VehicleLockState}
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, VehicleLockState}
|
||||
import net.psforever.objects.zones.{InterstellarCluster, Zone}
|
||||
import net.psforever.packet.game.objectcreate._
|
||||
import net.psforever.types._
|
||||
|
|
@ -45,25 +46,43 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
var continent : Zone = null
|
||||
var progressBarValue : Option[Float] = None
|
||||
|
||||
var clientKeepAlive : Cancellable = WorldSessionActor.DefaultCancellable
|
||||
var progressBarUpdate : Cancellable = WorldSessionActor.DefaultCancellable
|
||||
var clientKeepAlive : Cancellable = DefaultCancellable.obj
|
||||
var progressBarUpdate : Cancellable = DefaultCancellable.obj
|
||||
|
||||
override def postStop() = {
|
||||
if(clientKeepAlive != null)
|
||||
clientKeepAlive.cancel()
|
||||
localService ! Service.Leave()
|
||||
vehicleService ! Service.Leave()
|
||||
avatarService ! Service.Leave()
|
||||
LivePlayerList.Remove(sessionId) match {
|
||||
case Some(tplayer) =>
|
||||
tplayer.VehicleSeated match {
|
||||
case Some(vehicle_guid) =>
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 0, true))
|
||||
case None => ;
|
||||
}
|
||||
tplayer.VehicleOwned match {
|
||||
case Some(vehicle_guid) =>
|
||||
continent.GUID(vehicle_guid) match {
|
||||
case Some(vehicle : Vehicle) =>
|
||||
vehicle.Owner = None
|
||||
//TODO temporary solution; to un-own, permit driver seat to Empire access level
|
||||
vehicle.PermissionGroup(10, VehicleLockState.Empire.id)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SeatPermissions(tplayer.GUID, vehicle_guid, 10, VehicleLockState.Empire.id))
|
||||
case _ => ;
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
|
||||
avatarService ! Service.Leave()
|
||||
localService ! Service.Leave()
|
||||
vehicleService ! Service.Leave()
|
||||
LivePlayerList.Remove(sessionId) match {
|
||||
case Some(tplayer) =>
|
||||
if(tplayer.HasGUID) {
|
||||
val guid = tplayer.GUID
|
||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(guid, guid))
|
||||
taskResolver ! GUIDTask.UnregisterAvatar(tplayer)(continent.GUID)
|
||||
//TODO normally, the actual player avatar persists a minute or so after the user disconnects
|
||||
}
|
||||
case None => ;
|
||||
if(tplayer.HasGUID) {
|
||||
val guid = tplayer.GUID
|
||||
avatarService ! AvatarServiceMessage(tplayer.Continent, AvatarAction.ObjectDelete(guid, guid))
|
||||
taskResolver ! GUIDTask.UnregisterAvatar(tplayer)(continent.GUID)
|
||||
//TODO normally, the actual player avatar persists a minute or so after the user disconnects
|
||||
}
|
||||
|
||||
case None => ;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -124,6 +143,11 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(PacketCoding.CreateGamePacket(0, ArmorChangedMessage(guid, suit, subtype)))
|
||||
}
|
||||
|
||||
case AvatarResponse.ConcealPlayer() =>
|
||||
if(player.GUID != guid) {
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, GenericObjectActionMessage(guid, 36)))
|
||||
}
|
||||
|
||||
case AvatarResponse.EquipmentInHand(slot, item) =>
|
||||
if(player.GUID != guid) {
|
||||
val definition = item.Definition
|
||||
|
|
@ -186,7 +210,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
else {
|
||||
val before = player.lastSeenStreamMessage(guid.guid)
|
||||
val dist = WorldSessionActor.DistanceSquared(player.Position, msg.pos)
|
||||
val dist = Vector3.DistanceSquared(player.Position, msg.pos)
|
||||
(msg.pos, now - before, dist)
|
||||
}
|
||||
|
||||
|
|
@ -280,9 +304,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case VehicleResponse.MountVehicle(vehicle_guid, seat) =>
|
||||
if(player.GUID != guid) {
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(vehicle_guid, guid, seat)))
|
||||
if(player.VehicleOwned.contains(vehicle_guid)) { //simplistic vehicle ownership management
|
||||
player.VehicleOwned = None
|
||||
}
|
||||
}
|
||||
|
||||
case VehicleResponse.SeatPermissions(vehicle_guid, seat_group, permission) =>
|
||||
|
|
@ -524,6 +545,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(PacketCoding.CreateGamePacket(0, ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Learn, false)))
|
||||
}
|
||||
|
||||
case Terminal.BuyVehicle(vehicle, loadout) =>
|
||||
continent.Map.TerminalToSpawnPad.get(msg.terminal_guid.guid) match {
|
||||
case Some(pad_guid) =>
|
||||
val pad = continent.GUID(pad_guid).get.asInstanceOf[VehicleSpawnPad]
|
||||
vehicle.Faction = tplayer.Faction
|
||||
vehicle.Position = pad.Position
|
||||
vehicle.Orientation = pad.Orientation
|
||||
taskResolver ! RegisterNewVehicle(vehicle, pad)
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Learn, true)))
|
||||
case None =>
|
||||
log.error(s"$tplayer wanted to spawn a vehicle, but there was no spawn pad associated with terminal ${msg.terminal_guid} to accept it")
|
||||
}
|
||||
|
||||
case Terminal.NoDeal() =>
|
||||
log.warn(s"$tplayer made a request but the terminal rejected the order $msg")
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ItemTransactionResultMessage(msg.terminal_guid, msg.transaction_type, false)))
|
||||
|
|
@ -533,9 +567,21 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
reply match {
|
||||
case Vehicle.CanSeatPlayer(vehicle, seat_num) =>
|
||||
log.info(s"MountVehicleMsg: ${player.GUID} mounts ${vehicle.GUID} @ $seat_num")
|
||||
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(vehicle.GUID) //clear all deconstruction timers
|
||||
val vehicle_guid : PlanetSideGUID = vehicle.GUID
|
||||
tplayer.VehicleSeated = Some(vehicle_guid)
|
||||
if(seat_num == 0) { //simplistic vehicle ownership management
|
||||
vehicle.Owner match {
|
||||
case Some(owner_guid) =>
|
||||
continent.GUID(owner_guid) match {
|
||||
case Some(previous_owner : Player) =>
|
||||
if(previous_owner.VehicleOwned.contains(vehicle_guid)) {
|
||||
previous_owner.VehicleOwned = None //simplistic ownership management, player loses vehicle ownership
|
||||
}
|
||||
case _ => ;
|
||||
}
|
||||
case None => ;
|
||||
}
|
||||
player.VehicleOwned = Some(vehicle_guid)
|
||||
vehicle.Owner = Some(player.GUID)
|
||||
}
|
||||
|
|
@ -558,12 +604,52 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.MountVehicle(player_guid, vehicle_guid, seat_num))
|
||||
|
||||
case Vehicle.CannotSeatPlayer(vehicle, seat_num) =>
|
||||
val seat : Seat = vehicle.Seat(seat_num).get
|
||||
log.warn(s"MountVehicleMsg: player $tplayer attempted to board vehicle ${vehicle.GUID}'s seat $seat_num, but was not allowed")
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
case VehicleSpawnPad.ConcealPlayer =>
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, GenericObjectActionMessage(player.GUID, 36)))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ConcealPlayer(player.GUID))
|
||||
|
||||
case VehicleSpawnPad.LoadVehicle(vehicle, _/*pad*/) =>
|
||||
val player_guid = player.GUID
|
||||
val definition = vehicle.Definition
|
||||
val objedtId = definition.ObjectId
|
||||
val vehicle_guid = vehicle.GUID
|
||||
val vdata = definition.Packet.ConstructorData(vehicle).get
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectCreateMessage(objedtId, vehicle_guid, vdata)))
|
||||
continent.Transport ! Zone.SpawnVehicle(vehicle)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.LoadVehicle(player_guid, vehicle, objedtId, vehicle_guid, vdata))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(vehicle_guid, 22, 1L))) //mount points off?
|
||||
//sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(vehicle_guid, 21, player_guid.guid))) //fte and ownership?
|
||||
//sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(vehicle_guid, player_guid, 0)))
|
||||
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(vehicle_guid) //cancel queue timeout delay
|
||||
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(vehicle, continent, 21L) //temporary drive away from pad delay
|
||||
vehicle.Actor ! Vehicle.TrySeatPlayer(0, player)
|
||||
|
||||
case VehicleSpawnPad.PlayerSeatedInVehicle(vehicle) =>
|
||||
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(vehicle, continent, 21L) //sitting in the vehicle clears the drive away delay
|
||||
val vehicle_guid = vehicle.GUID
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(vehicle_guid, 22, 0L))) //mount points on?
|
||||
//sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(vehicle_guid, 0, vehicle.Definition.MaxHealth)))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(vehicle_guid, 68, 0L))) //???
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, PlanetsideAttributeMessage(vehicle_guid, 113, 0L))) //???
|
||||
ReloadVehicleAccessPermissions(vehicle)
|
||||
|
||||
case VehicleSpawnPad.SpawnPadBlockedWarning(vehicle, warning_count) =>
|
||||
if(warning_count > 2) {
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, TriggerSoundMessage(TriggeredSound.Unknown14, vehicle.Position, 20, 1f)))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0,
|
||||
ChatMsg(ChatMessageType.CMT_TELL, true, "", "\\#FYour vehicle is blocking the spawn pad, and will be deconstructed if not moved.", None))
|
||||
)
|
||||
}
|
||||
|
||||
case VehicleSpawnPad.SpawnPadUnblocked(vehicle_guid) =>
|
||||
//vehicle has moved away from spawn pad after initial spawn
|
||||
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(vehicle_guid) //cancel temporary drive away from pad delay
|
||||
|
||||
case ListAccountCharacters =>
|
||||
import net.psforever.objects.definition.converter.CharacterSelectConverter
|
||||
val gen : AtomicInteger = new AtomicInteger(1)
|
||||
|
|
@ -605,15 +691,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
failWithError(s"$tplayer failed to load anywhere")
|
||||
}
|
||||
|
||||
case VehicleLoaded(vehicle) =>
|
||||
val definition = vehicle.Definition
|
||||
val objedtId = definition.ObjectId
|
||||
val vehicle_guid = vehicle.GUID
|
||||
val vdata = definition.Packet.ConstructorData(vehicle).get
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectCreateMessage(objedtId, vehicle_guid, vdata)))
|
||||
ReloadVehicleAccessPermissions(vehicle)
|
||||
continent.Transport ! Zone.SpawnVehicle(vehicle)
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.LoadVehicle(player.GUID, vehicle, objedtId, vehicle_guid, vdata))
|
||||
case VehicleLoaded(_/*vehicle*/) => ;
|
||||
//currently being handled by VehicleSpawnPad.LoadVehicle during testing phase
|
||||
|
||||
case Zone.ClientInitialization(/*initList*/_) =>
|
||||
//TODO iterate over initList; for now, just do this
|
||||
|
|
@ -795,7 +874,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
}
|
||||
|
||||
var player : Player = null
|
||||
var harasser : Vehicle = null //TODO used in testing
|
||||
|
||||
def handleGamePkt(pkt : PlanetSideGamePacket) = pkt match {
|
||||
case ConnectToWorldRequestMessage(server, token, majorVersion, minorVersion, revision, buildDate, unk) =>
|
||||
|
|
@ -803,18 +881,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
log.info(s"New world login to $server with Token:$token. $clientVersion")
|
||||
//TODO begin temp player character auto-loading; remove later
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
val
|
||||
beamer1 = Tool(beamer)
|
||||
beamer1.AmmoSlots.head.Box = AmmoBox(energy_cell, 16)
|
||||
val
|
||||
suppressor1 = Tool(suppressor)
|
||||
suppressor1.AmmoSlots.head.Box = AmmoBox(bullet_9mm, 25)
|
||||
val
|
||||
forceblade1 = Tool(forceblade)
|
||||
forceblade1.AmmoSlots.head.Box = AmmoBox(melee_ammo)
|
||||
|
||||
player = Player("TestCharacter"+sessionId.toString, PlanetSideEmpire.VS, CharacterGender.Female, 41, 1)
|
||||
player.Position = Vector3(3674.8438f, 2726.789f, 91.15625f)
|
||||
//player.Position = Vector3(3674.8438f, 2726.789f, 91.15625f)
|
||||
player.Position = Vector3(3523.039f, 2855.5078f, 90.859375f)
|
||||
player.Orientation = Vector3(0f, 0f, 90f)
|
||||
player.Certifications += CertificationType.StandardAssault
|
||||
player.Certifications += CertificationType.MediumAssault
|
||||
|
|
@ -823,9 +892,24 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
player.Certifications += CertificationType.ReinforcedExoSuit
|
||||
player.Certifications += CertificationType.ATV
|
||||
player.Certifications += CertificationType.Harasser
|
||||
player.Slot(0).Equipment = beamer1
|
||||
player.Slot(2).Equipment = suppressor1
|
||||
player.Slot(4).Equipment = forceblade1
|
||||
//
|
||||
player.Certifications += CertificationType.GroundSupport
|
||||
player.Certifications += CertificationType.GroundTransport
|
||||
player.Certifications += CertificationType.Flail
|
||||
player.Certifications += CertificationType.Switchblade
|
||||
player.Certifications += CertificationType.AssaultBuggy
|
||||
player.Certifications += CertificationType.ArmoredAssault1
|
||||
player.Certifications += CertificationType.ArmoredAssault2
|
||||
player.Certifications += CertificationType.AirCavalryScout
|
||||
player.Certifications += CertificationType.AirCavalryAssault
|
||||
player.Certifications += CertificationType.AirCavalryInterceptor
|
||||
player.Certifications += CertificationType.AirSupport
|
||||
player.Certifications += CertificationType.GalaxyGunship
|
||||
player.Certifications += CertificationType.Phantasm
|
||||
//player.ExoSuit = ExoSuitType.Infiltrator
|
||||
player.Slot(0).Equipment = Tool(beamer)
|
||||
player.Slot(2).Equipment = Tool(suppressor)
|
||||
player.Slot(4).Equipment = Tool(forceblade)
|
||||
player.Slot(6).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(9).Equipment = AmmoBox(bullet_9mm)
|
||||
player.Slot(12).Equipment = AmmoBox(bullet_9mm)
|
||||
|
|
@ -917,21 +1001,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
})
|
||||
ReloadVehicleAccessPermissions(vehicle)
|
||||
})
|
||||
//TODO begin temp vehicle auto-loading
|
||||
import net.psforever.objects.GlobalDefinitions._
|
||||
if(continent.Vehicles.isEmpty) {
|
||||
harasser = Vehicle(two_man_assault_buggy)
|
||||
harasser.Position = Vector3(3674.8438f, 2730.789f, 91.15625f)
|
||||
harasser.Faction = PlanetSideEmpire.VS
|
||||
harasser.Orientation = Vector3(0f, 0f, 90f)
|
||||
harasser.Weapons(2).Equipment.get.asInstanceOf[Tool].AmmoSlots.head.Box = AmmoBox(bullet_12mm, 150)
|
||||
harasser.Trunk += 30 -> AmmoBox(bullet_12mm, 100)
|
||||
taskResolver ! RegisterNewVehicle(harasser)
|
||||
}
|
||||
else {
|
||||
harasser = continent.Vehicles.head //subsequent players after first
|
||||
}
|
||||
//TODO end temp vehicle auto-loading
|
||||
avatarService ! Service.Join(player.Continent)
|
||||
localService ! Service.Join(player.Continent)
|
||||
vehicleService ! Service.Join(player.Continent)
|
||||
|
|
@ -1129,6 +1198,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
continent.GUID(object_guid) match {
|
||||
case Some(vehicle : Vehicle) =>
|
||||
if(player.VehicleOwned.contains(object_guid) && vehicle.Owner.contains(player.GUID)) {
|
||||
vehicleService ! VehicleServiceMessage.UnscheduleDeconstruction(object_guid)
|
||||
vehicleService ! VehicleServiceMessage.RequestDeleteVehicle(vehicle, continent)
|
||||
log.info(s"RequestDestroy: vehicle $object_guid")
|
||||
}
|
||||
|
|
@ -1157,14 +1227,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDeleteMessage(object_guid, 0)))
|
||||
log.info("ObjectDelete: " + msg)
|
||||
|
||||
case msg @ MoveItemMessage(item_guid, avatar_guid_1, avatar_guid_2, dest, unk1) =>
|
||||
case msg @ MoveItemMessage(item_guid, source_guid, destination_guid, dest, unk1) =>
|
||||
player.Find(item_guid) match {
|
||||
case Some(index) =>
|
||||
val indexSlot = player.Slot(index)
|
||||
var itemOpt = indexSlot.Equipment //use this to short circuit
|
||||
var itemOpt : Option[Equipment] = indexSlot.Equipment
|
||||
//use this to short circuit
|
||||
val item = itemOpt.get
|
||||
val destSlot = player.Slot(dest)
|
||||
|
||||
val destItem = if((-1 < dest && dest < 5) || dest == Player.FreeHandSlot) {
|
||||
destSlot.Equipment match {
|
||||
case Some(found) =>
|
||||
|
|
@ -1181,20 +1251,21 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case Success(_) | scala.util.Failure(_) => itemOpt = None; None //abort item move altogether
|
||||
}
|
||||
}
|
||||
|
||||
if(itemOpt.isDefined) {
|
||||
log.info(s"MoveItem: $item_guid moved from $avatar_guid_1 @ $index to $avatar_guid_1 @ $dest")
|
||||
log.info(s"MoveItem: $item_guid moved from $source_guid @ $index to $source_guid @ $dest")
|
||||
indexSlot.Equipment = None
|
||||
destItem match { //do we have a swap item?
|
||||
destItem match {
|
||||
//do we have a swap item?
|
||||
case Some(entry) => //yes, swap
|
||||
val item2 = entry.obj
|
||||
player.Slot(entry.start).Equipment = None //remove item2 to make room for item
|
||||
destSlot.Equipment = item //in case dest and index could block each other
|
||||
(indexSlot.Equipment = entry.obj) match {
|
||||
case Some(_) => //item and item2 swapped places successfully
|
||||
log.info(s"MoveItem: ${item2.GUID} swapped to $avatar_guid_1 @ $index")
|
||||
log.info(s"MoveItem: ${item2.GUID} swapped to $source_guid @ $index")
|
||||
//we must shuffle items around cleanly to avoid causing icons to "disappear"
|
||||
if(index == Player.FreeHandSlot) { //temporarily put in safe location, A -> C
|
||||
if(index == Player.FreeHandSlot) {
|
||||
//temporarily put in safe location, A -> C
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectDetachMessage(player.GUID, item.GUID, Vector3(0f, 0f, 0f), 0f, 0f, 0f))) //ground
|
||||
}
|
||||
else {
|
||||
|
|
@ -1217,13 +1288,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case None => //just move item over
|
||||
destSlot.Equipment = item
|
||||
}
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(avatar_guid_1, item_guid, dest)))
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, ObjectAttachMessage(source_guid, item_guid, dest)))
|
||||
if(0 <= dest && dest < 5) {
|
||||
avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.EquipmentInHand(player.GUID, dest, item))
|
||||
}
|
||||
}
|
||||
case None =>
|
||||
log.info(s"MoveItem: $avatar_guid_1 wanted to move the item $item_guid but could not find it")
|
||||
log.info(s"MoveItem: $source_guid wanted to move the item $item_guid but could not find it")
|
||||
}
|
||||
|
||||
case msg @ ChangeAmmoMessage(item_guid, unk1) =>
|
||||
|
|
@ -1384,6 +1455,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
player.VehicleSeated = None
|
||||
sendResponse(PacketCoding.CreateGamePacket(0, DismountVehicleMsg(player_guid, unk1, unk2))) //should be safe; replace with ObjectDetachMessage later
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, unk1, unk2))
|
||||
if(obj.Seats.count(seat => seat.isOccupied) == 0) {
|
||||
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(obj, continent, 600L) //start vehicle decay (10m)
|
||||
}
|
||||
}
|
||||
case None =>
|
||||
log.warn(s"DismountVehicleMsg: can not find where player $player_guid is seated in vehicle $vehicle_guid")
|
||||
|
|
@ -1409,6 +1483,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
seat.Occupant = None
|
||||
tplayer.VehicleSeated = None
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(player_guid, unk1, unk2))
|
||||
if(obj.Seats.count(seat => seat.isOccupied) == 0) {
|
||||
vehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(obj, continent, 600L) //start vehicle decay (10m)
|
||||
}
|
||||
case None =>
|
||||
log.warn(s"DismountVehicleMsg: can not find where player $player_guid is seated in vehicle $vehicle_guid")
|
||||
}
|
||||
|
|
@ -1733,12 +1810,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
* @see `RegisterVehicle`
|
||||
* @return a `TaskResolver.GiveTask` message
|
||||
*/
|
||||
def RegisterNewVehicle(obj : Vehicle) : TaskResolver.GiveTask = {
|
||||
def RegisterNewVehicle(obj : Vehicle, pad : VehicleSpawnPad) : TaskResolver.GiveTask = {
|
||||
TaskResolver.GiveTask(
|
||||
new Task() {
|
||||
private val localVehicle = obj
|
||||
private val localAnnounce = vehicleService
|
||||
private val localSession : String = sessionId.toString
|
||||
private val localPad = pad.Actor
|
||||
private val localPlayer = player
|
||||
private val localVehicleService = vehicleService
|
||||
private val localZone = continent
|
||||
|
||||
override def isComplete : Task.Resolution.Value = {
|
||||
if(localVehicle.Actor != ActorRef.noSender) {
|
||||
|
|
@ -1751,6 +1832,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
def Execute(resolver : ActorRef) : Unit = {
|
||||
localAnnounce ! VehicleServiceMessage.GiveActorControl(obj, localSession)
|
||||
localPad ! VehicleSpawnPad.VehicleOrder(localPlayer, localVehicle)
|
||||
localVehicleService ! VehicleServiceMessage.DelayedVehicleDeconstruction(localVehicle, localZone, 60L)
|
||||
resolver ! scala.util.Success(this)
|
||||
}
|
||||
}, List(RegisterVehicle(obj)))
|
||||
|
|
@ -1945,35 +2028,4 @@ object WorldSessionActor {
|
|||
delta : Float,
|
||||
completeAction : () => Unit,
|
||||
tickAction : Option[() => Unit] = None)
|
||||
/**
|
||||
* A placeholder `Cancellable` object.
|
||||
*/
|
||||
private final val DefaultCancellable = new Cancellable() {
|
||||
def cancel : Boolean = true
|
||||
def isCancelled() : Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the actual distance between two points.
|
||||
* @param pos1 the first point
|
||||
* @param pos2 the second point
|
||||
* @return the distance
|
||||
*/
|
||||
def Distance(pos1 : Vector3, pos2 : Vector3) : Float = {
|
||||
math.sqrt(DistanceSquared(pos1, pos2)).toFloat
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the squared distance between two points.
|
||||
* Though some time is saved care must be taken that any comparative distance is also squared.
|
||||
* @param pos1 the first point
|
||||
* @param pos2 the second point
|
||||
* @return the distance
|
||||
*/
|
||||
def DistanceSquared(pos1 : Vector3, pos2 : Vector3) : Float = {
|
||||
val dx : Float = pos1.x - pos2.x
|
||||
val dy : Float = pos1.y - pos2.y
|
||||
val dz : Float = pos1.z - pos2.z
|
||||
(dx * dx) + (dy * dy) + (dz * dz)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ object AvatarAction {
|
|||
trait Action
|
||||
|
||||
final case class ArmorChanged(player_guid : PlanetSideGUID, suit : ExoSuitType.Value, subtype : Int) extends Action
|
||||
final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Action
|
||||
//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
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ object AvatarResponse {
|
|||
trait Response
|
||||
|
||||
final case class ArmorChanged(suit : ExoSuitType.Value, subtype : Int) extends Response
|
||||
final case class ConcealPlayer() extends Response
|
||||
//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
|
||||
|
|
|
|||
|
|
@ -33,6 +33,10 @@ class AvatarService extends Actor {
|
|||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ArmorChanged(suit, subtype))
|
||||
)
|
||||
case AvatarAction.ConcealPlayer(player_guid) =>
|
||||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.ConcealPlayer())
|
||||
)
|
||||
case AvatarAction.EquipmentInHand(player_guid, slot, obj) =>
|
||||
AvatarEvents.publish(
|
||||
AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.EquipmentInHand(slot, obj))
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package services.local.support
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.DefaultCancellable
|
||||
import net.psforever.objects.serverobject.doors.Door
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
|
@ -16,7 +17,7 @@ import scala.concurrent.duration._
|
|||
*/
|
||||
class DoorCloseActor() extends Actor {
|
||||
/** The periodic `Executor` that checks for doors to be closed */
|
||||
private var doorCloserTrigger : Cancellable = DoorCloseActor.DefaultCloser
|
||||
private var doorCloserTrigger : Cancellable = DefaultCancellable.obj
|
||||
/** A `List` of currently open doors */
|
||||
private var openDoors : List[DoorCloseActor.DoorEntry] = Nil
|
||||
//private[this] val log = org.log4s.getLogger
|
||||
|
|
@ -98,11 +99,6 @@ object DoorCloseActor {
|
|||
/** The wait before an open door closes; as a `FiniteDuration` for `Executor` simplicity */
|
||||
private final val timeout : FiniteDuration = timeout_time nanoseconds
|
||||
|
||||
private final val DefaultCloser : Cancellable = new Cancellable() {
|
||||
override def cancel : Boolean = true
|
||||
override def isCancelled : Boolean = true
|
||||
}
|
||||
|
||||
/**
|
||||
* Message that carries information about a door that has been opened.
|
||||
* @param door the door object
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
package services.local.support
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.DefaultCancellable
|
||||
import net.psforever.objects.serverobject.{CommonMessages, PlanetSideServerObject}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
|
@ -16,7 +17,7 @@ import scala.concurrent.duration._
|
|||
*/
|
||||
class HackClearActor() extends Actor {
|
||||
/** The periodic `Executor` that checks for server objects to be unhacked */
|
||||
private var clearTrigger : Cancellable = HackClearActor.DefaultClearer
|
||||
private var clearTrigger : Cancellable = DefaultCancellable.obj
|
||||
/** A `List` of currently hacked server objects */
|
||||
private var hackedObjects : List[HackClearActor.HackEntry] = Nil
|
||||
//private[this] val log = org.log4s.getLogger
|
||||
|
|
@ -99,11 +100,6 @@ object HackClearActor {
|
|||
/** The wait before a server object is to unhack; as a `FiniteDuration` for `Executor` simplicity */
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* Message that carries information about a server object that has been hacked.
|
||||
* @param target the server object
|
||||
|
|
|
|||
|
|
@ -2,12 +2,13 @@
|
|||
package services.vehicle
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import services.vehicle.support.{DeconstructionActor, VehicleContextActor}
|
||||
import services.vehicle.support.{DeconstructionActor, DelayedDeconstructionActor, VehicleContextActor}
|
||||
import services.{GenericEventBus, Service}
|
||||
|
||||
class VehicleService extends Actor {
|
||||
private val vehicleContext : ActorRef = context.actorOf(Props[VehicleContextActor], "vehicle-context-root")
|
||||
private val vehicleDecon : ActorRef = context.actorOf(Props[DeconstructionActor], "vehicle-decon-agent")
|
||||
private val vehicleDelayedDecon : ActorRef = context.actorOf(Props[DelayedDeconstructionActor], "vehicle-delayed-decon-agent")
|
||||
vehicleDecon ! DeconstructionActor.RequestTaskResolver
|
||||
private [this] val log = org.log4s.getLogger
|
||||
|
||||
|
|
@ -79,6 +80,14 @@ class VehicleService extends Actor {
|
|||
case VehicleServiceMessage.RequestDeleteVehicle(vehicle, continent) =>
|
||||
vehicleDecon ! DeconstructionActor.RequestDeleteVehicle(vehicle, continent)
|
||||
|
||||
//message to DelayedDeconstructionActor
|
||||
case VehicleServiceMessage.DelayedVehicleDeconstruction(vehicle, zone, timeAlive) =>
|
||||
vehicleDelayedDecon ! DelayedDeconstructionActor.ScheduleDeconstruction(vehicle, zone, timeAlive)
|
||||
|
||||
//message to DelayedDeconstructionActor
|
||||
case VehicleServiceMessage.UnscheduleDeconstruction(vehicle_guid) =>
|
||||
vehicleDelayedDecon ! DelayedDeconstructionActor.UnscheduleDeconstruction(vehicle_guid)
|
||||
|
||||
//response from DeconstructionActor
|
||||
case DeconstructionActor.DeleteVehicle(vehicle_guid, zone_id) =>
|
||||
VehicleEvents.publish(
|
||||
|
|
|
|||
|
|
@ -3,11 +3,14 @@ package services.vehicle
|
|||
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
|
||||
final case class VehicleServiceMessage(forChannel : String, actionMessage : VehicleAction.Action)
|
||||
|
||||
object VehicleServiceMessage {
|
||||
final case class DelayedVehicleDeconstruction(vehicle : Vehicle, continent : Zone, timeAlive : Long)
|
||||
final case class GiveActorControl(vehicle : Vehicle, actorName : String)
|
||||
final case class RevokeActorControl(vehicle : Vehicle)
|
||||
final case class RequestDeleteVehicle(vehicle : Vehicle, continent : Zone)
|
||||
final case class UnscheduleDeconstruction(vehicle_guid : PlanetSideGUID)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
package services.vehicle.support
|
||||
|
||||
import akka.actor.{Actor, ActorRef, Cancellable}
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.{DefaultCancellable, Vehicle}
|
||||
import net.psforever.objects.guid.TaskResolver
|
||||
import net.psforever.objects.vehicles.Seat
|
||||
import net.psforever.objects.zones.Zone
|
||||
|
|
@ -20,11 +20,13 @@ import scala.concurrent.duration._
|
|||
* A reference to a vehicle should be passed to this object as soon as it is going to be cleaned-up from the game world.
|
||||
* Once accepted, only a few seconds will remain before the vehicle is deleted.
|
||||
* To ensure that no players are lost in the deletion, all occupants of the vehicle are kicked out.
|
||||
* Furthermore, the vehicle is rendered "dead" and inaccessible right up to the point where it is removed.
|
||||
* Furthermore, the vehicle is rendered "dead" and inaccessible right up to the point where it is removed.<br>
|
||||
* <br>
|
||||
* This `Actor` is intended to sit on top of the event system that handles broadcast messaging.
|
||||
*/
|
||||
class DeconstructionActor extends Actor {
|
||||
/** The periodic `Executor` that scraps the next vehicle on the list */
|
||||
private var scrappingProcess : Cancellable = DeconstructionActor.DefaultProcess
|
||||
private var scrappingProcess : Cancellable = DefaultCancellable.obj
|
||||
/** A `List` of currently doomed vehicles */
|
||||
private var vehicles : List[DeconstructionActor.VehicleEntry] = Nil
|
||||
/** The manager that helps unregister the vehicle from its current GUID scope */
|
||||
|
|
@ -171,11 +173,6 @@ object DeconstructionActor {
|
|||
/** The wait before completely deleting a vehicle; as a `FiniteDuration` for `Executor` simplicity */
|
||||
private final val timeout : FiniteDuration = timeout_time nanoseconds
|
||||
|
||||
private final val DefaultProcess : Cancellable = new Cancellable() {
|
||||
override def cancel : Boolean = true
|
||||
override def isCancelled : Boolean = true
|
||||
}
|
||||
|
||||
final case class RequestTaskResolver()
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.vehicle.support
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.{DefaultCancellable, Vehicle}
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import services.vehicle.VehicleServiceMessage
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
* Maintain and curate a list of timed `vehicle` object deconstruction tasks.<br>
|
||||
* <br>
|
||||
* These tasks are queued or dismissed by player activity but they are executed independent of player activity.
|
||||
* A common disconnected cause of deconstruction is neglect for an extended period of time.
|
||||
* At that point, the original owner of the vehicle no longer matters.
|
||||
* Deconstruction neglect, however, is averted by having someone become seated.
|
||||
* A realized deconstruction is entirely based on a fixed interval after an unresolved request has been received.
|
||||
* The actual process of deconstructing the vehicle and cleaning up its resources is performed by an external agent.<br>
|
||||
* <br>
|
||||
* This `Actor` is intended to sit on top of the event system that handles broadcast messaging.
|
||||
*/
|
||||
class DelayedDeconstructionActor extends Actor {
|
||||
/** The periodic `Executor` that scraps the next vehicle on the list */
|
||||
private var monitor : Cancellable = DefaultCancellable.obj
|
||||
/** A `List` of currently doomed vehicles */
|
||||
private var vehicles : List[DelayedDeconstructionActor.VehicleEntry] = Nil
|
||||
private[this] val log = org.log4s.getLogger
|
||||
private[this] def trace(msg : String) : Unit = log.trace(msg)
|
||||
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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 })
|
||||
trace(s"attempting to clear deconstruction order for vehicle $vehicle_guid, found ${before - vehicles.length}")
|
||||
if(vehicles.isEmpty) {
|
||||
monitor.cancel
|
||||
}
|
||||
|
||||
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")
|
||||
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)
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
object DelayedDeconstructionActor {
|
||||
/**
|
||||
* Timer for the repeating executor.
|
||||
*/
|
||||
private final val periodicTest : FiniteDuration = 5000000000L nanoseconds //5s
|
||||
|
||||
/**
|
||||
* Queue a future vehicle deconstruction action.
|
||||
* @param vehicle the `Vehicle` object
|
||||
* @param zone the `Zone` that the vehicle currently occupies
|
||||
* @param survivalTime how long until the vehicle will be deconstructed in seconds
|
||||
*/
|
||||
final case class ScheduleDeconstruction(vehicle : Vehicle, zone : Zone, survivalTime : Long)
|
||||
|
||||
/**
|
||||
* Dequeue a vehicle from being deconstructed.
|
||||
* @param vehicle_guid the vehicle
|
||||
*/
|
||||
final case class UnscheduleDeconstruction(vehicle_guid : PlanetSideGUID)
|
||||
|
||||
/**
|
||||
* A message the `Actor` sends to itself.
|
||||
* The trigger for the periodic deconstruction task.
|
||||
*/
|
||||
private final case class PeriodicTaskCulling()
|
||||
|
||||
/**
|
||||
* An entry that stores vehicle deconstruction tasks.
|
||||
* @param vehicle the `Vehicle` object
|
||||
* @param zone the `Zone` that the vehicle currently occupies
|
||||
* @param survivalTime how long until the vehicle will be deconstructed in nanoseconds
|
||||
* @param logTime when this deconstruction request was initially created in nanoseconds;
|
||||
* initialized by default to a "now"
|
||||
*/
|
||||
private final case class VehicleEntry(vehicle : Vehicle, zone : Zone, survivalTime : Long, logTime : Long = System.nanoTime())
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package services.vehicle.support
|
||||
|
||||
import akka.actor.{Actor, Props}
|
||||
import akka.actor.{Actor, ActorRef, Props}
|
||||
import net.psforever.objects.vehicles.VehicleControl
|
||||
import services.vehicle.VehicleServiceMessage
|
||||
|
||||
|
|
@ -15,15 +15,18 @@ import services.vehicle.VehicleServiceMessage
|
|||
* <br>
|
||||
* The only purpose of this `Actor` is to allow vehicles to borrow a context for the purpose of `Actor` creation.
|
||||
* It is also be allowed to be responsible for cleaning up that context.
|
||||
* (In reality, it can be cleaned up anywhere a `PoisonPill` can be sent.)
|
||||
* (In reality, it can be cleaned up anywhere a `PoisonPill` can be sent.)<br>
|
||||
* <br>
|
||||
* This `Actor` is intended to sit on top of the event system that handles broadcast messaging.
|
||||
*/
|
||||
class VehicleContextActor() extends Actor {
|
||||
def receive : Receive = {
|
||||
case VehicleServiceMessage.GiveActorControl(vehicle, actorName) =>
|
||||
vehicle.Actor = context.actorOf(Props(classOf[VehicleControl], vehicle), s"${vehicle.Definition.Name}_$actorName")
|
||||
vehicle.Actor = context.actorOf(Props(classOf[VehicleControl], vehicle), s"${vehicle.Definition.Name}_$actorName.${System.nanoTime()}")
|
||||
|
||||
case VehicleServiceMessage.RevokeActorControl(vehicle) =>
|
||||
vehicle.Actor ! akka.actor.PoisonPill
|
||||
vehicle.Actor = ActorRef.noSender
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue