mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-07-16 08:55:18 +00:00
further changes to session actor handler classes
This commit is contained in:
parent
f012126fae
commit
39ad0fa997
10 changed files with 467 additions and 330 deletions
|
|
@ -283,8 +283,8 @@ class SessionActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], con
|
|||
sessionFuncs.vehicles.handleCanNotChangeDeployment(obj, state, reason)
|
||||
|
||||
/* rare messages */
|
||||
case ProximityUnit.StopAction(term, target) =>
|
||||
sessionFuncs.terminals.LocalStopUsingProximityUnit(term, target)
|
||||
case ProximityUnit.StopAction(term, _) =>
|
||||
sessionFuncs.terminals.LocalStopUsingProximityUnit(term)
|
||||
|
||||
case SessionActor.Suicide() =>
|
||||
sessionFuncs.suicide(sessionFuncs.player)
|
||||
|
|
|
|||
|
|
@ -32,7 +32,10 @@ class SessionAvatarHandlers(
|
|||
implicit val context: ActorContext
|
||||
) extends CommonSessionInterfacingFunctionality {
|
||||
//TODO player characters only exist within a certain range of GUIDs for a given zone; this is overkill
|
||||
private[support] var lastSeenStreamMessage: Array[Long] = Array.fill[Long](65535)(elem = 0L)
|
||||
private[support] var lastSeenStreamMessage: Array[SessionAvatarHandlers.LastUpstream] = {
|
||||
SessionAvatarHandlers.blankUpstreamMessages(65535)
|
||||
}
|
||||
private[this] val hidingPlayerRandomizer = new scala.util.Random
|
||||
|
||||
/**
|
||||
* na
|
||||
|
|
@ -47,12 +50,15 @@ class SessionAvatarHandlers(
|
|||
Service.defaultPlayerGUID
|
||||
}
|
||||
val isNotSameTarget = resolvedPlayerGuid != guid
|
||||
val isSameTarget = !isNotSameTarget
|
||||
reply match {
|
||||
/* special messages */
|
||||
case AvatarResponse.TeardownConnection() =>
|
||||
log.trace(s"ending ${player.Name}'s old session by event system request (relog)")
|
||||
context.stop(context.self)
|
||||
|
||||
case AvatarResponse.PlayerState(
|
||||
/* really common messages (very frequently, every life) */
|
||||
case pstate @ AvatarResponse.PlayerState(
|
||||
pos,
|
||||
vel,
|
||||
yaw,
|
||||
|
|
@ -68,12 +74,10 @@ class SessionAvatarHandlers(
|
|||
) if isNotSameTarget =>
|
||||
val now = System.currentTimeMillis()
|
||||
val (location, time, distanceSq): (Vector3, Long, Float) = if (spectating) {
|
||||
val r = new scala.util.Random
|
||||
val r1 = 2 + r.nextInt(30).toFloat
|
||||
val r2 = 2 + r.nextInt(4000).toFloat
|
||||
(Vector3(r2, r2, r1), 0L, 0f)
|
||||
val r2 = 2 + hidingPlayerRandomizer.nextInt(4000).toFloat
|
||||
(Vector3(r2, r2, 1f), 0L, 0f)
|
||||
} else {
|
||||
val before = lastSeenStreamMessage(guid.guid)
|
||||
val before = lastSeenStreamMessage(guid.guid).time
|
||||
val dist = Vector3.DistanceSquared(player.Position, pos)
|
||||
(pos, now - before, dist)
|
||||
}
|
||||
|
|
@ -86,157 +90,45 @@ class SessionAvatarHandlers(
|
|||
yaw,
|
||||
pitch,
|
||||
yawUpper,
|
||||
timestamp=0,
|
||||
timestamp = 0,
|
||||
isCrouching,
|
||||
isJumping,
|
||||
jumpThrust,
|
||||
isCloaking
|
||||
)
|
||||
)
|
||||
lastSeenStreamMessage(guid.guid) = now
|
||||
lastSeenStreamMessage(guid.guid) = SessionAvatarHandlers.LastUpstream(Some(pstate), now)
|
||||
}
|
||||
|
||||
case AvatarResponse.SendResponse(msg) =>
|
||||
sendResponse(msg)
|
||||
|
||||
case AvatarResponse.SendResponseTargeted(targetGuid, msg) if resolvedPlayerGuid == targetGuid =>
|
||||
sendResponse(msg)
|
||||
|
||||
case AvatarResponse.Revive(revivalTargetGuid) if resolvedPlayerGuid == revivalTargetGuid =>
|
||||
log.info(s"No time for rest, ${player.Name}. Back on your feet!")
|
||||
sessionData.zoning.spawn.reviveTimer.cancel()
|
||||
sessionData.zoning.spawn.deadState = DeadState.Alive
|
||||
player.Revive
|
||||
val health = player.Health
|
||||
sendResponse(PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.Alive, timer_max=0, timer=0, player.Position, player.Faction, unk5=true))
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.PlanetsideAttributeToAll(revivalTargetGuid, attribute_type=0, health)
|
||||
)
|
||||
|
||||
case AvatarResponse.ConcealPlayer() =>
|
||||
sendResponse(GenericObjectActionMessage(guid, code=9))
|
||||
|
||||
case AvatarResponse.EnvironmentalDamage(_, _, _) =>
|
||||
//TODO damage marker?
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||
|
||||
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
||||
// guid = victim // killer = killer
|
||||
sendResponse(DestroyMessage(victim, killer, weapon, pos))
|
||||
|
||||
case AvatarResponse.DestroyDisplay(killer, victim, method, unk) =>
|
||||
sendResponse(sessionData.destroyDisplayMessage(killer, victim, method, unk))
|
||||
// TODO Temporary thing that should go somewhere else and use proper xp values
|
||||
if (killer.CharId == avatar.id && killer.Faction != victim.Faction) {
|
||||
avatarActor ! AvatarActor.AwardBep((1000 * Config.app.game.bepRate).toLong, ExperienceType.Normal)
|
||||
avatarActor ! AvatarActor.AwardCep((100 * Config.app.game.cepRate).toLong)
|
||||
}
|
||||
|
||||
case AvatarResponse.DropItem(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.EquipmentInHand(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.GenericObjectAction(objectGuid, actionCode) if isNotSameTarget =>
|
||||
sendResponse(GenericObjectActionMessage(objectGuid, actionCode))
|
||||
|
||||
case AvatarResponse.HitHint(source_guid) if player.isAlive =>
|
||||
sendResponse(HitHint(source_guid, guid))
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||
|
||||
case AvatarResponse.DropSpecialItem() =>
|
||||
sessionData.dropSpecialSlotItem()
|
||||
|
||||
case AvatarResponse.Killed(mount) =>
|
||||
val cause = (player.LastDamage match {
|
||||
case Some(reason) => (Some(reason), reason.adversarial)
|
||||
case None => (None, None)
|
||||
}) match {
|
||||
case (_, Some(adversarial)) => adversarial.attacker.Name
|
||||
case (Some(reason), None) => s"a ${reason.interaction.cause.getClass.getSimpleName}"
|
||||
case _ => s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)"
|
||||
}
|
||||
log.info(s"${player.Name} has died, killed by $cause")
|
||||
val respawnTimer = 300.seconds
|
||||
//drop free hand item
|
||||
player.FreeHand.Equipment.foreach { item =>
|
||||
DropEquipmentFromInventory(player)(item)
|
||||
}
|
||||
sessionData.dropSpecialSlotItem()
|
||||
sessionData.toggleMaxSpecialState(enable = false)
|
||||
|
||||
if (player.LastDamage.flatMap { damage =>
|
||||
Some(damage.interaction.cause match {
|
||||
case cause: ExplodingEntityReason => cause.entity.isInstanceOf[VehicleSpawnPad]
|
||||
case _ => false
|
||||
}) }.contains(true)
|
||||
) {
|
||||
//also, @SVCP_Killed_TooCloseToPadOnCreate^n~ or "... within n meters of pad ..."
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, wideContents = false, "", "@SVCP_Killed_OnPadOnCreate", None))
|
||||
}
|
||||
sessionData.keepAliveFunc = sessionData.zoning.NormalKeepAlive
|
||||
sessionData.zoning.zoningStatus = Zoning.Status.None
|
||||
sessionData.zoning.spawn.deadState = DeadState.Dead
|
||||
continent.GUID(mount).collect { case obj: Vehicle =>
|
||||
sessionData.vehicles.ConditionalDriverVehicleControl(obj)
|
||||
sessionData.vehicles.serverVehicleControlVelocity = None
|
||||
sessionData.unaccessContainer(obj)
|
||||
}
|
||||
sessionData.playerActionsToCancel()
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel")
|
||||
if (sessionData.shooting.shotsWhileDead > 0) {
|
||||
log.warn(
|
||||
s"KillPlayer/SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionData.shooting.shotsWhileDead} rounds while character was dead on server"
|
||||
)
|
||||
sessionData.shooting.shotsWhileDead = 0
|
||||
}
|
||||
sessionData.zoning.spawn.reviveTimer.cancel()
|
||||
if (player.death_by == 0) {
|
||||
sessionData.zoning.spawn.reviveTimer = context.system.scheduler.scheduleOnce(respawnTimer) {
|
||||
sessionData.cluster ! ICS.GetRandomSpawnPoint(
|
||||
Zones.sanctuaryZoneNumber(player.Faction),
|
||||
player.Faction,
|
||||
Seq(SpawnGroup.Sanctuary),
|
||||
context.self
|
||||
)
|
||||
}
|
||||
} else {
|
||||
sessionData.zoning.spawn.HandleReleaseAvatar(player, continent)
|
||||
}
|
||||
AvatarActor.savePlayerLocation(player)
|
||||
sessionData.renewCharSavedTimer(fixedLen = 1800L, varLen = 0L)
|
||||
|
||||
case AvatarResponse.LoadPlayer(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.LoadProjectile(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.ObjectDelete(itemGuid, unk) if isNotSameTarget =>
|
||||
sendResponse(ObjectDeleteMessage(itemGuid, unk))
|
||||
|
||||
case AvatarResponse.ObjectHeld(slot, _) if resolvedPlayerGuid == guid && slot > -1 =>
|
||||
case AvatarResponse.ObjectHeld(slot, _)
|
||||
if isSameTarget && player.VisibleSlots.contains(slot) =>
|
||||
sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
|
||||
//Stop using proximity terminals if player unholsters a weapon
|
||||
if (player.VisibleSlots.contains(slot)) {
|
||||
continent.GUID(sessionData.terminals.usingMedicalTerminal).collect {
|
||||
case term: Terminal with ProximityUnit =>
|
||||
sessionData.terminals.StopUsingProximityUnit(term)
|
||||
}
|
||||
continent.GUID(sessionData.terminals.usingMedicalTerminal).collect {
|
||||
case term: Terminal with ProximityUnit => sessionData.terminals.StopUsingProximityUnit(term)
|
||||
}
|
||||
|
||||
case AvatarResponse.ObjectHeld(slot, _)
|
||||
if isSameTarget && slot > -1 =>
|
||||
sendResponse(ObjectHeldMessage(guid, slot, unk1=true))
|
||||
|
||||
case AvatarResponse.ObjectHeld(_, _)
|
||||
if isSameTarget => ()
|
||||
|
||||
case AvatarResponse.ObjectHeld(_, previousSlot) =>
|
||||
sendResponse(ObjectHeldMessage(guid, previousSlot, unk1=false))
|
||||
|
||||
case AvatarResponse.OxygenState(player, vehicle) =>
|
||||
sendResponse(OxygenStateMessage(
|
||||
DrowningTarget(player.guid, player.progress, player.state),
|
||||
vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
|
||||
))
|
||||
case AvatarResponse.ChangeFireState_Start(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Start(weaponGuid))
|
||||
|
||||
case AvatarResponse.ChangeFireState_Stop(weaponGuid) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireStateMessage_Stop(weaponGuid))
|
||||
|
||||
case AvatarResponse.LoadPlayer(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.EquipmentInHand(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.PlanetsideAttribute(attributeType, attributeValue) if isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
|
||||
|
|
@ -244,73 +136,43 @@ class SessionAvatarHandlers(
|
|||
case AvatarResponse.PlanetsideAttributeToAll(attributeType, attributeValue) =>
|
||||
sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
|
||||
|
||||
case AvatarResponse.PlanetsideAttributeSelf(attributeType, attributeValue) if resolvedPlayerGuid == guid =>
|
||||
case AvatarResponse.PlanetsideAttributeSelf(attributeType, attributeValue) if isSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(guid, attributeType, attributeValue))
|
||||
|
||||
case AvatarResponse.ProjectileExplodes(projectileGuid, projectile) =>
|
||||
sendResponse(
|
||||
ProjectileStateMessage(
|
||||
projectileGuid,
|
||||
projectile.Position,
|
||||
shot_vel = Vector3.Zero,
|
||||
projectile.Orientation,
|
||||
sequence_num=0,
|
||||
end=true,
|
||||
hit_target_guid=PlanetSideGUID(0)
|
||||
)
|
||||
case AvatarResponse.GenericObjectAction(objectGuid, actionCode) if isNotSameTarget =>
|
||||
sendResponse(GenericObjectActionMessage(objectGuid, actionCode))
|
||||
|
||||
case AvatarResponse.HitHint(sourceGuid) if player.isAlive =>
|
||||
sendResponse(HitHint(sourceGuid, guid))
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||
|
||||
case AvatarResponse.DestroyDisplay(killer, victim, method, unk)
|
||||
if killer.CharId == avatar.id && killer.Faction != victim.Faction =>
|
||||
// TODO Temporary thing that should go somewhere else and use proper xp values
|
||||
sendResponse(sessionData.destroyDisplayMessage(killer, victim, method, unk))
|
||||
avatarActor ! AvatarActor.AwardBep((1000 * Config.app.game.bepRate).toLong, ExperienceType.Normal)
|
||||
avatarActor ! AvatarActor.AwardCep((100 * Config.app.game.cepRate).toLong)
|
||||
|
||||
case AvatarResponse.Destroy(victim, killer, weapon, pos) =>
|
||||
// guid = victim // killer = killer
|
||||
sendResponse(DestroyMessage(victim, killer, weapon, pos))
|
||||
|
||||
case AvatarResponse.DestroyDisplay(killer, victim, method, unk) =>
|
||||
sendResponse(sessionData.destroyDisplayMessage(killer, victim, method, unk))
|
||||
|
||||
case AvatarResponse.TerminalOrderResult(terminalGuid, action, result)
|
||||
if result && (action == TransactionType.Buy || action == TransactionType.Loadout) =>
|
||||
sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
|
||||
sessionData.terminals.lastTerminalOrderFulfillment = true
|
||||
AvatarActor.savePlayerData(player)
|
||||
sessionData.renewCharSavedTimer(
|
||||
Config.app.game.savedMsg.interruptedByAction.fixed,
|
||||
Config.app.game.savedMsg.interruptedByAction.variable
|
||||
)
|
||||
sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
|
||||
|
||||
case AvatarResponse.ProjectileAutoLockAwareness(mode) =>
|
||||
sendResponse(GenericActionMessage(mode))
|
||||
|
||||
case AvatarResponse.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid) if isNotSameTarget =>
|
||||
sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
|
||||
|
||||
case AvatarResponse.PutDownFDU(target) if isNotSameTarget =>
|
||||
sendResponse(GenericObjectActionMessage(target, code=53))
|
||||
|
||||
case AvatarResponse.Release(tplayer) if isNotSameTarget =>
|
||||
sessionData.zoning.spawn.DepictPlayerAsCorpse(tplayer)
|
||||
|
||||
case AvatarResponse.Reload(itemGuid) if isNotSameTarget =>
|
||||
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
|
||||
|
||||
case AvatarResponse.SetEmpire(objectGuid, faction) if isNotSameTarget =>
|
||||
sendResponse(SetEmpireMessage(objectGuid, faction))
|
||||
|
||||
case AvatarResponse.StowEquipment(target, slot, item) if isNotSameTarget =>
|
||||
val definition = item.Definition
|
||||
sendResponse(
|
||||
ObjectCreateDetailedMessage(
|
||||
definition.ObjectId,
|
||||
item.GUID,
|
||||
ObjectCreateMessageParent(target, slot),
|
||||
definition.Packet.DetailedConstructorData(item).get
|
||||
)
|
||||
)
|
||||
|
||||
case AvatarResponse.WeaponDryFire(weaponGuid) if isNotSameTarget =>
|
||||
continent.GUID(weaponGuid).collect {
|
||||
case tool: Tool if tool.Magazine == 0 =>
|
||||
// check that the magazine is still empty before sending WeaponDryFireMessage
|
||||
// if it has been reloaded since then, other clients not see it firing
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
case _ =>
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
}
|
||||
|
||||
case AvatarResponse.TerminalOrderResult(terminalGuid, action, result) =>
|
||||
sendResponse(ItemTransactionResultMessage(terminalGuid, action, result))
|
||||
sessionData.terminals.lastTerminalOrderFulfillment = true
|
||||
if (result &&
|
||||
(action == TransactionType.Buy || action == TransactionType.Loadout)) {
|
||||
AvatarActor.savePlayerData(player)
|
||||
sessionData.renewCharSavedTimer(
|
||||
Config.app.game.savedMsg.interruptedByAction.fixed,
|
||||
Config.app.game.savedMsg.interruptedByAction.variable
|
||||
)
|
||||
}
|
||||
|
||||
case AvatarResponse.ChangeExosuit(
|
||||
target,
|
||||
|
|
@ -425,13 +287,13 @@ class SessionAvatarHandlers(
|
|||
DropLeftovers(player)(drops)
|
||||
|
||||
case AvatarResponse.ChangeLoadout(target, armor, exosuit, subtype, slot, _, oldHolsters, _, _, _, _) =>
|
||||
//redraw handled by callbacks
|
||||
sendResponse(ArmorChangedMessage(target, exosuit, subtype))
|
||||
sendResponse(PlanetsideAttributeMessage(target, attribute_type=4, armor))
|
||||
//happening to some other player
|
||||
sendResponse(ObjectHeldMessage(target, slot, unk1=false))
|
||||
//cleanup
|
||||
oldHolsters.foreach { case (_, guid) => sendResponse(ObjectDeleteMessage(guid, unk1=0)) }
|
||||
//redraw handled by callback
|
||||
|
||||
case AvatarResponse.UseKit(kguid, kObjId) =>
|
||||
sendResponse(
|
||||
|
|
@ -456,9 +318,191 @@ class SessionAvatarHandlers(
|
|||
|
||||
case AvatarResponse.KitNotUsed(_, msg) =>
|
||||
sessionData.kitToBeUsed = None
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_225, wideContents=false, recipient="", msg, note=None))
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_225, msg))
|
||||
|
||||
case AvatarResponse.SendResponse(msg) =>
|
||||
sendResponse(msg)
|
||||
|
||||
case AvatarResponse.SendResponseTargeted(targetGuid, msg) if resolvedPlayerGuid == targetGuid =>
|
||||
sendResponse(msg)
|
||||
|
||||
/* common messages (maybe once every respawn) */
|
||||
case AvatarResponse.Reload(itemGuid) if isNotSameTarget =>
|
||||
sendResponse(ReloadMessage(itemGuid, ammo_clip=1, unk1=0))
|
||||
|
||||
case AvatarResponse.Killed(mount) =>
|
||||
//log and chat messages
|
||||
val cause = player.LastDamage.flatMap { damage =>
|
||||
damage.interaction.cause match {
|
||||
case cause: ExplodingEntityReason if cause.entity.isInstanceOf[VehicleSpawnPad] =>
|
||||
//also, @SVCP_Killed_TooCloseToPadOnCreate^n~ or "... within n meters of pad ..."
|
||||
sendResponse(ChatMsg(ChatMessageType.UNK_227, "@SVCP_Killed_OnPadOnCreate"))
|
||||
case _ => ()
|
||||
}
|
||||
damage match {
|
||||
case damage if damage.adversarial.nonEmpty => Some(damage.adversarial.get.attacker.Name)
|
||||
case damage => Some(s"a ${damage.interaction.cause.getClass.getSimpleName}")
|
||||
}
|
||||
}.getOrElse { s"an unfortunate circumstance (probably ${player.Sex.pronounObject} own fault)" }
|
||||
log.info(s"${player.Name} has died, killed by $cause")
|
||||
if (sessionData.shooting.shotsWhileDead > 0) {
|
||||
log.warn(
|
||||
s"SHOTS_WHILE_DEAD: client of ${avatar.name} fired ${sessionData.shooting.shotsWhileDead} rounds while character was dead on server"
|
||||
)
|
||||
sessionData.shooting.shotsWhileDead = 0
|
||||
}
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason(msg = "cancel")
|
||||
sessionData.renewCharSavedTimer(fixedLen = 1800L, varLen = 0L)
|
||||
|
||||
//player state changes
|
||||
player.FreeHand.Equipment.foreach { item =>
|
||||
DropEquipmentFromInventory(player)(item)
|
||||
}
|
||||
sessionData.dropSpecialSlotItem()
|
||||
sessionData.toggleMaxSpecialState(enable = false)
|
||||
sessionData.keepAliveFunc = sessionData.zoning.NormalKeepAlive
|
||||
sessionData.zoning.zoningStatus = Zoning.Status.None
|
||||
sessionData.zoning.spawn.deadState = DeadState.Dead
|
||||
continent.GUID(mount).collect { case obj: Vehicle =>
|
||||
sessionData.vehicles.ConditionalDriverVehicleControl(obj)
|
||||
sessionData.vehicles.serverVehicleControlVelocity = None
|
||||
sessionData.unaccessContainer(obj)
|
||||
}
|
||||
sessionData.playerActionsToCancel()
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
AvatarActor.savePlayerLocation(player)
|
||||
|
||||
//respawn
|
||||
val respawnTimer = 300.seconds
|
||||
sessionData.zoning.spawn.reviveTimer.cancel()
|
||||
if (player.death_by == 0) {
|
||||
sessionData.zoning.spawn.reviveTimer = context.system.scheduler.scheduleOnce(respawnTimer) {
|
||||
sessionData.cluster ! ICS.GetRandomSpawnPoint(
|
||||
Zones.sanctuaryZoneNumber(player.Faction),
|
||||
player.Faction,
|
||||
Seq(SpawnGroup.Sanctuary),
|
||||
context.self
|
||||
)
|
||||
}
|
||||
} else {
|
||||
sessionData.zoning.spawn.HandleReleaseAvatar(player, continent)
|
||||
}
|
||||
|
||||
case AvatarResponse.Release(tplayer) if isNotSameTarget =>
|
||||
sessionData.zoning.spawn.DepictPlayerAsCorpse(tplayer)
|
||||
|
||||
case AvatarResponse.Revive(revivalTargetGuid) if resolvedPlayerGuid == revivalTargetGuid =>
|
||||
log.info(s"No time for rest, ${player.Name}. Back on your feet!")
|
||||
sessionData.zoning.spawn.reviveTimer.cancel()
|
||||
sessionData.zoning.spawn.deadState = DeadState.Alive
|
||||
player.Revive
|
||||
val health = player.Health
|
||||
sendResponse(PlanetsideAttributeMessage(revivalTargetGuid, attribute_type=0, health))
|
||||
sendResponse(AvatarDeadStateMessage(DeadState.Alive, timer_max=0, timer=0, player.Position, player.Faction, unk5=true))
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.PlanetsideAttributeToAll(revivalTargetGuid, attribute_type=0, health)
|
||||
)
|
||||
|
||||
/* uncommon messages (utility, or once in a while) */
|
||||
case AvatarResponse.ChangeAmmo(weapon_guid, weapon_slot, previous_guid, ammo_id, ammo_guid, ammo_data)
|
||||
if isNotSameTarget =>
|
||||
sendResponse(ObjectDetachMessage(weapon_guid, previous_guid, Vector3.Zero, 0))
|
||||
sendResponse(
|
||||
ObjectCreateMessage(
|
||||
ammo_id,
|
||||
ammo_guid,
|
||||
ObjectCreateMessageParent(weapon_guid, weapon_slot),
|
||||
ammo_data
|
||||
)
|
||||
)
|
||||
sendResponse(ChangeAmmoMessage(weapon_guid, 1))
|
||||
|
||||
case AvatarResponse.ChangeFireMode(itemGuid, mode) if isNotSameTarget =>
|
||||
sendResponse(ChangeFireModeMessage(itemGuid, mode))
|
||||
|
||||
case AvatarResponse.ConcealPlayer() =>
|
||||
sendResponse(GenericObjectActionMessage(guid, code=9))
|
||||
|
||||
case AvatarResponse.EnvironmentalDamage(_, _, _) =>
|
||||
//TODO damage marker?
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_dmg")
|
||||
|
||||
case AvatarResponse.DropItem(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.ObjectDelete(itemGuid, unk) if isNotSameTarget =>
|
||||
sendResponse(ObjectDeleteMessage(itemGuid, unk))
|
||||
|
||||
/* rare messages */
|
||||
case AvatarResponse.SetEmpire(objectGuid, faction) if isNotSameTarget =>
|
||||
sendResponse(SetEmpireMessage(objectGuid, faction))
|
||||
|
||||
case AvatarResponse.DropSpecialItem() =>
|
||||
sessionData.dropSpecialSlotItem()
|
||||
|
||||
case AvatarResponse.OxygenState(player, vehicle) =>
|
||||
sendResponse(OxygenStateMessage(
|
||||
DrowningTarget(player.guid, player.progress, player.state),
|
||||
vehicle.flatMap { vinfo => Some(DrowningTarget(vinfo.guid, vinfo.progress, vinfo.state)) }
|
||||
))
|
||||
|
||||
case AvatarResponse.LoadProjectile(pkt) if isNotSameTarget =>
|
||||
sendResponse(pkt)
|
||||
|
||||
case AvatarResponse.ProjectileState(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid) if isNotSameTarget =>
|
||||
sendResponse(ProjectileStateMessage(projectileGuid, shotPos, shotVel, shotOrient, seq, end, targetGuid))
|
||||
|
||||
case AvatarResponse.ProjectileExplodes(projectileGuid, projectile) =>
|
||||
sendResponse(
|
||||
ProjectileStateMessage(
|
||||
projectileGuid,
|
||||
projectile.Position,
|
||||
shot_vel = Vector3.Zero,
|
||||
projectile.Orientation,
|
||||
sequence_num=0,
|
||||
end=true,
|
||||
hit_target_guid=PlanetSideGUID(0)
|
||||
)
|
||||
)
|
||||
sendResponse(ObjectDeleteMessage(projectileGuid, unk1=2))
|
||||
|
||||
case AvatarResponse.ProjectileAutoLockAwareness(mode) =>
|
||||
sendResponse(GenericActionMessage(mode))
|
||||
|
||||
case AvatarResponse.PutDownFDU(target) if isNotSameTarget =>
|
||||
sendResponse(GenericObjectActionMessage(target, code=53))
|
||||
|
||||
case AvatarResponse.StowEquipment(target, slot, item) if isNotSameTarget =>
|
||||
val definition = item.Definition
|
||||
sendResponse(
|
||||
ObjectCreateDetailedMessage(
|
||||
definition.ObjectId,
|
||||
item.GUID,
|
||||
ObjectCreateMessageParent(target, slot),
|
||||
definition.Packet.DetailedConstructorData(item).get
|
||||
)
|
||||
)
|
||||
|
||||
case AvatarResponse.WeaponDryFire(weaponGuid) if isNotSameTarget =>
|
||||
continent.GUID(weaponGuid).collect {
|
||||
case tool: Tool if tool.Magazine == 0 =>
|
||||
// check that the magazine is still empty before sending WeaponDryFireMessage
|
||||
// if it has been reloaded since then, other clients not see it firing
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
case _ =>
|
||||
sendResponse(WeaponDryFireMessage(weaponGuid))
|
||||
}
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object SessionAvatarHandlers {
|
||||
private[support] case class LastUpstream(msg: Option[AvatarResponse.PlayerState], time: Long)
|
||||
|
||||
private[support] def blankUpstreamMessages(n: Int): Array[LastUpstream] = {
|
||||
Array.fill[SessionAvatarHandlers.LastUpstream](n)(elem = LastUpstream(None, 0L))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -257,10 +257,7 @@ class SessionData(
|
|||
}
|
||||
case None => ()
|
||||
}
|
||||
val wepInHand: Boolean = player.Slot(player.DrawnSlot).Equipment match {
|
||||
case Some(item) => item.Definition == GlobalDefinitions.bolt_driver
|
||||
case _ => false
|
||||
}
|
||||
val eagleEye: Boolean = canSeeReallyFar
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.PlayerState(
|
||||
|
|
@ -276,7 +273,7 @@ class SessionData(
|
|||
jumpThrust,
|
||||
isCloaking,
|
||||
player.spectator,
|
||||
wepInHand
|
||||
eagleEye
|
||||
)
|
||||
)
|
||||
squad.updateSquad()
|
||||
|
|
@ -2910,6 +2907,23 @@ class SessionData(
|
|||
heightLast = zHeight
|
||||
}
|
||||
|
||||
def canSeeReallyFar: Boolean = {
|
||||
findEquipment().exists {
|
||||
case weapon: Tool
|
||||
if weapon.Size == EquipmentSize.Rifle &&
|
||||
(weapon.Projectile ne GlobalDefinitions.no_projectile) &&
|
||||
player.Crouching &&
|
||||
player.avatar
|
||||
.implants
|
||||
.exists { p =>
|
||||
p.collect { implant => implant.definition.implantType == ImplantType.RangeMagnifier && implant.initialized }.nonEmpty
|
||||
} =>
|
||||
true
|
||||
case item =>
|
||||
item.Definition == GlobalDefinitions.bolt_driver || item.Definition == GlobalDefinitions.heavy_sniper
|
||||
}
|
||||
}
|
||||
|
||||
def displayCharSavedMsgThenRenewTimer(fixedLen: Long, varLen: Long): Unit = {
|
||||
charSaved()
|
||||
renewCharSavedTimer(fixedLen, varLen)
|
||||
|
|
|
|||
|
|
@ -114,16 +114,16 @@ class SessionLocalHandlers(
|
|||
case LocalResponse.HackObject(targetGuid, unk1, unk2) =>
|
||||
HackObject(targetGuid, unk1, unk2)
|
||||
|
||||
case LocalResponse.SendPlanetsideAttributeMessage(targetGuid, attributeType, attributeValue) =>
|
||||
case LocalResponse.PlanetsideAttribute(targetGuid, attributeType, attributeValue) =>
|
||||
SendPlanetsideAttributeMessage(targetGuid, attributeType, attributeValue)
|
||||
|
||||
case LocalResponse.SendGenericObjectActionMessage(targetGuid, actionNumber) =>
|
||||
case LocalResponse.GenericObjectAction(targetGuid, actionNumber) =>
|
||||
sendResponse(GenericObjectActionMessage(targetGuid, actionNumber))
|
||||
|
||||
case LocalResponse.SendGenericActionMessage(actionNumber) =>
|
||||
case LocalResponse.GenericActionMessage(actionNumber) =>
|
||||
sendResponse(GenericActionMessage(actionNumber))
|
||||
|
||||
case LocalResponse.SendChatMsg(msg) =>
|
||||
case LocalResponse.ChatMessage(msg) =>
|
||||
sendResponse(msg)
|
||||
|
||||
case LocalResponse.SendPacket(packet) =>
|
||||
|
|
@ -142,7 +142,7 @@ class SessionLocalHandlers(
|
|||
sendResponse(TriggerSoundMessage(TriggeredSound.LLUDeconstruct, position, unk=20, volume=0.8000001f))
|
||||
sendResponse(ObjectDeleteMessage(lluGuid, unk1=0))
|
||||
// If the player was holding the LLU, remove it from their tracked special item slot
|
||||
sessionData.specialItemSlotGuid.foreach { case guid if guid == lluGuid =>
|
||||
sessionData.specialItemSlotGuid.collect { case guid if guid == lluGuid =>
|
||||
sessionData.specialItemSlotGuid = None
|
||||
player.Carrying = None
|
||||
}
|
||||
|
|
@ -198,20 +198,19 @@ class SessionLocalHandlers(
|
|||
case LocalResponse.TriggerSound(sound, pos, unk, volume) =>
|
||||
sendResponse(TriggerSoundMessage(sound, pos, unk, volume))
|
||||
|
||||
case LocalResponse.UpdateForceDomeStatus(buildingGuid, activated) if activated =>
|
||||
case LocalResponse.UpdateForceDomeStatus(buildingGuid, true) =>
|
||||
sendResponse(GenericObjectActionMessage(buildingGuid, 11))
|
||||
|
||||
case LocalResponse.UpdateForceDomeStatus(buildingGuid, _) =>
|
||||
case LocalResponse.UpdateForceDomeStatus(buildingGuid, false) =>
|
||||
sendResponse(GenericObjectActionMessage(buildingGuid, 12))
|
||||
|
||||
case LocalResponse.RechargeVehicleWeapon(vehicleGuid, weaponGuid) if resolvedPlayerGuid == guid =>
|
||||
continent.GUID(vehicleGuid).collect { case vehicle: MountableWeapons =>
|
||||
vehicle.PassengerInSeat(player).collect { seat_num =>
|
||||
vehicle.WeaponControlledFromSeat(seat_num).collect { case weapon: Tool if weapon.GUID == weaponGuid =>
|
||||
sendResponse(InventoryStateMessage(weapon.AmmoSlot.Box.GUID, weapon.GUID, weapon.Magazine))
|
||||
}
|
||||
continent.GUID(vehicleGuid)
|
||||
.collect { case vehicle: MountableWeapons => (vehicle, vehicle.PassengerInSeat(player)) }
|
||||
.collect { case (vehicle, Some(seat_num)) => vehicle.WeaponControlledFromSeat(seat_num) }
|
||||
.collect { case weapon: Tool if weapon.GUID == weaponGuid =>
|
||||
sendResponse(InventoryStateMessage(weapon.AmmoSlot.Box.GUID, weapon.GUID, weapon.Magazine))
|
||||
}
|
||||
}
|
||||
|
||||
case _ => ()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,54 +46,118 @@ class SessionMountHandlers(
|
|||
MountingAction(tplayer, obj, seatNumber)
|
||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
||||
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _) =>
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||
if obj.Definition == GlobalDefinitions.ant =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.info(s"${player.Name} mounts the ${obj.Definition.Name} in ${
|
||||
obj.SeatPermissionGroup(seatNumber) match {
|
||||
case Some(AccessPermissionGroup.Driver) => "the driver seat"
|
||||
case Some(seatType) => s"a $seatType seat (#$seatNumber)"
|
||||
case None => "a seat"
|
||||
}
|
||||
}")
|
||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||
val obj_guid: PlanetSideGUID = obj.GUID
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||
if (obj.Definition == GlobalDefinitions.ant) {
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=45, obj.NtuCapacitorScaled))
|
||||
}
|
||||
if (obj.Definition.MaxCapacitor > 0) {
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=113, obj.Capacitor))
|
||||
}
|
||||
if (seatNumber == 0) {
|
||||
if (obj.Definition == GlobalDefinitions.quadstealth) {
|
||||
//wraith cloak state matches the cloak state of the driver
|
||||
//phantasm doesn't uncloak if the driver is uncloaked and no other vehicle cloaks
|
||||
obj.Cloaked = tplayer.Cloaked
|
||||
}
|
||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||
} else if (obj.WeaponControlledFromSeat(seatNumber).isEmpty) {
|
||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
||||
}
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=45, obj.NtuCapacitorScaled))
|
||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||
if obj.Definition == GlobalDefinitions.quadstealth =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||
val obj_guid: PlanetSideGUID = obj.GUID
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||
//exclusive to the wraith, cloak state matches the cloak state of the driver
|
||||
//phantasm doesn't uncloak if the driver is uncloaked and no other vehicle cloaks
|
||||
obj.Cloaked = tplayer.Cloaked
|
||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||
sessionData.accessContainer(obj)
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||
if seatNumber == 0 && obj.Definition.MaxCapacitor > 0 =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||
val obj_guid: PlanetSideGUID = obj.GUID
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=113, obj.Capacitor))
|
||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||
sessionData.accessContainer(obj)
|
||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _) =>
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||
if seatNumber == 0 =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
if (!obj.isUpgrading) {
|
||||
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
||||
if (obj.Definition == GlobalDefinitions.vanu_sentry_turret) {
|
||||
obj.Zone.LocalEvents ! LocalServiceMessage(obj.Zone.id, LocalAction.SetEmpire(obj.GUID, player.Faction))
|
||||
log.info(s"${player.Name} mounts the driver seat of the ${obj.Definition.Name}")
|
||||
val obj_guid: PlanetSideGUID = obj.GUID
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
|
||||
sessionData.accessContainer(obj)
|
||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _)
|
||||
if obj.Definition.MaxCapacitor > 0 =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.info(s"${player.Name} mounts ${
|
||||
obj.SeatPermissionGroup(seatNumber) match {
|
||||
case Some(seatType) => s"a $seatType seat (#$seatNumber)"
|
||||
case None => "a seat"
|
||||
}
|
||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
} else {
|
||||
log.warn(
|
||||
s"MountVehicleMsg: ${tplayer.Name} wants to mount turret ${obj.GUID.guid}, but needs to wait until it finishes updating"
|
||||
)
|
||||
}
|
||||
} of the ${obj.Definition.Name}")
|
||||
val obj_guid: PlanetSideGUID = obj.GUID
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=113, obj.Capacitor))
|
||||
sessionData.accessContainer(obj)
|
||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: Vehicle, seatNumber, _) =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.info(s"${player.Name} mounts the ${
|
||||
obj.SeatPermissionGroup(seatNumber) match {
|
||||
case Some(seatType) => s"a $seatType seat (#$seatNumber)"
|
||||
case None => "a seat"
|
||||
}
|
||||
} of the ${obj.Definition.Name}")
|
||||
val obj_guid: PlanetSideGUID = obj.GUID
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=0, obj.Health))
|
||||
sendResponse(PlanetsideAttributeMessage(obj_guid, obj.Definition.shieldUiAttribute, obj.Shields))
|
||||
sessionData.accessContainer(obj)
|
||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
||||
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
||||
if obj.Definition == GlobalDefinitions.vanu_sentry_turret =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
||||
obj.Zone.LocalEvents ! LocalServiceMessage(obj.Zone.id, LocalAction.SetEmpire(obj.GUID, player.Faction))
|
||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
|
||||
if !obj.isUpgrading =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.info(s"${player.Name} mounts the ${obj.Definition.Name}")
|
||||
sendResponse(PlanetsideAttributeMessage(obj.GUID, attribute_type=0, obj.Health))
|
||||
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
|
||||
MountingAction(tplayer, obj, seatNumber)
|
||||
|
||||
case Mountable.CanMount(obj: FacilityTurret, _, _) =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
log.warn(
|
||||
s"MountVehicleMsg: ${tplayer.Name} wants to mount turret ${obj.GUID.guid}, but needs to wait until it finishes updating"
|
||||
)
|
||||
|
||||
case Mountable.CanMount(obj: PlanetSideGameObject with WeaponTurret, seatNumber, _) =>
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_mount")
|
||||
|
|
|
|||
|
|
@ -28,19 +28,19 @@ class SessionTerminalHandlers(
|
|||
/* packets */
|
||||
|
||||
def handleItemTransaction(pkt: ItemTransactionMessage): Unit = {
|
||||
val ItemTransactionMessage(terminalGuid, _, _, _, _, _) = pkt
|
||||
val ItemTransactionMessage(terminalGuid, transactionType, _, itemName, _, _) = pkt
|
||||
continent.GUID(terminalGuid) match {
|
||||
case Some(term: Terminal) =>
|
||||
if (lastTerminalOrderFulfillment) {
|
||||
log.trace(s"ItemTransactionMessage: ${player.Name} is submitting an order")
|
||||
lastTerminalOrderFulfillment = false
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||
term.Actor ! Terminal.Request(player, pkt)
|
||||
}
|
||||
case Some(obj: PlanetSideGameObject) =>
|
||||
log.error(s"ItemTransaction: $obj is not a terminal, ${player.Name}")
|
||||
case Some(term: Terminal) if lastTerminalOrderFulfillment =>
|
||||
log.info(s"${player.Name} is submitting an order - $transactionType of $itemName")
|
||||
lastTerminalOrderFulfillment = false
|
||||
sessionData.zoning.CancelZoningProcessWithDescriptiveReason("cancel_use")
|
||||
term.Actor ! Terminal.Request(player, pkt)
|
||||
case Some(_: Terminal) =>
|
||||
log.warn(s"Please Wait until your previous order has been fulfilled, ${player.Name}")
|
||||
case Some(obj) =>
|
||||
log.error(s"ItemTransaction: ${obj.Definition.Name} is not a terminal, ${player.Name}")
|
||||
case _ =>
|
||||
log.error(s"ItemTransaction: $terminalGuid does not exist, ${player.Name}")
|
||||
log.error(s"ItemTransaction: entity with guid=${terminalGuid.guid} does not exist, ${player.Name}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -50,9 +50,9 @@ class SessionTerminalHandlers(
|
|||
case Some(obj: Terminal with ProximityUnit) =>
|
||||
HandleProximityTerminalUse(obj)
|
||||
case Some(obj) =>
|
||||
log.warn(s"ProximityTerminalUse: $obj does not have proximity effects for ${player.Name}")
|
||||
log.warn(s"ProximityTerminalUse: ${obj.Definition.Name} guid=${objectGuid.guid} is not ready to implement proximity effects")
|
||||
case None =>
|
||||
log.error(s"ProximityTerminalUse: ${player.Name} can not find an object with guid $objectGuid")
|
||||
log.error(s"ProximityTerminalUse: ${player.Name} can not find an object with guid ${objectGuid.guid}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +66,8 @@ class SessionTerminalHandlers(
|
|||
*/
|
||||
def handle(tplayer: Player, msg: ItemTransactionMessage, order: Terminal.Exchange): Unit = {
|
||||
order match {
|
||||
case Terminal.BuyEquipment(item) if tplayer.avatar.purchaseCooldown(item.Definition).nonEmpty =>
|
||||
case Terminal.BuyEquipment(item)
|
||||
if tplayer.avatar.purchaseCooldown(item.Definition).nonEmpty =>
|
||||
lastTerminalOrderFulfillment = true
|
||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, success = false))
|
||||
|
||||
|
|
@ -100,19 +101,16 @@ class SessionTerminalHandlers(
|
|||
avatarActor ! AvatarActor.SellImplant(msg.terminal_guid, implant)
|
||||
lastTerminalOrderFulfillment = true
|
||||
|
||||
case Terminal.BuyVehicle(vehicle, _, _) if tplayer.avatar.purchaseCooldown(vehicle.Definition).nonEmpty =>
|
||||
case Terminal.BuyVehicle(vehicle, _, _)
|
||||
if tplayer.avatar.purchaseCooldown(vehicle.Definition).nonEmpty =>
|
||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, success = false))
|
||||
lastTerminalOrderFulfillment = true
|
||||
|
||||
case Terminal.BuyVehicle(vehicle, weapons, trunk) =>
|
||||
continent.map.terminalToSpawnPad
|
||||
.find { case (termid, _) => termid == msg.terminal_guid.guid }
|
||||
.map {
|
||||
case (a: Int, b: Int) => (continent.GUID(a), continent.GUID(b))
|
||||
case _ => (None, None)
|
||||
}
|
||||
.get match {
|
||||
case (Some(term: Terminal), Some(pad: VehicleSpawnPad)) =>
|
||||
.map { case (a: Int, b: Int) => (continent.GUID(a), continent.GUID(b)) }
|
||||
.collect { case (Some(term: Terminal), Some(pad: VehicleSpawnPad)) =>
|
||||
avatarActor ! AvatarActor.UpdatePurchaseTime(vehicle.Definition)
|
||||
vehicle.Faction = tplayer.Faction
|
||||
vehicle.Position = pad.Position
|
||||
|
|
@ -143,27 +141,30 @@ class SessionTerminalHandlers(
|
|||
if (GlobalDefinitions.isBattleFrameVehicle(vehicle.Definition)) {
|
||||
sendResponse(UnuseItemMessage(player.GUID, msg.terminal_guid))
|
||||
}
|
||||
case _ =>
|
||||
log.error(
|
||||
s"${tplayer.Name} wanted to spawn a vehicle, but there was no spawn pad associated with terminal ${msg.terminal_guid} to accept it"
|
||||
)
|
||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, success = false))
|
||||
}.orElse {
|
||||
log.error(
|
||||
s"${tplayer.Name} wanted to spawn a vehicle, but there was no spawn pad associated with terminal ${msg.terminal_guid} to accept it"
|
||||
)
|
||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, TransactionType.Buy, success = false))
|
||||
None
|
||||
}
|
||||
|
||||
case Terminal.NoDeal() =>
|
||||
val order: String = if (msg == null) {
|
||||
"missing order"
|
||||
} else {
|
||||
s"${msg.transaction_type} order"
|
||||
}
|
||||
log.warn(s"NoDeal: ${tplayer.Name} made a request but the terminal rejected the $order")
|
||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, msg.transaction_type, success = false))
|
||||
case Terminal.NoDeal() if msg != null =>
|
||||
val transaction = msg.transaction_type
|
||||
log.warn(s"NoDeal: ${tplayer.Name} made a request but the terminal rejected the ${transaction.toString} order")
|
||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, transaction, success = false))
|
||||
lastTerminalOrderFulfillment = true
|
||||
|
||||
case _ =>
|
||||
val transaction = msg.transaction_type
|
||||
log.warn(s"n/a: ${tplayer.Name} made a $transaction request but terminal#${msg.terminal_guid.guid} is missing or wrong")
|
||||
sendResponse(ItemTransactionResultMessage(msg.terminal_guid, transaction, success = false))
|
||||
val terminal = msg.terminal_guid.guid
|
||||
continent.GUID(terminal) match {
|
||||
case Some(term: Terminal) =>
|
||||
log.warn(s"NoDeal?: ${tplayer.Name} made a request but the ${term.Definition.Name}#$terminal rejected the missing order")
|
||||
case Some(_) =>
|
||||
log.warn(s"NoDeal?: ${tplayer.Name} made a request to a non-terminal entity#$terminal")
|
||||
case None =>
|
||||
log.warn(s"NoDeal?: ${tplayer.Name} made a request to a missing entity#$terminal")
|
||||
}
|
||||
lastTerminalOrderFulfillment = true
|
||||
}
|
||||
}
|
||||
|
|
@ -239,7 +240,6 @@ class SessionTerminalHandlers(
|
|||
*/
|
||||
def StartUsingProximityUnit(terminal: Terminal with ProximityUnit, target: PlanetSideGameObject): Unit = {
|
||||
val term_guid = terminal.GUID
|
||||
//log.trace(s"StartUsingProximityUnit: ${player.Name} wants to use ${terminal.Definition.Name}@${term_guid.guid} on $target")
|
||||
if (player.isAlive) {
|
||||
target match {
|
||||
case _: Player =>
|
||||
|
|
@ -267,7 +267,7 @@ class SessionTerminalHandlers(
|
|||
*/
|
||||
def StopUsingProximityUnit(terminal: Terminal with ProximityUnit): Unit = {
|
||||
FindProximityUnitTargetsInScope(terminal).foreach { target =>
|
||||
LocalStopUsingProximityUnit(terminal, target)
|
||||
LocalStopUsingProximityUnit(terminal)
|
||||
terminal.Actor ! CommonMessages.Unuse(player, Some(target))
|
||||
}
|
||||
}
|
||||
|
|
@ -280,7 +280,7 @@ class SessionTerminalHandlers(
|
|||
* Other sorts of proximity-based units are put on a timer.
|
||||
* @param terminal the proximity-based unit
|
||||
*/
|
||||
def LocalStopUsingProximityUnit(terminal: Terminal with ProximityUnit, target: PlanetSideGameObject): Unit = {
|
||||
def LocalStopUsingProximityUnit(terminal: Terminal with ProximityUnit): Unit = {
|
||||
ForgetAllProximityTerminals(terminal.GUID)
|
||||
}
|
||||
|
||||
|
|
@ -291,12 +291,23 @@ class SessionTerminalHandlers(
|
|||
* @see `postStop`
|
||||
*/
|
||||
def CancelAllProximityUnits(): Unit = {
|
||||
continent.GUID(usingMedicalTerminal).collect {
|
||||
usingMedicalTerminal.foreach { CancelAllProximityUnits }
|
||||
}
|
||||
|
||||
/**
|
||||
* Cease all current interactions with proximity-based units.
|
||||
* Pair with `PlayerActionsToCancel`, except when logging out (stopping).
|
||||
* This operations may invoke callback messages.
|
||||
* @param guid globally unique identifier for a proximity terminal
|
||||
* @see `postStop`
|
||||
*/
|
||||
def CancelAllProximityUnits(guid: PlanetSideGUID): Unit = {
|
||||
continent.GUID(guid).collect {
|
||||
case terminal: Terminal with ProximityUnit =>
|
||||
FindProximityUnitTargetsInScope(terminal).foreach(target =>
|
||||
terminal.Actor ! CommonMessages.Unuse(player, Some(target))
|
||||
)
|
||||
ForgetAllProximityTerminals(usingMedicalTerminal.get)
|
||||
ForgetAllProximityTerminals(guid)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -163,10 +163,8 @@ class SessionVehicleHandlers(
|
|||
avatarActor ! AvatarActor.SetVehicle(Some(vehicleGuid))
|
||||
sendResponse(PlanetsideAttributeMessage(resolvedPlayerGuid, attribute_type=21, vehicleGuid))
|
||||
|
||||
case VehicleResponse.PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) =>
|
||||
if (isNotSameTarget) {
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
|
||||
}
|
||||
case VehicleResponse.PlanetsideAttribute(vehicleGuid, attributeType, attributeValue) if isNotSameTarget =>
|
||||
sendResponse(PlanetsideAttributeMessage(vehicleGuid, attributeType, attributeValue))
|
||||
|
||||
case VehicleResponse.ResetSpawnPad(padGuid) =>
|
||||
sendResponse(GenericObjectActionMessage(padGuid, code=23))
|
||||
|
|
@ -201,7 +199,7 @@ class SessionVehicleHandlers(
|
|||
|
||||
case VehicleResponse.KickCargo(vehicle, speed, delay)
|
||||
if player.VehicleSeated.nonEmpty && sessionData.zoning.spawn.deadState == DeadState.Alive && speed > 0 =>
|
||||
val strafe = if (Vehicles.CargoOrientation(vehicle) == 1) { 2 } else { 1 }
|
||||
val strafe = 1 + Vehicles.CargoOrientation(vehicle)
|
||||
val reverseSpeed = if (strafe > 1) { 0 } else { speed }
|
||||
//strafe or reverse, not both
|
||||
sessionData.vehicles.serverVehicleControlVelocity = Some(reverseSpeed)
|
||||
|
|
@ -236,19 +234,29 @@ class SessionVehicleHandlers(
|
|||
unk8=None
|
||||
))
|
||||
|
||||
case VehicleResponse.StartPlayerSeatedInVehicle(vehicle, _)
|
||||
if player.VisibleSlots.contains(player.DrawnSlot) =>
|
||||
val vehicle_guid = vehicle.GUID
|
||||
sessionData.playerActionsToCancel()
|
||||
sessionData.vehicles.serverVehicleControlVelocity = Some(0)
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
player.DrawnSlot = Player.HandsDownSlot
|
||||
sendResponse(ObjectHeldMessage(player.GUID, Player.HandsDownSlot, unk1=true))
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.SendResponse(player.GUID, ObjectHeldMessage(player.GUID, player.LastDrawnSlot, unk1=false))
|
||||
)
|
||||
sendResponse(PlanetsideAttributeMessage(vehicle_guid, attribute_type=22, attribute_value=1L)) //mount points off
|
||||
sendResponse(PlanetsideAttributeMessage(player.GUID, attribute_type=21, vehicle_guid)) //ownership
|
||||
vehicle.MountPoints.find { case (_, mp) => mp.seatIndex == 0 }.collect {
|
||||
case (mountPoint, _) => vehicle.Actor ! Mountable.TryMount(player, mountPoint)
|
||||
}
|
||||
|
||||
case VehicleResponse.StartPlayerSeatedInVehicle(vehicle, _) =>
|
||||
val vehicle_guid = vehicle.GUID
|
||||
sessionData.playerActionsToCancel()
|
||||
sessionData.vehicles.serverVehicleControlVelocity = Some(0)
|
||||
sessionData.terminals.CancelAllProximityUnits()
|
||||
if (player.VisibleSlots.contains(player.DrawnSlot)) {
|
||||
player.DrawnSlot = Player.HandsDownSlot
|
||||
sendResponse(ObjectHeldMessage(player.GUID, Player.HandsDownSlot, unk1=true))
|
||||
continent.AvatarEvents ! AvatarServiceMessage(
|
||||
continent.id,
|
||||
AvatarAction.SendResponse(player.GUID, ObjectHeldMessage(player.GUID, player.LastDrawnSlot, unk1=false))
|
||||
)
|
||||
}
|
||||
sendResponse(PlanetsideAttributeMessage(vehicle_guid, attribute_type=22, attribute_value=1L)) //mount points off
|
||||
sendResponse(PlanetsideAttributeMessage(player.GUID, attribute_type=21, vehicle_guid)) //ownership
|
||||
vehicle.MountPoints.find { case (_, mp) => mp.seatIndex == 0 }.collect {
|
||||
|
|
|
|||
|
|
@ -1446,14 +1446,11 @@ class ZoningOperations(
|
|||
Deployables.Disown(continent, avatar, context.self)
|
||||
spawn.drawDeloyableIcon = spawn.RedrawDeployableIcons //important for when SetCurrentAvatar initializes the UI next zone
|
||||
sessionData.squad.squadSetup = sessionData.squad.ZoneChangeSquadSetup
|
||||
val lastSeen = sessionData.avatarResponse.lastSeenStreamMessage
|
||||
lastSeen.indices.foreach { index =>
|
||||
lastSeen(index) = 0
|
||||
}
|
||||
sessionData.avatarResponse.lastSeenStreamMessage = SessionAvatarHandlers.blankUpstreamMessages(65535)
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to tranfer to the player's faction-specific sanctuary continent.
|
||||
* Attempt to transfer to the player's faction-specific sanctuary continent.
|
||||
* If the server thinks the player is already on his sanctuary continent, and dead,
|
||||
* it will disconnect the player under the assumption that an error has occurred.
|
||||
* Eventually, this functionality should support better error-handling before it jumps to the conclusion:
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ class LocalService(zone: Zone) extends Actor {
|
|||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.SendPlanetsideAttributeMessage(target_guid, attribute_number, attribute_value)
|
||||
LocalResponse.PlanetsideAttribute(target_guid, attribute_number, attribute_value)
|
||||
)
|
||||
)
|
||||
case LocalAction.SendGenericObjectActionMessage(player_guid, target_guid, action_number) =>
|
||||
|
|
@ -153,7 +153,7 @@ class LocalService(zone: Zone) extends Actor {
|
|||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.SendGenericObjectActionMessage(target_guid, action_number)
|
||||
LocalResponse.GenericObjectAction(target_guid, action_number)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ class LocalService(zone: Zone) extends Actor {
|
|||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.SendChatMsg(msg)
|
||||
LocalResponse.ChatMessage(msg)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
@ -171,7 +171,7 @@ class LocalService(zone: Zone) extends Actor {
|
|||
LocalServiceResponse(
|
||||
s"/$forChannel/Local",
|
||||
player_guid,
|
||||
LocalResponse.SendGenericActionMessage(action_number)
|
||||
LocalResponse.GenericActionMessage(action_number)
|
||||
)
|
||||
)
|
||||
case LocalAction.RouterTelepadMessage(msg) =>
|
||||
|
|
|
|||
|
|
@ -38,12 +38,12 @@ object LocalResponse {
|
|||
final case class HackObject(target_guid: PlanetSideGUID, unk1: Long, unk2: Long) extends Response
|
||||
|
||||
final case class SendPacket(packet: PlanetSideGamePacket) extends Response
|
||||
final case class SendPlanetsideAttributeMessage(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long)
|
||||
final case class PlanetsideAttribute(target_guid: PlanetSideGUID, attribute_number: PlanetsideAttributeEnum, attribute_value: Long)
|
||||
extends Response
|
||||
final case class SendGenericObjectActionMessage(target_guid: PlanetSideGUID, action_number: GenericObjectActionEnum)
|
||||
final case class GenericObjectAction(target_guid: PlanetSideGUID, action_number: GenericObjectActionEnum)
|
||||
extends Response
|
||||
final case class SendChatMsg(msg: ChatMsg) extends Response
|
||||
final case class SendGenericActionMessage(action_num: GenericAction) extends Response
|
||||
final case class ChatMessage(msg: ChatMsg) extends Response
|
||||
final case class GenericActionMessage(action_num: GenericAction) extends Response
|
||||
|
||||
final case class LluSpawned(llu: CaptureFlag) extends Response
|
||||
final case class LluDespawned(guid: PlanetSideGUID, position: Vector3) extends Response
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue