mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-01-19 18:14:44 +00:00
Passenger interim (#501)
* properly handle interim and, thus, persistence for a pure passenger * persistence maintained during relog; message handling case reset at death
This commit is contained in:
parent
3003c8d490
commit
fa7342264e
|
|
@ -158,12 +158,13 @@ class WorldSessionActor extends Actor
|
|||
var squadUpdateCounter : Int = 0
|
||||
val queuedSquadActions : Seq[() => Unit] = Seq(SquadUpdates, NoSquadUpdates, NoSquadUpdates, NoSquadUpdates)
|
||||
/** Upstream message counter<br>
|
||||
* Checks for server acknowledgement of the following messages:<br>
|
||||
* `PlayerStateMessageUpstream`<br>
|
||||
* Checks for server acknowledgement of the following messages in the following conditions:<br>
|
||||
* `PlayerStateMessageUpstream` (infantry)<br>
|
||||
* `VehicleStateMessage` (driver seat only)<br>
|
||||
* `ChildObjectStateMessage` (any seat but driver)<br>
|
||||
* `ChildObjectStateMessage` (any gunner seat that is not the driver)<br>
|
||||
* `KeepAliveMessage` (any passenger seat that is not the driver)<br>
|
||||
* As they should arrive roughly every 250 milliseconds this allows for a very crude method of scheduling tasks up to four times per second */
|
||||
private var upstreamMessageCount : Int = 0
|
||||
var upstreamMessageCount : Int = 0
|
||||
var zoningType : Zoning.Method.Value = Zoning.Method.None
|
||||
var zoningChatMessageType : ChatMessageType.Value = ChatMessageType.CMT_QUIT
|
||||
var zoningStatus : Zoning.Status.Value = Zoning.Status.None
|
||||
|
|
@ -180,7 +181,10 @@ class WorldSessionActor extends Actor
|
|||
var zoneLoaded : Option[Boolean] = None
|
||||
/** a flag that forces the current zone to reload itself during a zoning operation */
|
||||
var zoneReload : Boolean = false
|
||||
var turnCounter : PlanetSideGUID=>Unit = TurnCounterDuringInterim
|
||||
var interimUngunnedVehicle : Option[PlanetSideGUID] = None
|
||||
var interimUngunnedVehicleSeat : Option[Int] = None
|
||||
var keepAliveFunc : ()=>Unit = NormalKeepAlive
|
||||
var turnCounterFunc : PlanetSideGUID=>Unit = TurnCounterDuringInterim
|
||||
|
||||
var clientKeepAlive : Cancellable = Default.Cancellable
|
||||
var progressBarUpdate : Cancellable = Default.Cancellable
|
||||
|
|
@ -299,7 +303,6 @@ class WorldSessionActor extends Actor
|
|||
handleGamePkt(pkt)
|
||||
|
||||
case PokeClient() =>
|
||||
persist()
|
||||
sendResponse(KeepAliveMessage())
|
||||
|
||||
case AvatarServiceResponse(toChannel, guid, reply) =>
|
||||
|
|
@ -1142,7 +1145,14 @@ class WorldSessionActor extends Actor
|
|||
//important! the LoadMapMessage must be processed by the client before the avatar is created
|
||||
player = tplayer
|
||||
setupAvatarFunc()
|
||||
turnCounter = TurnCounterDuringInterim
|
||||
//interimUngunnedVehicle should have been setup by setupAvatarFunc, if it is applicable
|
||||
turnCounterFunc = interimUngunnedVehicle match {
|
||||
case Some(_) =>
|
||||
TurnCounterDuringInterimWhileInPassengerSeat
|
||||
case None =>
|
||||
TurnCounterDuringInterim
|
||||
}
|
||||
keepAliveFunc = NormalKeepAlive
|
||||
upstreamMessageCount = 0
|
||||
persist()
|
||||
|
||||
|
|
@ -1151,7 +1161,14 @@ class WorldSessionActor extends Actor
|
|||
log.info(s"Player ${tplayer.Name} will respawn")
|
||||
player = tplayer
|
||||
setupAvatarFunc()
|
||||
turnCounter = TurnCounterDuringInterim
|
||||
//interimUngunnedVehicle should have been setup by setupAvatarFunc, if it is applicable
|
||||
turnCounterFunc = interimUngunnedVehicle match {
|
||||
case Some(_) =>
|
||||
TurnCounterDuringInterimWhileInPassengerSeat
|
||||
case None =>
|
||||
TurnCounterDuringInterim
|
||||
}
|
||||
keepAliveFunc = NormalKeepAlive
|
||||
upstreamMessageCount = 0
|
||||
persist()
|
||||
|
||||
|
|
@ -1835,6 +1852,7 @@ class WorldSessionActor extends Actor
|
|||
case AvatarResponse.Killed(mount) =>
|
||||
val respawnTimer = 300000 //milliseconds
|
||||
ToggleMaxSpecialState(enable = false)
|
||||
keepAliveFunc = NormalKeepAlive
|
||||
zoningStatus = Zoning.Status.None
|
||||
deadState = DeadState.Dead
|
||||
continent.GUID(mount) match {
|
||||
|
|
@ -1850,6 +1868,7 @@ class WorldSessionActor extends Actor
|
|||
log.warn(s"KillPlayer/SHOTS_WHILE_DEAD: client of ${avatar.name} fired $shotsWhileDead rounds while character was dead on server")
|
||||
shotsWhileDead = 0
|
||||
}
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
reviveTimer.cancel
|
||||
if(player.death_by == 0) {
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
|
@ -2458,6 +2477,10 @@ class WorldSessionActor extends Actor
|
|||
obj.Cloaked = tplayer.Cloaked
|
||||
}
|
||||
}
|
||||
else if(obj.Seats(seat_num).ControlledWeapon.isEmpty) {
|
||||
//the player will receive no messages consistently except the KeepAliveMessage echo
|
||||
keepAliveFunc = KeepAlivePersistence
|
||||
}
|
||||
AccessContents(obj)
|
||||
UpdateWeaponAtSeatPosition(obj, seat_num)
|
||||
MountingAction(tplayer, obj, seat_num)
|
||||
|
|
@ -2812,11 +2835,6 @@ class WorldSessionActor extends Actor
|
|||
sendResponse(VehicleStateMessage(vehicle_guid, unk1, pos, ang, vel, unk2, unk3, unk4, wheel_direction, unk5, unk6))
|
||||
if(player.VehicleSeated.contains(vehicle_guid)) {
|
||||
player.Position = pos
|
||||
GetVehicleAndSeat() match {
|
||||
case (Some(_), Some(seatNum)) if seatNum > 0 =>
|
||||
turnCounter(guid)
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
}
|
||||
case VehicleResponse.SendResponse(msg) =>
|
||||
|
|
@ -3536,8 +3554,8 @@ class WorldSessionActor extends Actor
|
|||
log.error("Unsupported " + default + " in " + msg)
|
||||
}
|
||||
|
||||
case KeepAliveMessage(code) =>
|
||||
sendResponse(KeepAliveMessage())
|
||||
case KeepAliveMessage(_) =>
|
||||
keepAliveFunc()
|
||||
|
||||
case msg@BeginZoningMessage() =>
|
||||
log.info("Reticulating splines ...")
|
||||
|
|
@ -3844,7 +3862,8 @@ class WorldSessionActor extends Actor
|
|||
|
||||
case msg @ PlayerStateMessageUpstream(avatar_guid, pos, vel, yaw, pitch, yaw_upper, seq_time, unk3, is_crouching, is_jumping, jump_thrust, is_cloaking, unk5, unk6) =>
|
||||
//log.info(s"$msg")
|
||||
turnCounter(avatar_guid)
|
||||
persist()
|
||||
turnCounterFunc(avatar_guid)
|
||||
val isMoving = WorldEntity.isMoving(vel)
|
||||
val isMovingPlus = isMoving || is_jumping || jump_thrust
|
||||
if(isMovingPlus) {
|
||||
|
|
@ -3911,7 +3930,8 @@ class WorldSessionActor extends Actor
|
|||
}) match {
|
||||
case None | Some(0) => ;
|
||||
case Some(_) =>
|
||||
turnCounter(player.GUID)
|
||||
persist()
|
||||
turnCounterFunc(player.GUID)
|
||||
}
|
||||
if(tool.GUID == object_guid) {
|
||||
//TODO set tool orientation?
|
||||
|
|
@ -3936,7 +3956,8 @@ class WorldSessionActor extends Actor
|
|||
GetVehicleAndSeat() match {
|
||||
case (Some(obj), Some(0)) =>
|
||||
//we're driving the vehicle
|
||||
turnCounter(player.GUID)
|
||||
persist()
|
||||
turnCounterFunc(player.GUID)
|
||||
val seat = obj.Seats(0)
|
||||
player.Position = pos //convenient
|
||||
if(seat.ControlledWeapon.isEmpty) {
|
||||
|
|
@ -7377,6 +7398,8 @@ class WorldSessionActor extends Actor
|
|||
interstellarFerry = None
|
||||
val vdef = vehicle.Definition
|
||||
val vguid = vehicle.GUID
|
||||
vehicle.Position = shiftPosition.getOrElse(vehicle.Position)
|
||||
vehicle.Orientation = shiftOrientation.getOrElse(vehicle.Orientation)
|
||||
val vdata = if(seat == 0) {
|
||||
//driver
|
||||
continent.Transport ! Zone.Vehicle.Spawn(vehicle)
|
||||
|
|
@ -7522,9 +7545,15 @@ class WorldSessionActor extends Actor
|
|||
val pdata = pdef.Packet.DetailedConstructorData(tplayer).get
|
||||
tplayer.VehicleSeated = vguid
|
||||
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
|
||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||
AccessContents(vehicle)
|
||||
UpdateWeaponAtSeatPosition(vehicle, seat)
|
||||
if(seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) {
|
||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||
AccessContents(vehicle)
|
||||
UpdateWeaponAtSeatPosition(vehicle, seat)
|
||||
}
|
||||
else {
|
||||
interimUngunnedVehicle = Some(vguid)
|
||||
interimUngunnedVehicleSeat = Some(seat)
|
||||
}
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.Id,
|
||||
AvatarAction.LoadPlayer(
|
||||
|
|
@ -7602,10 +7631,16 @@ class WorldSessionActor extends Actor
|
|||
val pdata = pdef.Packet.DetailedConstructorData(player).get
|
||||
player.VehicleSeated = vguid
|
||||
sendResponse(ObjectCreateDetailedMessage(pdef.ObjectId, pguid, pdata))
|
||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||
//log.info(s"AvatarRejoin: $vguid -> $vdata")
|
||||
AccessContents(vehicle)
|
||||
UpdateWeaponAtSeatPosition(vehicle, seat)
|
||||
if(seat == 0 || vehicle.Seats(seat).ControlledWeapon.nonEmpty) {
|
||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||
AccessContents(vehicle)
|
||||
UpdateWeaponAtSeatPosition(vehicle, seat)
|
||||
}
|
||||
else {
|
||||
interimUngunnedVehicle = Some(vguid)
|
||||
interimUngunnedVehicleSeat = Some(seat)
|
||||
}
|
||||
log.info(s"AvatarRejoin: ${player.Name} in ${vehicle.Definition.Name}")
|
||||
|
||||
case _ =>
|
||||
|
|
@ -8192,6 +8227,7 @@ class WorldSessionActor extends Actor
|
|||
def DismountAction(tplayer : Player, obj : PlanetSideGameObject with Mountable, seatNum : Int) : Unit = {
|
||||
val player_guid : PlanetSideGUID = tplayer.GUID
|
||||
log.info(s"DismountVehicleMsg: ${tplayer.Name} dismounts $obj from $seatNum")
|
||||
keepAliveFunc = NormalKeepAlive
|
||||
sendResponse(DismountVehicleMsg(player_guid, BailType.Normal, false))
|
||||
continent.VehicleEvents ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, BailType.Normal, false))
|
||||
}
|
||||
|
|
@ -10225,14 +10261,81 @@ class WorldSessionActor extends Actor
|
|||
* @param guid the player's globally unique identifier number
|
||||
*/
|
||||
def TurnCounterDuringInterim(guid : PlanetSideGUID) : Unit = {
|
||||
upstreamMessageCount = 0
|
||||
if(player.GUID == guid && player.Zone == continent) {
|
||||
turnCounter = NormalTurnCounter
|
||||
turnCounterFunc = NormalTurnCounter
|
||||
}
|
||||
else {
|
||||
upstreamMessageCount = 0
|
||||
}
|
||||
|
||||
/**
|
||||
* During the interim period between the avatar being in one place/zone
|
||||
* and completing the process of transitioning to another place/zone,
|
||||
* the upstream message counter is zero'd
|
||||
* awaiting new activity from the client.
|
||||
* Until new upstream messages that pass some tests against their data start being reported,
|
||||
* the counter does not accumulate properly.<br>
|
||||
* <br>
|
||||
* In the case that the transitioning player is seated in a vehicle seat
|
||||
* that is not the driver and does not have a mounted weapon under its control,
|
||||
* no obvious feedback will be provided by the client.
|
||||
* For example, when as infantry, a `PlayerStateMessageUpstream` packet is dispatched by the client.
|
||||
* For example, when in the driver seat, a `VehicleStateMessage` is dispatched by the client.
|
||||
* In the given case, the only packet that indicates the player is seated is a `KeepAliveMessage`.
|
||||
* Detection of this `KeepALiveMessage`, for the purpose of transitioning logic,
|
||||
* can not be instantaneous to the zoning process or other checks for proper zoning conditions that will be disrupted.
|
||||
* To avoid complications, the player in such a seat is initially spawned as infantry on their own client,
|
||||
* realizes the state transition confirmation for infantry (turn counter),
|
||||
* and is forced to transition into being seated,
|
||||
* and only at that time will begin registering `KeepAliveMessage` to mark the end of their interim period.
|
||||
* @param guid the player's globally unique identifier number
|
||||
*/
|
||||
def TurnCounterDuringInterimWhileInPassengerSeat(guid : PlanetSideGUID) : Unit = {
|
||||
upstreamMessageCount = 0
|
||||
val pguid = player.GUID
|
||||
if(pguid == guid && player.Zone == continent) {
|
||||
(continent.GUID(interimUngunnedVehicle), interimUngunnedVehicle, interimUngunnedVehicleSeat) match {
|
||||
case (Some(vehicle : Vehicle), Some(vguid), Some(seat)) =>
|
||||
//sit down
|
||||
sendResponse(ObjectAttachMessage(vguid, pguid, seat))
|
||||
AccessContents(vehicle)
|
||||
keepAliveFunc = KeepAlivePersistence
|
||||
case _ => ;
|
||||
//we can't find a vehicle? and we're still here? that's bad
|
||||
player.VehicleSeated = None
|
||||
}
|
||||
interimUngunnedVehicle = None
|
||||
interimUngunnedVehicleSeat = None
|
||||
turnCounterFunc = NormalTurnCounter
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The normal response to receiving a `KeepAliveMessage` packet from the client.<br>
|
||||
* <br>
|
||||
* Even though receiving a `KeepAliveMessage` outside of zoning is uncommon,
|
||||
* the behavior should be configured to maintain a neutral action.
|
||||
* @see `KeepAliveMessage`
|
||||
* @see `keepAliveFunc`
|
||||
*/
|
||||
def NormalKeepAlive() : Unit = { }
|
||||
|
||||
/**
|
||||
* The atypical response to receiving a `KeepAliveMessage` packet from the client.<br>
|
||||
* <br>
|
||||
* `KeepAliveMessage` packets are the primary vehicle for persistence due to client reporting
|
||||
* in the case where the player's avatar is riding in a vehicle in a seat with no vehicle.
|
||||
* @see `KeepAliveMessage`
|
||||
* @see `keepAliveFunc`
|
||||
* @see `turnCounterFunc`
|
||||
* @see `persist`
|
||||
*/
|
||||
def KeepAlivePersistence() : Unit = {
|
||||
//log.info(s"KeepAlive in a vehicle - $upstreamMessageCount")
|
||||
interimUngunnedVehicle = None
|
||||
persist()
|
||||
turnCounterFunc(player.GUID)
|
||||
}
|
||||
|
||||
def AdministrativeKick(tplayer : Player, permitKickSelf : Boolean = false) : Boolean = {
|
||||
if(permitKickSelf || tplayer != player) { //stop kicking yourself
|
||||
tplayer.death_by = -1
|
||||
|
|
|
|||
Loading…
Reference in a new issue