Gating Fixes (#254)

* rescheduling of passenger gating summons to increase chances of detecting passengers joining same zone; short-circuit new spawn requests and new warp gate requests while a previous request is already being processed

* changing respawn delays for warp gate spawn points

* adjusting how warp gates store broadcast data and how broadcast gates are declared in packets; activating TR sanctuary warp gates and making Solsar warp gates broadcast for the TR

* changes to vehicle disowning and what happens to an AMS when it is unloaded
This commit is contained in:
Fate-JH 2019-04-21 08:23:12 -04:00 committed by GitHub
parent 6399963e68
commit 5209f9ec21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 223 additions and 94 deletions

View file

@ -1039,14 +1039,12 @@ object GlobalDefinitions {
val warpgate : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(993) with SpawnPointDefinition val warpgate : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(993) with SpawnPointDefinition
warpgate.Name = "warpgate" warpgate.Name = "warpgate"
warpgate.UseRadius = 301.8713f warpgate.UseRadius = 301.8713f
warpgate.Delay = 10
warpgate.VehicleAllowance = true warpgate.VehicleAllowance = true
warpgate.SpecificPointFunc = SpawnPoint.Gate warpgate.SpecificPointFunc = SpawnPoint.Gate
val hst : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(402) with SpawnPointDefinition val hst : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(402) with SpawnPointDefinition
hst.Name = "hst" hst.Name = "hst"
hst.UseRadius = 20.4810f hst.UseRadius = 20.4810f
hst.Delay = 10
hst.VehicleAllowance = true hst.VehicleAllowance = true
hst.NoWarp += dropship hst.NoWarp += dropship
hst.NoWarp += galaxy_gunship hst.NoWarp += galaxy_gunship
@ -1062,7 +1060,6 @@ object GlobalDefinitions {
val warpgate_cavern : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(994) with SpawnPointDefinition val warpgate_cavern : ObjectDefinition with SpawnPointDefinition = new ObjectDefinition(994) with SpawnPointDefinition
warpgate_cavern.Name = "warpgate_cavern" warpgate_cavern.Name = "warpgate_cavern"
warpgate_cavern.UseRadius = 55.0522f warpgate_cavern.UseRadius = 55.0522f
warpgate_cavern.Delay = 10
warpgate_cavern.VehicleAllowance = true warpgate_cavern.VehicleAllowance = true
warpgate_cavern.SpecificPointFunc = SpawnPoint.Gate warpgate_cavern.SpecificPointFunc = SpawnPoint.Gate

View file

@ -9,11 +9,15 @@ import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{Additional1, Additional2, Additional3, PlanetSideGeneratorState} import net.psforever.packet.game.{Additional1, Additional2, Additional3, PlanetSideGeneratorState}
import net.psforever.types.{PlanetSideEmpire, Vector3} import net.psforever.types.{PlanetSideEmpire, Vector3}
import scala.collection.mutable
class WarpGate(building_guid : Int, map_id : Int, zone : Zone, buildingDefinition : ObjectDefinition with SpawnPointDefinition) class WarpGate(building_guid : Int, map_id : Int, zone : Zone, buildingDefinition : ObjectDefinition with SpawnPointDefinition)
extends Building(building_guid, map_id, zone, StructureType.WarpGate, buildingDefinition) extends Building(building_guid, map_id, zone, StructureType.WarpGate, buildingDefinition)
with SpawnPoint { with SpawnPoint {
/** can this building be used as an active warp gate */
private var active : Boolean = true private var active : Boolean = true
private var broadcast : Boolean = false /** what faction views this warp gate as a broadcast gate */
private var broadcast : mutable.Set[PlanetSideEmpire.Value] = mutable.Set.empty[PlanetSideEmpire.Value]
override def Info : ( override def Info : (
Int, Int,
@ -48,18 +52,105 @@ class WarpGate(building_guid : Int, map_id : Int, zone : Zone, buildingDefinitio
) )
} }
/**
* If a warp gate is active, it can be used to transport faction-affiliated forces between other gates.
* For transportation of faction-opposed forces, use broadcast logic for that faction.
* @return `true`, if the warp gate can be used for transport;
* `false`, otherwise
*/
def Active : Boolean = active def Active : Boolean = active
/**
* Control whether a warp gate is usable for transporting faction-affiliated forces between other gates.
* @param state `true`, to activate the gate;
* `false`, otherwise
* @return `true`, if the gate is active;
* `false`, otherwise
*/
def Active_=(state : Boolean) : Boolean = { def Active_=(state : Boolean) : Boolean = {
active = state active = state
Active Active
} }
def Broadcast : Boolean = Active && broadcast /**
* Determine whether any faction interacts with this warp gate as "broadcast."
* The gate must be active first.
* @return `true`, if some faction sees this warp gate as a "broadcast gate";
* `false`, otherwise
*/
def Broadcast : Boolean = Active && broadcast.nonEmpty
def Broadcast_=(cast : Boolean) : Boolean = { /**
broadcast = cast * Determine whether a specific faction interacts with this warp gate as "broadcast."
Broadcast * The warp gate being `NEUTRAL` should allow for any polled faction to interact.
* The gate must be active first.
* @return `true`, if the given faction interacts with this warp gate as a "broadcast gate";
* `false`, otherwise
*/
def Broadcast(faction : PlanetSideEmpire.Value) : Boolean = {
Active && (broadcast.contains(faction) || broadcast.contains(PlanetSideEmpire.NEUTRAL))
}
/**
* Toggle whether the warp gate's faction-affiliated force interacts with this warp gate as "broadcast."
* Other "broadcast" associations are not affected.
* The gate must be active first.
* @param bcast `true`, if the faction-affiliated force interacts with this gate as broadcast;
* `false`, if not
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def Broadcast_=(bcast : Boolean) : Set[PlanetSideEmpire.Value] = {
if(Active) {
if(bcast) {
broadcast += Faction
}
else {
broadcast -= Faction
}
}
broadcast.toSet
}
/**
* Which factions interact with this warp gate as "broadcast?"
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def BroadcastFor : Set[PlanetSideEmpire.Value] = broadcast.toSet
/**
* Allow a faction to interact with a given warp gate as "broadcast" if it is active.
* @param bcast the faction
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def BroadcastFor_=(bcast : PlanetSideEmpire.Value) : Set[PlanetSideEmpire.Value] = {
(broadcast += bcast).toSet
}
/**
* Allow some factions to interact with a given warp gate as "broadcast" if it is active.
* @param bcast the factions
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def BroadcastFor_=(bcast : Set[PlanetSideEmpire.Value]) : Set[PlanetSideEmpire.Value] = {
(broadcast ++= bcast).toSet
}
/**
* Disallow a faction to interact with a given warp gate as "broadcast."
* @param bcast the faction
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def StopBroadcastFor_=(bcast : PlanetSideEmpire.Value) : Set[PlanetSideEmpire.Value] = {
(broadcast -= bcast).toSet
}
/**
* Disallow some factions to interact with a given warp gate as "broadcast."
* @param bcast the factions
* @return the set of all factions who interact with this warp gate as "broadcast"
*/
def StopBroadcastFor_=(bcast : Set[PlanetSideEmpire.Value]) : Set[PlanetSideEmpire.Value] = {
(broadcast --= bcast).toSet
} }
def Owner : PlanetSideServerObject = this def Owner : PlanetSideServerObject = this

View file

@ -6,28 +6,26 @@ import scodec.Codec
import scodec.codecs._ import scodec.codecs._
/** /**
* Promotes a warpgate's "broadcast" functionality.<br> * Dispatched by the server to promote a warp gate's broadcast functionality.<br>
* <br> * <br>
* Change the map name of a warpgate into "Broadcast" when the proper state is set. * Changes the map name of a warp gate into "Broadcast"
* If a proper warpgate is not designated, nothing happens. * and allow a given faction to access the gate's intercontinental transport functionality to/from that gate,
* If not set, the map name of the warpgate will default to whatever is normally written on the map. * even if the gate is not properly owned.
* The map designation of geowarps is not affected by this packet.<br> * If an actual warp gate is not designated, nothing happens.
* <br> * If not set, the map name of the warp gate will default to whatever is normally written on the map.
* Exploration:<br> * The map designation of geowarps is not affected by this packet.
* I believe these `Boolean` values actually indicate some measure of warpgate operation. * @see `BuildingInfoUpdateMessage`
* Geowarps, for example, though their appearance does not change, recieve this packet. * @param zone_id the zone ordinal number
* Moreover, they can operate as a receiving-end broadcast gate. * @param building_id the warp gate map id
* @param continent_id the zone * @param tr players belonging to the Terran Republic interact with this warp gate as a "broadcast gate"
* @param building_id the warp gate (see `BuildingInfoUpdateMessage`) * @param nc players belonging to the New Conglomerate interact with this warp gate as a "broadcast gate"
* @param unk1 na * @param vs players belonging to the Vanu Sovereignty interact with this warp gate as a "broadcast gate"
* @param unk2 na
* @param broadcast if true, the gate replaces its destination text with "Broadcast"
*/ */
final case class BroadcastWarpgateUpdateMessage(continent_id : Int, final case class BroadcastWarpgateUpdateMessage(zone_id : Int,
building_id : Int, building_id : Int,
unk1 : Boolean, tr : Boolean,
unk2 : Boolean, nc : Boolean,
broadcast : Boolean) vs : Boolean)
extends PlanetSideGamePacket { extends PlanetSideGamePacket {
type Packet = BroadcastWarpgateUpdateMessage type Packet = BroadcastWarpgateUpdateMessage
def opcode = GamePacketOpcode.BroadcastWarpgateUpdateMessage def opcode = GamePacketOpcode.BroadcastWarpgateUpdateMessage
@ -36,10 +34,10 @@ final case class BroadcastWarpgateUpdateMessage(continent_id : Int,
object BroadcastWarpgateUpdateMessage extends Marshallable[BroadcastWarpgateUpdateMessage] { object BroadcastWarpgateUpdateMessage extends Marshallable[BroadcastWarpgateUpdateMessage] {
implicit val codec : Codec[BroadcastWarpgateUpdateMessage] = ( implicit val codec : Codec[BroadcastWarpgateUpdateMessage] = (
("continent_id" | uint16L) :: ("zone_id" | uint16L) ::
("building_id" | uint16L) :: ("building_id" | uint16L) ::
("unk1" | bool) :: ("tr" | bool) ::
("unk2" | bool) :: ("nc" | bool) ::
("broadcast" | bool) ("vs" | bool)
).as[BroadcastWarpgateUpdateMessage] ).as[BroadcastWarpgateUpdateMessage]
} }

View file

@ -164,6 +164,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
//quickly and briefly kill player to avoid disembark animation //quickly and briefly kill player to avoid disembark animation
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0)) avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 0, 0))
DismountVehicleOnLogOut() DismountVehicleOnLogOut()
DisownVehicle()
} }
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid)) avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player_guid, player_guid))
taskResolver ! GUIDTask.UnregisterAvatar(player)(continent.GUID) taskResolver ! GUIDTask.UnregisterAvatar(player)(continent.GUID)
@ -207,14 +208,14 @@ class WorldSessionActor extends Actor with MDCContextAware {
* Vehicle cleanup that is specific to log out behavior. * Vehicle cleanup that is specific to log out behavior.
*/ */
def DismountVehicleOnLogOut() : Unit = { def DismountVehicleOnLogOut() : Unit = {
(player.VehicleSeated match { (continent.GUID(player.VehicleSeated) match {
case Some(vehicle_guid) => case Some(obj : Mountable) =>
continent.GUID(vehicle_guid) (Some(obj), obj.PassengerInSeat(player))
case None => case _ =>
None (None, None)
}) match { }) match {
case Some(mobj : Mountable) => case (Some(mountObj), Some(seatIndex)) =>
mobj.Seat(mobj.PassengerInSeat(player).get).get.Occupant = None mountObj.Seats(seatIndex).Occupant = None
case _ => ; case _ => ;
} }
@ -2733,6 +2734,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
}) })
StopBundlingPackets() StopBundlingPackets()
drawDeloyableIcon = DontRedrawIcons drawDeloyableIcon = DontRedrawIcons
//if driver of a vehicle, summon any passengers and cargo vehicles left behind on previous continent
GetVehicleAndSeat() match {
case (Some(vehicle), Some(0)) =>
LoadZoneTransferPassengerMessages(
guid,
continent.Id,
TransportVehicleChannelName(vehicle),
vehicle,
interstellarFerryTopLevelGUID.getOrElse(vehicle.GUID)
)
interstellarFerryTopLevelGUID = None
case _ => ;
}
} }
def handleControlPkt(pkt : PlanetSideControlPacket) = { def handleControlPkt(pkt : PlanetSideControlPacket) = {
@ -3028,16 +3042,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}) })
//our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate //our vehicle would have already been loaded; see NewPlayerLoaded/AvatarCreate
usedVehicle.headOption match { usedVehicle.headOption match {
case Some(vehicle) if vehicle.PassengerInSeat(player).contains(0) => case Some(vehicle) if !vehicle.PassengerInSeat(player).contains(0) =>
//if driver of vehicle, summon any passengers and cargo vehicles left behind on previous continent
LoadZoneTransferPassengerMessages(
guid,
continentId,
TransportVehicleChannelName(vehicle),
vehicle,
interstellarFerryTopLevelGUID.orElse(player.VehicleSeated).getOrElse(PlanetSideGUID(0))
)
case Some(vehicle) =>
//if passenger, attempt to depict any other passengers already in this zone //if passenger, attempt to depict any other passengers already in this zone
val vguid = vehicle.GUID val vguid = vehicle.GUID
vehicle.Seats vehicle.Seats
@ -3054,7 +3059,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
) )
) )
}) })
case _ => ; //no vehicle case _ => ; //driver, or no vehicle
} }
//vehicle wreckages //vehicle wreckages
wreckages.foreach(vehicle => { wreckages.foreach(vehicle => {
@ -3287,7 +3292,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ SpawnRequestMessage(u1, spawn_type, u3, u4, zone_number) => case msg @ SpawnRequestMessage(u1, spawn_type, u3, u4, zone_number) =>
log.info(s"SpawnRequestMessage: $msg") log.info(s"SpawnRequestMessage: $msg")
cluster ! Zone.Lattice.RequestSpawnPoint(zone_number.toInt, player, spawn_type.id.toInt) if(deadState != DeadState.RespawnTime) {
deadState = DeadState.RespawnTime
cluster ! Zone.Lattice.RequestSpawnPoint(zone_number.toInt, player, spawn_type.id.toInt)
}
else {
log.warn("SpawnRequestMessage: request consumed; already respawning ...")
}
case msg @ SetChatFilterMessage(send_channel, origin, whitelist) => case msg @ SetChatFilterMessage(send_channel, origin, whitelist) =>
//log.info("SetChatFilters: " + msg) //log.info("SetChatFilters: " + msg)
@ -3332,18 +3343,22 @@ class WorldSessionActor extends Actor with MDCContextAware {
PlayerActionsToCancel() PlayerActionsToCancel()
continent.GUID(player.VehicleSeated) match { continent.GUID(player.VehicleSeated) match {
case Some(vehicle : Vehicle) => case Some(vehicle : Vehicle) =>
vehicle.Position = pos vehicle.PassengerInSeat(player) match {
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.UnloadVehicle(player.GUID, continent, vehicle, vehicle.GUID)) case Some(0) =>
LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0) vehicle.Position = pos
LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0)
case _ => //not seated as the driver, in which case we can't move
deadState = DeadState.Alive
}
case None => case None =>
player.Position = pos player.Position = pos
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID)) //avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectDelete(player.GUID, player.GUID))
LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0) LoadZonePhysicalSpawnPoint(zone, pos, Vector3.Zero, 0)
case _ => //seated in something that is not a vehicle, in which case we can't move case _ => //seated in something that is not a vehicle, or we're dead, in which case we can't move
deadState = DeadState.Alive deadState = DeadState.Alive
} }
case (false, _, _) => ; case (_, _, _) => ;
} }
CSRWarp.read(traveler, msg) match { CSRWarp.read(traveler, msg) match {
@ -3351,17 +3366,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
deadState = DeadState.Release //cancel movement updates deadState = DeadState.Release //cancel movement updates
PlayerActionsToCancel() PlayerActionsToCancel()
continent.GUID(player.VehicleSeated) match { continent.GUID(player.VehicleSeated) match {
case Some(vehicle : Vehicle) => case Some(vehicle : Vehicle) if player.isAlive =>
LoadZonePhysicalSpawnPoint(continent.Id, pos, Vector3.z(vehicle.Orientation.z), 0) vehicle.PassengerInSeat(player) match {
case Some(0) =>
vehicle.Position = pos
LoadZonePhysicalSpawnPoint(continent.Id, pos, Vector3.z(vehicle.Orientation.z), 0)
case _ => //not seated as the driver, in which case we can't move
deadState = DeadState.Alive
}
case None => case None =>
player.Position = pos player.Position = pos
sendResponse(PlayerStateShiftMessage(ShiftState(0, pos, player.Orientation.z, None))) sendResponse(PlayerStateShiftMessage(ShiftState(0, pos, player.Orientation.z, None)))
deadState = DeadState.Alive //must be set here deadState = DeadState.Alive //must be set here
case _ => //seated in something that is not a vehicle, in which case we can't move case _ => //seated in something that is not a vehicle, or we're dead, in which case we can't move
deadState = DeadState.Alive deadState = DeadState.Alive
} }
case (false, _) => ; case (_, _) => ;
} }
// TODO: Prevents log spam, but should be handled correctly // TODO: Prevents log spam, but should be handled correctly
@ -4485,17 +4506,23 @@ class WorldSessionActor extends Actor with MDCContextAware {
case msg @ WarpgateRequest(continent_guid, building_guid, dest_building_guid, dest_continent_guid, unk1, unk2) => case msg @ WarpgateRequest(continent_guid, building_guid, dest_building_guid, dest_continent_guid, unk1, unk2) =>
log.info(s"WarpgateRequest: $msg") log.info(s"WarpgateRequest: $msg")
continent.Buildings.values.find(building => building.GUID == building_guid) match { if(deadState != DeadState.RespawnTime) {
case Some(wg : WarpGate) if(wg.Active && (GetKnownVehicleAndSeat() match { deadState = DeadState.RespawnTime
case (Some(vehicle), _) => continent.Buildings.values.find(building => building.GUID == building_guid) match {
wg.Definition.VehicleAllowance && !wg.Definition.NoWarp.contains(vehicle.Definition) case Some(wg : WarpGate) if (wg.Active && (GetKnownVehicleAndSeat() match {
case _ => case (Some(vehicle), _) =>
true wg.Definition.VehicleAllowance && !wg.Definition.NoWarp.contains(vehicle.Definition)
})) => case _ =>
cluster ! Zone.Lattice.RequestSpecificSpawnPoint(dest_continent_guid.guid, player, dest_building_guid) true
})) =>
cluster ! Zone.Lattice.RequestSpecificSpawnPoint(dest_continent_guid.guid, player, dest_building_guid)
case _ => case _ =>
RequestSanctuaryZoneSpawn(player, continent.Number) RequestSanctuaryZoneSpawn(player, continent.Number)
}
}
else {
log.warn("WarpgateRequest: request consumed; already respawning ...")
} }
case msg @ MountVehicleMsg(player_guid, mountable_guid, entry_point) => case msg @ MountVehicleMsg(player_guid, mountable_guid, entry_point) =>
@ -5332,7 +5359,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* @param vehicle the discovered vehicle * @param vehicle the discovered vehicle
*/ */
private def SpecialCaseVehicleDespawn(tplayer : Player, vehicle : Vehicle) : Option[Vehicle] = { private def SpecialCaseVehicleDespawn(tplayer : Player, vehicle : Vehicle) : Option[Vehicle] = {
if(vehicle.Owner.contains(tplayer.GUID) || !vehicle.Seats(0).isOccupied) { if(vehicle.Owner.contains(tplayer.GUID)) {
vehicle.Owner = None vehicle.Owner = None
vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(vehicle), continent)) vehicleService ! VehicleServiceMessage.Decon(RemoverActor.ClearSpecific(List(vehicle), continent))
vehicle.CargoHolds.values vehicle.CargoHolds.values
@ -5345,7 +5372,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
vehicle, vehicle,
ferry.GUID, ferry.GUID,
ferry, ferry,
true, false,
false, false,
false false
) )
@ -6357,7 +6384,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
) )
) )
sendResponse(DensityLevelUpdateMessage(continentNumber, buildingNumber, List(0,0, 0,0, 0,0, 0,0))) sendResponse(DensityLevelUpdateMessage(continentNumber, buildingNumber, List(0,0, 0,0, 0,0, 0,0)))
sendResponse(BroadcastWarpgateUpdateMessage(continentNumber, buildingNumber, false, false, wg.Broadcast)) //TODO one faction knows which gates are broadcast for another faction?
sendResponse(
BroadcastWarpgateUpdateMessage(
continentNumber,
buildingNumber,
wg.Broadcast(PlanetSideEmpire.TR),
wg.Broadcast(PlanetSideEmpire.NC),
wg.Broadcast(PlanetSideEmpire.VS)
)
)
case _ => ; case _ => ;
} }
} }
@ -6598,15 +6634,6 @@ class WorldSessionActor extends Actor with MDCContextAware {
case _ => case _ =>
vehicle.MountedIn = None vehicle.MountedIn = None
} }
//call for passengers across the expanse
LoadZoneTransferPassengerMessages(
player.GUID,
continent.Id,
TransportVehicleChannelName(vehicle),
vehicle,
interstellarFerryTopLevelGUID.orElse(player.VehicleSeated).getOrElse(PlanetSideGUID(0))
)
interstellarFerryTopLevelGUID = None
} }
else { else {
//if passenger; //if passenger;
@ -7875,7 +7902,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
* does not factor in any time required for loading zone or game objects * does not factor in any time required for loading zone or game objects
*/ */
def LoadZonePhysicalSpawnPoint(zone_id : String, pos : Vector3, ori : Vector3, respawnTime : Long) : Unit = { def LoadZonePhysicalSpawnPoint(zone_id : String, pos : Vector3, ori : Vector3, respawnTime : Long) : Unit = {
log.info(s"Load in zone $zone_id at position $pos") log.info(s"Load in zone $zone_id at position $pos in $respawnTime seconds")
respawnTimer.cancel respawnTimer.cancel
reviveTimer.cancel reviveTimer.cancel
val backpack = player.isBackpack val backpack = player.isBackpack
@ -7940,7 +7967,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
else { else {
LoadZoneCommonTransferActivity() LoadZoneCommonTransferActivity()
val original = player val original = player
if(tplayer.isBackpack) { if(player.isBackpack) {
//unregister avatar locker + GiveWorld //unregister avatar locker + GiveWorld
player = tplayer player = tplayer
(taskResolver, TaskBeforeZoneChange(GUIDTask.UnregisterLocker(original.Locker)(continent.GUID), zone_id)) (taskResolver, TaskBeforeZoneChange(GUIDTask.UnregisterLocker(original.Locker)(continent.GUID), zone_id))
@ -8381,7 +8408,12 @@ class WorldSessionActor extends Actor with MDCContextAware {
*/ */
def BeforeUnloadVehicle(vehicle : Vehicle) : Unit = { def BeforeUnloadVehicle(vehicle : Vehicle) : Unit = {
vehicle.Definition match { vehicle.Definition match {
case GlobalDefinitions.ams if vehicle.Faction == player.Faction =>
log.info("BeforeUnload: cleaning up after a mobile spawn vehicle ...")
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.UpdateAmsSpawnPoint(continent))
None
case GlobalDefinitions.router => case GlobalDefinitions.router =>
//this may repeat for multiple players on the same continent but that's okay(?)
log.info("BeforeUnload: cleaning up after a router ...") log.info("BeforeUnload: cleaning up after a router ...")
(vehicle.Utility(UtilityType.internal_router_telepad_deployable) match { (vehicle.Utility(UtilityType.internal_router_telepad_deployable) match {
case Some(util : Utility.InternalTelepad) => case Some(util : Utility.InternalTelepad) =>
@ -8566,7 +8598,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
/** /**
* Given an origin and a destination, determine how long the process of traveling should take in reconstruction time. * Given an origin and a destination, determine how long the process of traveling should take in reconstruction time.
* For most destinations, the unit of receiving ("spawn point") determines the reconstruction time. * For most destinations, the unit of receiving ("spawn point") determines the reconstruction time.
* In a special consideration, travel from any sanctuary or sanctuary-special zone should be as immediate as zone loading. * In a special consideration, travel to any sanctuary or sanctuary-special zone should be as immediate as zone loading.
* @param toZoneId the zone where the target is headed * @param toZoneId the zone where the target is headed
* @param toSpawnPoint the unit the target is using as a destination * @param toSpawnPoint the unit the target is using as a destination
* @param fromZoneId the zone where the target current is located * @param fromZoneId the zone where the target current is located
@ -8574,12 +8606,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
*/ */
def CountSpawnDelay(toZoneId : String, toSpawnPoint : SpawnPoint, fromZoneId : String) : Long = { def CountSpawnDelay(toZoneId : String, toSpawnPoint : SpawnPoint, fromZoneId : String) : Long = {
val sanctuaryZoneId = Zones.SanctuaryZoneId(player.Faction) val sanctuaryZoneId = Zones.SanctuaryZoneId(player.Faction)
if(sanctuaryZoneId.equals(fromZoneId)) { //TODO includes traveing zones if(sanctuaryZoneId.equals(toZoneId)) { //to sanctuary
0L 0L
} }
else if(sanctuaryZoneId.equals(toZoneId)) {
10L
}
else if(!player.isAlive) { else if(!player.isAlive) {
toSpawnPoint.Definition.Delay //TODO +cumulative death penalty toSpawnPoint.Definition.Delay //TODO +cumulative death penalty
} }
@ -8601,8 +8630,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
.sortBy(tube => Vector3.DistanceSquared(tube.Position, player.Position)) .sortBy(tube => Vector3.DistanceSquared(tube.Position, player.Position))
.headOption match { .headOption match {
case Some(tube) => case Some(tube) =>
log.info("DrawCurrentAmsSpawnPoint - new @ams spawn point drawn")
sendResponse(BindPlayerMessage(BindStatus.Available, "@ams", true, false, SpawnGroup.AMS, continent.Number, 5, tube.Position)) sendResponse(BindPlayerMessage(BindStatus.Available, "@ams", true, false, SpawnGroup.AMS, continent.Number, 5, tube.Position))
case None => case None =>
log.info("DrawCurrentAmsSpawnPoint - no @ams spawn point drawn")
sendResponse(BindPlayerMessage(BindStatus.Unavailable, "@ams", false, false, SpawnGroup.AMS, continent.Number, 0, Vector3.Zero)) sendResponse(BindPlayerMessage(BindStatus.Unavailable, "@ams", false, false, SpawnGroup.AMS, continent.Number, 0, Vector3.Zero))
} }
} }

View file

@ -7,7 +7,16 @@ import net.psforever.objects.zones.Zone
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
object Zones { object Zones {
val z1 = new Zone("z1", Maps.map1, 1) val z1 = new Zone("z1", Maps.map1, 1) {
override def Init(implicit context : ActorContext) : Unit = {
super.Init(context)
BuildingByMapId(1).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
BuildingByMapId(2).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
BuildingByMapId(3).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
BuildingByMapId(4).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.TR
}
}
val z2 = new Zone("z2", Maps.map2, 2) val z2 = new Zone("z2", Maps.map2, 2)
@ -101,10 +110,10 @@ object Zones {
} }
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
BuildingByMapId(2).get.Faction = PlanetSideEmpire.VS BuildingByMapId(2).get.Faction = PlanetSideEmpire.VS
BuildingByMapId(10).get.asInstanceOf[WarpGate].Broadcast = true BuildingByMapId(10).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(11).get.asInstanceOf[WarpGate].Broadcast = true BuildingByMapId(11).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(12).get.asInstanceOf[WarpGate].Broadcast = true BuildingByMapId(12).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(13).get.asInstanceOf[WarpGate].Broadcast = true BuildingByMapId(13).get.asInstanceOf[WarpGate].BroadcastFor = PlanetSideEmpire.VS
BuildingByMapId(48).get.Faction = PlanetSideEmpire.VS BuildingByMapId(48).get.Faction = PlanetSideEmpire.VS
BuildingByMapId(49).get.Faction = PlanetSideEmpire.VS BuildingByMapId(49).get.Faction = PlanetSideEmpire.VS
BuildingByMapId(18657).get.asInstanceOf[WarpGate].Active = false BuildingByMapId(18657).get.asInstanceOf[WarpGate].Active = false
@ -135,6 +144,9 @@ object Zones {
import net.psforever.types.PlanetSideEmpire import net.psforever.types.PlanetSideEmpire
Buildings.values.foreach { _.Faction = PlanetSideEmpire.TR } Buildings.values.foreach { _.Faction = PlanetSideEmpire.TR }
BuildingByMapId(1).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(2).get.asInstanceOf[WarpGate].Broadcast = true
BuildingByMapId(3).get.asInstanceOf[WarpGate].Broadcast = true
} }
} }