mirror of
https://github.com/psforever/PSF-LoginServer.git
synced 2026-03-17 11:20:40 +00:00
zone interaction for turret discovery, players only so far; minor field value change for small turret data; automated turret target recognition; grammatical and linter fixes
This commit is contained in:
parent
e9daae5802
commit
9952803883
8 changed files with 274 additions and 26 deletions
|
|
@ -3,7 +3,7 @@ package net.psforever.objects
|
|||
|
||||
import net.psforever.objects.avatar.{Avatar, LoadoutManager, SpecialCarry}
|
||||
import net.psforever.objects.ballistics.InteractWithRadiationClouds
|
||||
import net.psforever.objects.ce.{Deployable, InteractWithMines}
|
||||
import net.psforever.objects.ce.{Deployable, InteractWithMines, InteractWithTurrets}
|
||||
import net.psforever.objects.definition.{AvatarDefinition, ExoSuitDefinition, SpecialExoSuitDefinition}
|
||||
import net.psforever.objects.equipment.{Equipment, EquipmentSize, EquipmentSlot, JammableUnit}
|
||||
import net.psforever.objects.inventory.{Container, GridInventory, InventoryItem}
|
||||
|
|
@ -38,6 +38,7 @@ class Player(var avatar: Avatar)
|
|||
with MountableEntity {
|
||||
interaction(new InteractWithEnvironment())
|
||||
interaction(new InteractWithMinesUnlessSpectating(obj = this, range = 10))
|
||||
interaction(new InteractWithTurrets(range = 25f))
|
||||
interaction(new InteractWithRadiationClouds(range = 10f, Some(this)))
|
||||
|
||||
private var backpack: Boolean = false
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import net.psforever.objects.serverobject.damage.DamageableWeaponTurret
|
|||
import net.psforever.objects.serverobject.hackable.Hackable
|
||||
import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
|
||||
import net.psforever.objects.serverobject.repair.RepairableWeaponTurret
|
||||
import net.psforever.objects.serverobject.turret.{TurretDefinition, WeaponTurret}
|
||||
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior, TurretDefinition, WeaponTurret}
|
||||
import net.psforever.objects.vital.damage.DamageCalculations
|
||||
import net.psforever.objects.vital.interaction.DamageResult
|
||||
import net.psforever.objects.vital.{SimpleResolutions, StandardVehicleResistance}
|
||||
|
|
@ -26,10 +26,11 @@ class TurretDeployable(tdef: TurretDeployableDefinition)
|
|||
extends Deployable(tdef)
|
||||
with WeaponTurret
|
||||
with JammableUnit
|
||||
with Hackable {
|
||||
with Hackable
|
||||
with AutomatedTurret {
|
||||
WeaponTurret.LoadDefinition(this)
|
||||
|
||||
override def Definition = tdef
|
||||
override def Definition: TurretDeployableDefinition = tdef
|
||||
}
|
||||
|
||||
class TurretDeployableDefinition(private val objectId: Int)
|
||||
|
|
@ -46,7 +47,7 @@ class TurretDeployableDefinition(private val objectId: Int)
|
|||
//override to clarify inheritance conflict
|
||||
override def MaxHealth_=(max: Int): Int = super[DeployableDefinition].MaxHealth_=(max)
|
||||
|
||||
override def Initialize(obj: Deployable, context: ActorContext) = {
|
||||
override def Initialize(obj: Deployable, context: ActorContext): Unit = {
|
||||
obj.Actor = context.actorOf(Props(classOf[TurretControl], obj), PlanetSideServerObject.UniqueActorName(obj))
|
||||
}
|
||||
}
|
||||
|
|
@ -66,13 +67,15 @@ class TurretControl(turret: TurretDeployable)
|
|||
with JammableMountedWeapons //note: jammable status is reported as vehicle events, not local events
|
||||
with MountableBehavior
|
||||
with DamageableWeaponTurret
|
||||
with RepairableWeaponTurret {
|
||||
def DeployableObject = turret
|
||||
def MountableObject = turret
|
||||
def JammableObject = turret
|
||||
def FactionObject = turret
|
||||
def DamageableObject = turret
|
||||
def RepairableObject = turret
|
||||
with RepairableWeaponTurret
|
||||
with AutomatedTurretBehavior {
|
||||
def DeployableObject: TurretDeployable = turret
|
||||
def MountableObject: TurretDeployable = turret
|
||||
def JammableObject: TurretDeployable = turret
|
||||
def FactionObject: TurretDeployable = turret
|
||||
def DamageableObject: TurretDeployable = turret
|
||||
def RepairableObject: TurretDeployable = turret
|
||||
def AutomatedTurretObject: TurretDeployable = turret
|
||||
|
||||
override def postStop(): Unit = {
|
||||
super.postStop()
|
||||
|
|
@ -88,8 +91,9 @@ class TurretControl(turret: TurretDeployable)
|
|||
.orElse(dismountBehavior)
|
||||
.orElse(takesDamage)
|
||||
.orElse(canBeRepairedByNanoDispenser)
|
||||
.orElse(automatedTurretBehavior)
|
||||
.orElse {
|
||||
case _ => ;
|
||||
case _ => ()
|
||||
}
|
||||
|
||||
override protected def mountTest(
|
||||
|
|
@ -122,7 +126,7 @@ class TurretControl(turret: TurretDeployable)
|
|||
zone.id,
|
||||
VehicleAction.KickPassenger(tplayer.GUID, 4, wasKickedByDriver, turret.GUID)
|
||||
)
|
||||
case None => ;
|
||||
case None => ()
|
||||
}
|
||||
}
|
||||
Some(time.getOrElse(Deployable.cleanup) + Deployable.cleanup)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2021 PSForever
|
||||
package net.psforever.objects.ce
|
||||
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.serverobject.turret.{AutomatedTurret, AutomatedTurretBehavior}
|
||||
import net.psforever.objects.zones.blockmap.SectorPopulation
|
||||
import net.psforever.objects.zones.{InteractsWithZone, ZoneInteraction, ZoneInteractionType}
|
||||
import net.psforever.objects.sourcing.SourceEntry
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
case object TurretInteraction extends ZoneInteractionType
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
class InteractWithTurrets(val range: Float)
|
||||
extends ZoneInteraction {
|
||||
def Type: TurretInteraction.type = TurretInteraction
|
||||
|
||||
/**
|
||||
* ...
|
||||
*/
|
||||
def interaction(sector: SectorPopulation, target: InteractsWithZone): Unit = {
|
||||
target match {
|
||||
case clarifiedTarget: AutomatedTurret.Target =>
|
||||
val posxy = clarifiedTarget.Position.xy
|
||||
val unique = SourceEntry(clarifiedTarget).unique
|
||||
val targets = getTurretTargets(sector, posxy).filter { turret => turret.Detected(unique).isEmpty }
|
||||
targets.foreach { t => t.Actor ! AutomatedTurretBehavior.Alert(clarifiedTarget) }
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
private def getTurretTargets(
|
||||
sector: SectorPopulation,
|
||||
position: Vector3
|
||||
): List[PlanetSideServerObject with AutomatedTurret] = {
|
||||
(sector
|
||||
.deployableList
|
||||
.collect {
|
||||
case turret: AutomatedTurret => turret
|
||||
} ++ sector
|
||||
.amenityList
|
||||
.collect {
|
||||
case turret: AutomatedTurret => turret
|
||||
})
|
||||
.filter { turret => Vector3.DistanceSquared(turret.Position.xy, position) < 625 }
|
||||
}
|
||||
|
||||
/**
|
||||
* ...
|
||||
* @param target na
|
||||
*/
|
||||
def resetInteraction(target: InteractsWithZone): Unit = {
|
||||
getTurretTargets(
|
||||
target.getInteractionSector(),
|
||||
target.Position.xy
|
||||
).foreach { turret =>
|
||||
turret.Actor ! AutomatedTurretBehavior.ResetAlerts
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@ import scala.util.{Success, Try}
|
|||
|
||||
class AmmoBoxConverter extends ObjectCreateConverter[AmmoBox] {
|
||||
override def ConstructorData(obj: AmmoBox): Try[CommonFieldData] = {
|
||||
Success(CommonFieldData()(false))
|
||||
Success(CommonFieldData()(flag = false))
|
||||
}
|
||||
|
||||
override def DetailedConstructorData(obj: AmmoBox): Try[DetailedAmmoBoxData] = {
|
||||
|
|
@ -19,9 +19,9 @@ class AmmoBoxConverter extends ObjectCreateConverter[AmmoBox] {
|
|||
PlanetSideEmpire.NEUTRAL,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
true,
|
||||
v1 = true,
|
||||
None,
|
||||
false,
|
||||
jammered = false,
|
||||
None,
|
||||
None,
|
||||
PlanetSideGUID(0)
|
||||
|
|
|
|||
|
|
@ -21,9 +21,9 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
|||
obj.Faction,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
false,
|
||||
v1 = true,
|
||||
None,
|
||||
jammered = obj.Jammed,
|
||||
obj.Jammed,
|
||||
Some(true),
|
||||
None,
|
||||
obj.OwnerGuid match {
|
||||
|
|
@ -45,9 +45,9 @@ class SmallTurretConverter extends ObjectCreateConverter[TurretDeployable]() {
|
|||
obj.Faction,
|
||||
bops = false,
|
||||
alternate = true,
|
||||
false,
|
||||
v1 = false,
|
||||
None,
|
||||
false,
|
||||
jammered = false,
|
||||
Some(false),
|
||||
None,
|
||||
PlanetSideGUID(0)
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ class ToolConverter extends ObjectCreateConverter[Tool]() {
|
|||
obj.Faction,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
true,
|
||||
v1 = true,
|
||||
None,
|
||||
obj.Jammed,
|
||||
None,
|
||||
|
|
@ -47,7 +47,7 @@ class ToolConverter extends ObjectCreateConverter[Tool]() {
|
|||
obj.Faction,
|
||||
bops = false,
|
||||
alternate = false,
|
||||
true,
|
||||
v1 = true,
|
||||
None,
|
||||
obj.Jammed,
|
||||
None,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,181 @@
|
|||
// Copyright (c) 2023 PSForever
|
||||
package net.psforever.objects.serverobject.turret
|
||||
|
||||
import akka.actor.{Actor, Cancellable}
|
||||
import net.psforever.objects.definition.ObjectDefinition
|
||||
import net.psforever.objects.{Default, Player}
|
||||
import net.psforever.objects.serverobject.PlanetSideServerObject
|
||||
import net.psforever.objects.sourcing.{SourceEntry, SourceUniqueness}
|
||||
import net.psforever.objects.vital.Vitality
|
||||
import net.psforever.packet.game.{ChangeFireStateMessage_Start, ObjectDetectedMessage}
|
||||
import net.psforever.services.avatar.{AvatarAction, AvatarServiceMessage}
|
||||
import net.psforever.types.{PlanetSideGUID, Vector3}
|
||||
|
||||
import scala.collection.mutable
|
||||
import scala.concurrent.duration._
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
|
||||
trait AutomatedTurret
|
||||
extends PlanetSideServerObject
|
||||
with WeaponTurret {
|
||||
import AutomatedTurret.Target
|
||||
private var targets: List[Target] = List[Target]()
|
||||
|
||||
def Targets: List[Target] = targets
|
||||
|
||||
def Detected(target: Target): Option[Target] = {
|
||||
val unique = SourceEntry(target).unique
|
||||
targets.find(SourceEntry(_).unique == unique)
|
||||
}
|
||||
|
||||
def Detected(target: SourceUniqueness): Option[Target] = {
|
||||
targets.find(SourceEntry(_).unique == target)
|
||||
}
|
||||
|
||||
def AddTarget(target: Target): Unit = {
|
||||
targets = targets :+ target
|
||||
}
|
||||
|
||||
def RemoveTarget(target: Target): Unit = {
|
||||
val unique = SourceEntry(target).unique
|
||||
targets = targets.filterNot(SourceEntry(_).unique == unique)
|
||||
}
|
||||
|
||||
def Clear(): List[Target] = {
|
||||
val oldTargets = targets
|
||||
targets = Nil
|
||||
oldTargets
|
||||
}
|
||||
|
||||
def Definition: ObjectDefinition with TurretDefinition
|
||||
}
|
||||
|
||||
object AutomatedTurret {
|
||||
type Target = PlanetSideServerObject with Vitality
|
||||
}
|
||||
|
||||
trait AutomatedTurretBehavior {
|
||||
_: Actor =>
|
||||
import AutomatedTurret.Target
|
||||
import AutomatedTurretBehavior.TurretTargetEntry
|
||||
|
||||
private val targets: mutable.HashMap[SourceUniqueness, TurretTargetEntry] =
|
||||
mutable.HashMap[SourceUniqueness, TurretTargetEntry]()
|
||||
|
||||
private var targetDistanceCheck: Cancellable = Default.Cancellable
|
||||
|
||||
def AutomatedTurretObject: AutomatedTurret
|
||||
|
||||
val automatedTurretBehavior: Actor.Receive = {
|
||||
case AutomatedTurretBehavior.Alert(target) =>
|
||||
val targets = AutomatedTurretObject.Targets
|
||||
val size = targets.size
|
||||
AutomatedTurretObject.Detected(target)
|
||||
.orElse {
|
||||
AutomatedTurretObject.AddTarget(target)
|
||||
retimeDistanceCheck(size)
|
||||
Some(target)
|
||||
}
|
||||
.foreach { newDetectedTarget }
|
||||
|
||||
case AutomatedTurretBehavior.Unalert(target) =>
|
||||
val targets = AutomatedTurretObject.Targets
|
||||
val size = targets.size
|
||||
AutomatedTurretObject.Detected(target)
|
||||
.collect { out =>
|
||||
AutomatedTurretObject.RemoveTarget(target)
|
||||
testDistanceCheckQualifications(size)
|
||||
out
|
||||
}
|
||||
.foreach { noLongerDetectedTarget }
|
||||
|
||||
case AutomatedTurretBehavior.ResetAlerts =>
|
||||
AutomatedTurretObject.Clear().foreach { noLongerDetectedTarget }
|
||||
testDistanceCheckQualifications(beforeSize = 1)
|
||||
|
||||
case AutomatedTurretBehavior.PeriodicDistanceCheck =>
|
||||
performPeriodicDistanceCheck()
|
||||
}
|
||||
|
||||
private def newDetectedTarget(target: Target): Unit = {
|
||||
target match {
|
||||
case target: Player =>
|
||||
target.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
target.Name,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ObjectDetectedMessage(AutomatedTurretObject.GUID, AutomatedTurretObject.GUID, 0, List(target.GUID)))
|
||||
)
|
||||
target.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
target.Name,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ChangeFireStateMessage_Start(AutomatedTurretObject.Weapons.values.head.Equipment.get.GUID))
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
private def noLongerDetectedTarget(target: Target): Unit = {
|
||||
target match {
|
||||
case target: Player =>
|
||||
target.Zone.AvatarEvents ! AvatarServiceMessage(
|
||||
target.Name,
|
||||
AvatarAction.SendResponse(PlanetSideGUID(0), ObjectDetectedMessage(AutomatedTurretObject.GUID, AutomatedTurretObject.GUID, 0, List(PlanetSideGUID(0))))
|
||||
)
|
||||
case _ => ()
|
||||
}
|
||||
}
|
||||
|
||||
private def testDistanceCheckQualifications(beforeSize: Int): Unit = {
|
||||
if (beforeSize > 0 && AutomatedTurretObject.Targets.isEmpty) {
|
||||
targetDistanceCheck.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
private def retimeDistanceCheck(beforeSize: Int): Unit = {
|
||||
if (beforeSize == 0 && AutomatedTurretObject.Targets.nonEmpty) {
|
||||
targetDistanceCheck = context.system.scheduler.scheduleAtFixedRate(
|
||||
1.second,
|
||||
1.second,
|
||||
self,
|
||||
AutomatedTurretBehavior.PeriodicDistanceCheck
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private def performPeriodicDistanceCheck(): List[Target] = {
|
||||
val pos = AutomatedTurretObject.Position
|
||||
val earlyTargets = AutomatedTurretObject.Targets
|
||||
val earlySize = earlyTargets.size
|
||||
val removedTargets = earlyTargets
|
||||
.collect {
|
||||
case t if Vector3.DistanceSquared(t.Position, pos) > 625 =>
|
||||
AutomatedTurretObject.RemoveTarget(t)
|
||||
t
|
||||
}
|
||||
removedTargets.foreach { noLongerDetectedTarget }
|
||||
testDistanceCheckQualifications(earlySize)
|
||||
removedTargets
|
||||
}
|
||||
}
|
||||
|
||||
object AutomatedTurretBehavior {
|
||||
import AutomatedTurret.Target
|
||||
final case class Alert(target: Target)
|
||||
|
||||
final case class Unalert(target: Target)
|
||||
|
||||
final case object ResetAlerts
|
||||
|
||||
private case object PeriodicDistanceCheck
|
||||
|
||||
final case class TurretTargetEntry(target: Target, regard: RegardTargetAs.TurretOpinion)
|
||||
|
||||
object RegardTargetAs {
|
||||
trait TurretOpinion
|
||||
|
||||
final case object Friendly extends TurretOpinion
|
||||
final case object Testing extends TurretOpinion
|
||||
final case object Unreachable extends TurretOpinion
|
||||
final case object Blocked extends TurretOpinion
|
||||
final case object Invalid extends TurretOpinion
|
||||
final case object Attack extends TurretOpinion
|
||||
}
|
||||
}
|
||||
|
|
@ -81,13 +81,13 @@ object CommonFieldData extends Marshallable[CommonFieldData] {
|
|||
CommonFieldData(faction, false, false, false, None, false, None, None, PlanetSideGUID(0))
|
||||
|
||||
def apply(faction: PlanetSideEmpire.Value, unk: Int): CommonFieldData =
|
||||
CommonFieldData(faction, false, false, unk > 1, None, unk % 1 == 1, None, None, PlanetSideGUID(0))
|
||||
CommonFieldData(faction, false, false, unk > 1, None, unk > 0, None, None, PlanetSideGUID(0))
|
||||
|
||||
def apply(faction: PlanetSideEmpire.Value, unk: Int, player_guid: PlanetSideGUID): CommonFieldData =
|
||||
CommonFieldData(faction, false, false, unk > 1, None, unk % 1 == 1, None, None, player_guid)
|
||||
CommonFieldData(faction, false, false, unk > 1, None, unk > 0, None, None, player_guid)
|
||||
|
||||
def apply(faction: PlanetSideEmpire.Value, destroyed: Boolean, unk: Int): CommonFieldData =
|
||||
CommonFieldData(faction, false, destroyed, unk > 1, None, unk % 1 == 1, None, None, PlanetSideGUID(0))
|
||||
CommonFieldData(faction, false, destroyed, unk > 1, None, unk > 0, None, None, PlanetSideGUID(0))
|
||||
|
||||
def apply(
|
||||
faction: PlanetSideEmpire.Value,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue