Skip to content

Commit

Permalink
reusing the existing sector data; better resets, negating an issue du…
Browse files Browse the repository at this point in the history
…ring mounting where the player does not switch back to recovery; disabling was bugged due to missed timer upgrade
  • Loading branch information
Fate-JH committed Feb 19, 2024
1 parent 99aafbe commit 6790ced
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package net.psforever.actors.session.support

import akka.actor.{ActorContext, typed}
import net.psforever.objects.serverobject.affinity.FactionAffinity
import net.psforever.objects.serverobject.environment.interaction.ResetAllEnvironmentInteractions
import net.psforever.objects.vital.InGameHistory

import scala.concurrent.duration._
Expand Down Expand Up @@ -61,6 +62,7 @@ class SessionMountHandlers(
sendResponse(PlanetsideAttributeMessage(obj_guid, attribute_type=45, obj.NtuCapacitorScaled))
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
sessionData.accessContainer(obj)
tplayer.Actor ! ResetAllEnvironmentInteractions
MountingAction(tplayer, obj, seatNumber)

case Mountable.CanMount(obj: Vehicle, seatNumber, _)
Expand All @@ -76,6 +78,7 @@ class SessionMountHandlers(
obj.Cloaked = tplayer.Cloaked
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
sessionData.accessContainer(obj)
tplayer.Actor ! ResetAllEnvironmentInteractions
MountingAction(tplayer, obj, seatNumber)

case Mountable.CanMount(obj: Vehicle, seatNumber, _)
Expand All @@ -90,6 +93,7 @@ class SessionMountHandlers(
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
sessionData.accessContainer(obj)
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
tplayer.Actor ! ResetAllEnvironmentInteractions
MountingAction(tplayer, obj, seatNumber)

case Mountable.CanMount(obj: Vehicle, seatNumber, _)
Expand All @@ -103,6 +107,7 @@ class SessionMountHandlers(
sendResponse(GenericObjectActionMessage(obj_guid, code=11))
sessionData.accessContainer(obj)
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
tplayer.Actor ! ResetAllEnvironmentInteractions
MountingAction(tplayer, obj, seatNumber)

case Mountable.CanMount(obj: Vehicle, seatNumber, _)
Expand All @@ -122,6 +127,7 @@ class SessionMountHandlers(
sessionData.accessContainer(obj)
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
tplayer.Actor ! ResetAllEnvironmentInteractions
MountingAction(tplayer, obj, seatNumber)

case Mountable.CanMount(obj: Vehicle, seatNumber, _) =>
Expand All @@ -139,6 +145,7 @@ class SessionMountHandlers(
sessionData.accessContainer(obj)
sessionData.updateWeaponAtSeatPosition(obj, seatNumber)
sessionData.keepAliveFunc = sessionData.keepAlivePersistence
tplayer.Actor ! ResetAllEnvironmentInteractions
MountingAction(tplayer, obj, seatNumber)

case Mountable.CanMount(obj: FacilityTurret, seatNumber, _)
Expand Down Expand Up @@ -173,7 +180,7 @@ class SessionMountHandlers(
MountingAction(tplayer, obj, seatNumber)

case Mountable.CanMount(obj: Mountable, _, _) =>
log.warn(s"MountVehicleMsg: $obj is some mountable object and nothing will happen for ${player.Name}")
log.warn(s"MountVehicleMsg: $obj is some kind of mountable object but nothing will happen for ${player.Name}")

case Mountable.CanDismount(obj: ImplantTerminalMech, seatNum, _) =>
log.info(s"${tplayer.Name} dismounts the implant terminal")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,23 @@ class WithWater(val channel: String)
body: PieceOfEnvironment,
data: Option[Any]
): Unit = {
val (effect, time, percentage) = Watery.drowningInWateryConditions(obj, condition.map(_.state), waterInteractionTime)
val cond = OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage)
val extra = data.collect {
case t: OxygenStateTarget => Some(t)
case w: Watery => w.Condition
}.flatten
if (effect) {
waterInteractionTime = System.currentTimeMillis() + time
condition = Some(cond)
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = time milliseconds, obj.Actor, Player.Die())
//inform the player that they are in trouble
obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, extra))
} else if (extra.isDefined) {
//inform the player that their mounted vehicle is in trouble (that they are in trouble)
obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, None))
if (extra.isDefined) {
//inform the player that their mounted vehicle is in trouble (that they are in trouble (but not from drowning (yet)))
stopInteractingWith(obj, body, data)
} else {
val (effect, time, percentage) = Watery.drowningInWateryConditions(obj, condition.map(_.state), waterInteractionTime)
if (effect) {
val cond = OxygenStateTarget(obj.GUID, body, OxygenState.Suffocation, percentage)
waterInteractionTime = System.currentTimeMillis() + time
condition = Some(cond)
obj.Actor ! RespondsToZoneEnvironment.Timer(attribute, delay = time milliseconds, obj.Actor, Player.Die())
//inform the player that they are in trouble
obj.Zone.AvatarEvents ! AvatarServiceMessage(channel, AvatarAction.OxygenState(cond, extra))
}
}
}

Expand Down Expand Up @@ -78,6 +80,9 @@ class WithWater(val channel: String)

override def recoverFromInteracting(obj: InteractsWithZone): Unit = {
super.recoverFromInteracting(obj)
if (condition.exists(_.state == OxygenState.Suffocation)) {
stopInteractingWith(obj, condition.map(_.body).get, None)
}
waterInteractionTime = 0L
condition = None
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,11 @@ object EnvironmentAttribute extends Enum[EnvironmentTrait] {
/** water can only interact with objects that are negatively affected by being exposed to water;
* it's better this way */
def canInteractWith(obj: PlanetSideGameObject): Boolean = {
obj.Definition.DrownAtMaxDepth || obj.Definition.DisableAtMaxDepth
obj.Definition.DrownAtMaxDepth || obj.Definition.DisableAtMaxDepth || (obj match {
case p: Player => p.VehicleSeated.isEmpty
case v: Vehicle => v.MountedIn.isEmpty
case _ => true
})
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment}
import net.psforever.objects.zones._
import net.psforever.objects.zones.blockmap.{BlockMapEntity, SectorPopulation}
import net.psforever.objects.zones.blockmap.{BlockMapEntity, SectorGroup, SectorPopulation}

import scala.collection.mutable

Expand Down Expand Up @@ -41,7 +41,7 @@ class InteractWithEnvironment()
def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = {
target match {
case t: InteractsWithZone =>
interactWith = interactionBehavior.perform(t, interactWith, allow=true)
interactWith = interactionBehavior.perform(t, sector, interactWith, allow=true)
interactionBehavior = interactionBehavior.next
case _ => ()
}
Expand All @@ -60,8 +60,8 @@ class InteractWithEnvironment()
*/
def resetInteraction(target: InteractsWithZone) : Unit = {
target match {
case t: InteractsWithZone =>
AwaitOngoingInteraction(target.Zone).perform(t, interactWith, allow=false)
case t: InteractsWithZone with BlockMapEntity =>
AwaitOngoingInteraction(target.Zone).perform(t, SectorGroup.emptySector, interactWith, allow=false)
case _ => ()
}
interactWith = Set()
Expand Down Expand Up @@ -110,19 +110,17 @@ object InteractWithEnvironment {
/**
* Test whether any special terrain component has an affect upon the target entity.
* @param obj the target entity
* @param sector the portion of the block map being tested
* @return any unstable, interactive, or special terrain that is being interacted
*/
def checkAllEnvironmentInteractions(obj: PlanetSideServerObject): Set[PieceOfEnvironment] = {
def checkAllEnvironmentInteractions(
obj: PlanetSideServerObject,
sector: SectorPopulation
): Set[PieceOfEnvironment] = {
val position = obj.Position
val depth = GlobalDefinitions.MaxDepth(obj)
(obj match {
case bme: BlockMapEntity =>
obj.Zone.blockMap.sector(bme).environmentList
case _ =>
obj.Zone.map.environment
}).filter { body =>
body.attribute.canInteractWith(obj) && body.testInteraction(position, depth)
}
sector.environmentList
.filter(body => body.attribute.canInteractWith(obj) && body.testInteraction(position, depth))
.distinctBy(_.attribute)
.toSet
}
Expand All @@ -134,7 +132,11 @@ object InteractWithEnvironment {
* @param obj the target entity
* @return any unstable, interactive, or special terrain that is being interacted
*/
def checkSpecificEnvironmentInteraction(zone: Zone, body: PieceOfEnvironment, obj: PlanetSideServerObject): Option[PieceOfEnvironment] = {
def checkSpecificEnvironmentInteraction(
zone: Zone,
body: PieceOfEnvironment,
obj: PlanetSideServerObject
): Option[PieceOfEnvironment] = {
if ((obj.Zone eq zone) && body.testInteraction(obj.Position, GlobalDefinitions.MaxDepth(obj))) {
Some(body)
} else {
Expand All @@ -146,7 +148,12 @@ object InteractWithEnvironment {
trait InteractionBehavior {
protected var nextstep: InteractionBehavior = this

def perform(obj: InteractsWithZone, existing: Set[PieceOfEnvironment], allow: Boolean): Set[PieceOfEnvironment]
def perform(
obj: InteractsWithZone,
sector: SectorPopulation,
existing: Set[PieceOfEnvironment],
allow: Boolean
): Set[PieceOfEnvironment]

def next: InteractionBehavior = {
val out = nextstep
Expand All @@ -166,15 +173,20 @@ case class OnStableEnvironment() extends InteractionBehavior {
* @see `AwaitOngoingInteraction`
* @see `OnStableEnvironment`
* @param obj target entity
* @param sector the portion of the block map being tested
* @param existing not applicable
* @param allow is this permitted, or will it be blocked?
* @return the function literal that represents the next iterative call of ongoing interaction testing;
* may return itself
* @return applicable interactive environmental fields
*/
def perform(obj: InteractsWithZone, existing: Set[PieceOfEnvironment], allow: Boolean): Set[PieceOfEnvironment] = {
def perform(
obj: InteractsWithZone,
sector: SectorPopulation,
existing: Set[PieceOfEnvironment],
allow: Boolean
): Set[PieceOfEnvironment] = {
if (allow) {
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj)
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
env.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
if (env.nonEmpty) {
nextstep = AwaitOngoingInteraction(obj.Zone)
Expand All @@ -201,21 +213,26 @@ final case class AwaitOngoingInteraction(zone: Zone) extends InteractionBehavior
* @see `InteractWithEnvironment.checkSpecificEnvironmentInteraction`
* @see `OnStableEnvironment`
* @param obj target entity
* @param sector the portion of the block map being tested
* @param existing environment fields from the previous step
* @param allow is this permitted, or will it be blocked?
* @return the function literal that represents the next iterative call of ongoing interaction testing;
* may return itself
* @return applicable interactive environmental fields
*/
def perform(obj: InteractsWithZone, existing: Set[PieceOfEnvironment], allow: Boolean): Set[PieceOfEnvironment] = {
def perform(
obj: InteractsWithZone,
sector: SectorPopulation,
existing: Set[PieceOfEnvironment],
allow: Boolean
): Set[PieceOfEnvironment] = {
val interactions = obj.interaction().collectFirst { case inter: InteractWithEnvironment => inter.Interactions }
if (allow) {
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj)
val env = InteractWithEnvironment.checkAllEnvironmentInteractions(obj, sector)
val (in, out) = existing.partition(body => InteractWithEnvironment.checkSpecificEnvironmentInteraction(zone, body, obj).nonEmpty)
env.diff(in).foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.doInteractingWith(obj, body, None)))
out.foreach(body => interactions.flatMap(_.get(body.attribute)).foreach(_.stopInteractingWith(obj, body, None)))
if (env.isEmpty) {
val n = OnStableEnvironment()
val out = n.perform(obj, Set(), allow)
val out = n.perform(obj, sector, Set(), allow)
nextstep = n.next
out
} else {
Expand All @@ -236,12 +253,17 @@ case class BlockedFromInteracting() extends InteractionBehavior {
* Considered tail recursive, but not treated that way.
* @see `OnStableEnvironment`
* @param obj target entity
* @param sector the portion of the block map being tested
* @param existing not applicable
* @param allow is this permitted, or will it be blocked?
* @return the function literal that represents the next iterative call of ongoing interaction testing;
* may return itself
* @return an empty set
*/
def perform(obj: InteractsWithZone, existing: Set[PieceOfEnvironment], allow: Boolean): Set[PieceOfEnvironment] = {
def perform(
obj: InteractsWithZone,
sector: SectorPopulation,
existing: Set[PieceOfEnvironment],
allow: Boolean
): Set[PieceOfEnvironment] = {
if (allow) {
nextstep = OnStableEnvironment()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ final case class EscapeFromEnvironment(
)

/**
* Completely reset any internal actions or processes related to environment clipping.
* Completely reset internal actions or processes related to environment clipping.
*/
final case class RecoveredFromEnvironmentInteraction(attribute: EnvironmentTrait)

/**
* Completely reset internal actions or processes related to environment clipping.
*/
case object ResetAllEnvironmentInteractions
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ trait RespondsToZoneEnvironment {
applicableInteractions
.get(attribute)
.foreach(_.recoverFromInteracting(InteractiveObject))

case ResetAllEnvironmentInteractions =>
applicableInteractions.values.foreach(_.recoverFromInteracting(InteractiveObject))
interactionTimers.values.foreach(_.cancel())
}

def respondToEnvironmentPostStop(): Unit = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ class VehicleControl(vehicle: Vehicle)
)
}

case VehicleControl.Disable() =>
PrepareForDisabled(kickPassengers = false)
case VehicleControl.Disable(kickPassengers) =>
PrepareForDisabled(kickPassengers)
context.become(Disabled)

case Vehicle.Deconstruct(time) =>
Expand Down Expand Up @@ -384,28 +384,20 @@ class VehicleControl(vehicle: Vehicle)
val zone = vehicle.Zone
val zoneId = zone.id
val events = zone.VehicleEvents
//miscellaneous changes
//recoverFromEnvironmentInteracting()
//escape being someone else's cargo
vehicle.MountedIn match {
case Some(_) =>
startCargoDismounting(bailed = true)
case _ => ;
}
vehicle.MountedIn.foreach(_ => startCargoDismounting(bailed = true))
if (!vehicle.isFlying || kickPassengers) {
//kick all passengers (either not flying, or being explicitly instructed)
vehicle.Seats.values.foreach { seat =>
seat.occupant match {
case Some(player) =>
seat.unmount(player, BailType.Kicked)
player.VehicleSeated = None
if (player.isAlive) {
zone.actor ! ZoneActor.AddToBlockMap(player, vehicle.Position)
}
if (player.HasGUID) {
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = true, guid))
}
case None => ;
seat.occupant.foreach { player =>
seat.unmount(player, BailType.Kicked)
player.VehicleSeated = None
if (player.isAlive) {
zone.actor ! ZoneActor.AddToBlockMap(player, vehicle.Position)
}
if (player.HasGUID) {
events ! VehicleServiceMessage(zoneId, VehicleAction.KickPassenger(player.GUID, 4, unk2 = true, guid))
}
}
}
}
Expand Down Expand Up @@ -722,7 +714,7 @@ object VehicleControl {

private case class PrepareForDeletion()

private[vehicles] case class Disable()
final case class Disable(kickPassengers: Boolean = false)

private case class Deletion()

Expand Down
Loading

0 comments on commit 6790ced

Please sign in to comment.