From 86acd94fd7114a3b18e1864ee9021da5226aaaf9 Mon Sep 17 00:00:00 2001 From: Fate-JH Date: Tue, 19 Mar 2024 20:29:37 -0400 Subject: [PATCH] removed three too-specific fields on the door's definition, resulting in nontrivial rewrites that resulted in all amenities being able to project an environment field onto the block map, to do with whatever it needs --- .../WeaponAndProjectileOperations.scala | 2 +- .../net/psforever/objects/SpawnPoint.scala | 8 ----- .../scala/net/psforever/objects/Vehicle.scala | 2 +- .../objects/definition/ObjectDefinition.scala | 12 ++++++- .../objects/geometry/GeometryForm.scala | 4 +-- .../VolumetricEnvironmentCollision.scala | 11 +++---- .../GlobalDefinitionsMiscellaneous.scala | 24 ++++++++------ .../serverobject/doors/DoorDefinition.scala | 31 ++++++++++--------- .../doors/InteriorDoorPassage.scala | 23 +++++++++++--- .../structures/AmenityDefinition.scala | 25 ++++++++++++++- .../terminals/ProximityDefinition.scala | 13 ++------ .../net/psforever/objects/zones/Zone.scala | 5 +-- .../objects/zones/blockmap/Sector.scala | 13 +++----- 13 files changed, 103 insertions(+), 70 deletions(-) diff --git a/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala b/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala index 1aa0e284e..4e1d27387 100644 --- a/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala +++ b/src/main/scala/net/psforever/actors/session/support/WeaponAndProjectileOperations.scala @@ -1515,7 +1515,7 @@ private[support] class WeaponAndProjectileOperations( origin, hitPosition, door.Position, - door.Definition.geometryInteractionRadius.get + 0.1f + door.Definition.UseRadius + 0.1f ) (door, intersectTest) } diff --git a/src/main/scala/net/psforever/objects/SpawnPoint.scala b/src/main/scala/net/psforever/objects/SpawnPoint.scala index 500126850..d6f800dde 100644 --- a/src/main/scala/net/psforever/objects/SpawnPoint.scala +++ b/src/main/scala/net/psforever/objects/SpawnPoint.scala @@ -162,18 +162,10 @@ object SpawnPoint { } trait SpawnPointDefinition { - private var radius: Float = 0f //m private var delay: Long = 0 //s private var noWarp: Option[mutable.Set[VehicleDefinition]] = None private var spawningFunc: (SpawnPoint, PlanetSideGameObject) => (Vector3, Vector3) = SpawnPoint.Default - def UseRadius: Float = radius - - def UseRadius_=(rad: Float): Float = { - radius = rad - UseRadius - } - def Delay: Long = delay def Delay_=(toDelay: Long): Long = { diff --git a/src/main/scala/net/psforever/objects/Vehicle.scala b/src/main/scala/net/psforever/objects/Vehicle.scala index 2c067a698..e60259ede 100644 --- a/src/main/scala/net/psforever/objects/Vehicle.scala +++ b/src/main/scala/net/psforever/objects/Vehicle.scala @@ -16,7 +16,7 @@ import net.psforever.objects.serverobject.hackable.Hackable import net.psforever.objects.serverobject.interior.{InteriorAwareFromInteraction, Sidedness} import net.psforever.objects.serverobject.structures.AmenityOwner import net.psforever.objects.vehicles._ -import net.psforever.objects.vehicles.interaction.{WithEntranceInVehicle, WithLava, WithWater} +import net.psforever.objects.vehicles.interaction.{WithLava, WithWater} import net.psforever.objects.vital.resistance.StandardResistanceProfile import net.psforever.objects.vital.Vitality import net.psforever.objects.vital.resolution.DamageResistanceModel diff --git a/src/main/scala/net/psforever/objects/definition/ObjectDefinition.scala b/src/main/scala/net/psforever/objects/definition/ObjectDefinition.scala index 23578022f..c1b12cb21 100644 --- a/src/main/scala/net/psforever/objects/definition/ObjectDefinition.scala +++ b/src/main/scala/net/psforever/objects/definition/ObjectDefinition.scala @@ -20,13 +20,23 @@ import net.psforever.types.OxygenState * So long as it is an `ObjectCreatePacket`, those methods can be called correctly for a game object of the desired type. * @param objectId the object's identifier number */ -abstract class ObjectDefinition(private val objectId: Int) extends BasicDefinition { +abstract class ObjectDefinition(private val objectId: Int) + extends BasicDefinition { var registerAs: String = "generic" /** a data converter for this type of object */ protected var packet: PacketConverter = new ObjectCreateConverter[PlanetSideGameObject]() {} Name = "object_definition" + private var useRadius: Float = 0f + + def UseRadius: Float = useRadius + + def UseRadius_=(radius: Float): Float = { + useRadius = radius + UseRadius + } + /** * Get the conversion object. * @return diff --git a/src/main/scala/net/psforever/objects/geometry/GeometryForm.scala b/src/main/scala/net/psforever/objects/geometry/GeometryForm.scala index 40a9afa54..070ae972e 100644 --- a/src/main/scala/net/psforever/objects/geometry/GeometryForm.scala +++ b/src/main/scala/net/psforever/objects/geometry/GeometryForm.scala @@ -106,8 +106,8 @@ object GeometryForm { */ def representByCylinder(radius: Float, height: Float)(o: Any): VolumetricGeometry = { o match { - case p: PlanetSideGameObject => Cylinder(p.Position, Vector3.relativeUp(p.Orientation), radius, height) - case s: SourceEntry => Cylinder(s.Position, Vector3.relativeUp(s.Orientation), radius, height) + case p: PlanetSideGameObject => Cylinder(p.Position, Vector3.relativeUp(p.Orientation), radius, math.abs(height)) + case s: SourceEntry => Cylinder(s.Position, Vector3.relativeUp(s.Orientation), radius, math.abs(height)) case _ => invalidCylinder } } diff --git a/src/main/scala/net/psforever/objects/geometry/VolumetricEnvironmentCollision.scala b/src/main/scala/net/psforever/objects/geometry/VolumetricEnvironmentCollision.scala index e2ae08ec6..db29ae14f 100644 --- a/src/main/scala/net/psforever/objects/geometry/VolumetricEnvironmentCollision.scala +++ b/src/main/scala/net/psforever/objects/geometry/VolumetricEnvironmentCollision.scala @@ -4,16 +4,13 @@ package net.psforever.objects.geometry import net.psforever.objects.PlanetSideGameObject import net.psforever.objects.geometry.d2.Rectangle import net.psforever.objects.geometry.d3.VolumetricGeometry -import net.psforever.objects.serverobject.doors.Door import net.psforever.objects.serverobject.environment.EnvironmentCollision import net.psforever.objects.zones.Zone import net.psforever.types.Vector3 -case class VolumetricEnvironmentCollision(door: Door) +final case class VolumetricEnvironmentCollision(g: VolumetricGeometry) extends EnvironmentCollision { - private lazy val geometry = door.Definition.Geometry.apply(door) private lazy val bound: Rectangle = { - val g = geometry Rectangle( g.pointOnOutside(Vector3(0, 1,0)).y, g.pointOnOutside(Vector3(-1,0,0)).x, @@ -22,12 +19,12 @@ case class VolumetricEnvironmentCollision(door: Door) ) } - def Geometry: VolumetricGeometry = geometry + def Geometry: VolumetricGeometry = g - def altitude: Float = geometry.pointOnOutside(Vector3(0,0,1)).z + def altitude: Float = g.pointOnOutside(Vector3(0,0,1)).z def testInteraction(obj: PlanetSideGameObject, varDepth: Float): Boolean = { - Zone.distanceCheck(obj.Definition.Geometry(obj), geometry) <= varDepth + Zone.distanceCheck(obj.Definition.Geometry(obj), g) <= varDepth } def bounding: Rectangle = bound diff --git a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala index bdd4b888f..f625b38f5 100644 --- a/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala +++ b/src/main/scala/net/psforever/objects/global/GlobalDefinitionsMiscellaneous.scala @@ -6,6 +6,7 @@ import net.psforever.objects.avatar.Certification import net.psforever.objects.equipment.EffectTarget import net.psforever.objects.geometry.GeometryForm import net.psforever.objects.geometry.d3.VolumetricGeometry +import net.psforever.objects.serverobject.doors.InteriorDoorField import net.psforever.objects.serverobject.mount.{MountInfo, SeatDefinition} import net.psforever.objects.serverobject.pad.VehicleSpawnPadDefinition import net.psforever.objects.serverobject.structures.AutoRepairStats @@ -601,10 +602,12 @@ object GlobalDefinitionsMiscellaneous { amp_cap_door.Name = "amp_cap_door" ancient_door.Name = "ancient_door" - ancient_door.geometryInteractionRadius = Some(1) + ancient_door.UseRadius = 1f + //ancient_door.environmentField = InteriorDoorField() ancient_garage_door.Name = "ancient_garage_door" - ancient_garage_door.geometryInteractionRadius = Some(1) + ancient_garage_door.UseRadius = 1f + //ancient_garage_door.environmentField = InteriorDoorField() cryo_med_door.Name = "cryo_med_door" @@ -648,14 +651,14 @@ object GlobalDefinitionsMiscellaneous { gr_door_airlock.Name = "gr_door_airlock" gr_door_ext.Name = "gr_door_ext" - gr_door_ext.geometryInteractionRadius = Some(1.9f) + gr_door_ext.UseRadius = 1.9f + gr_door_ext.environmentField = InteriorDoorField() gr_door_garage_ext.Name = "gr_door_garage_ext" + gr_door_garage_ext.UseRadius = 11f gr_door_garage_ext.initialOpeningDistance = 8f gr_door_garage_ext.continuousOpenDistance = 9f - gr_door_garage_ext.geometryInteractionRadius = Some(11) - gr_door_garage_ext.geometryInteractionHeight = Some(-11) - gr_door_garage_ext.geometryInteractionCenterOn = true + gr_door_garage_ext.environmentField = InteriorDoorField(Some(-11), centerOn = true) gr_door_garage_int.Name = "gr_door_garage_int" gr_door_garage_int.initialOpeningDistance = 8f @@ -664,15 +667,18 @@ object GlobalDefinitionsMiscellaneous { gr_door_int.Name = "gr_door_int" gr_door_main.Name = "gr_door_main" - gr_door_main.geometryInteractionRadius = Some(2.75f) + gr_door_main.UseRadius = 2.75f + gr_door_main.environmentField = InteriorDoorField() gr_door_mb_ext.Name = "gr_door_mb_ext" - gr_door_mb_ext.geometryInteractionRadius = Some(2) + gr_door_mb_ext.UseRadius = 2f + gr_door_mb_ext.environmentField = InteriorDoorField() gr_door_mb_int.Name = "gr_door_mb_int" gr_door_mb_lrg.Name = "gr_door_mb_lrg" - gr_door_mb_lrg.geometryInteractionRadius = Some(2.5f) + gr_door_mb_lrg.UseRadius = 2.5f + gr_door_mb_lrg.environmentField = InteriorDoorField() gr_door_mb_obsd.Name = "gr_door_mb_obsd" diff --git a/src/main/scala/net/psforever/objects/serverobject/doors/DoorDefinition.scala b/src/main/scala/net/psforever/objects/serverobject/doors/DoorDefinition.scala index f75d409dc..08b23a29c 100644 --- a/src/main/scala/net/psforever/objects/serverobject/doors/DoorDefinition.scala +++ b/src/main/scala/net/psforever/objects/serverobject/doors/DoorDefinition.scala @@ -3,7 +3,22 @@ package net.psforever.objects.serverobject.doors import net.psforever.objects.geometry.GeometryForm import net.psforever.objects.geometry.d3.VolumetricGeometry -import net.psforever.objects.serverobject.structures.AmenityDefinition +import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentTrait, PieceOfEnvironment} +import net.psforever.objects.serverobject.structures.{Amenity, AmenityDefinition, CreateEnvironmentField} + +final case class InteriorDoorField( + cylinderHeight: Option[Float] = None, + centerOn: Boolean = false + ) extends CreateEnvironmentField { + def attribute: EnvironmentTrait = EnvironmentAttribute.InteriorField + + def create(obj: Amenity): PieceOfEnvironment = { + obj match { + case door: Door => InteriorDoorPassage(door, cylinderHeight, centerOn) + case _ => throw new IllegalArgumentException("expecting door") + } + } +} /** * The definition for any `Door`. @@ -17,17 +32,5 @@ class DoorDefinition(objectId: Int) /** range within which the door must detect a target player to remain open */ var continuousOpenDistance: Float = 5.05f - var geometryInteractionRadius: Option[Float] = None - var geometryInteractionHeight: Option[Float] = None - var geometryInteractionCenterOn: Boolean = false - - override def Geometry: Any => VolumetricGeometry = { - (geometryInteractionRadius, geometryInteractionHeight, geometryInteractionCenterOn) match { - case (Some(r), Some(h), false) => GeometryForm.representByCylinder(r, h) - case (Some(r), Some(h), true) => GeometryForm.representByRaisedCylinder(r, h) - case (Some(r), None, false) => GeometryForm.representBySphereOnBase(r) - case (Some(r), None, true) => GeometryForm.representBySphere(r) - case _ => super.Geometry - } - } + override def Geometry: Any => VolumetricGeometry = GeometryForm.representBySphere(UseRadius) } diff --git a/src/main/scala/net/psforever/objects/serverobject/doors/InteriorDoorPassage.scala b/src/main/scala/net/psforever/objects/serverobject/doors/InteriorDoorPassage.scala index 37cbd226d..071130e4b 100644 --- a/src/main/scala/net/psforever/objects/serverobject/doors/InteriorDoorPassage.scala +++ b/src/main/scala/net/psforever/objects/serverobject/doors/InteriorDoorPassage.scala @@ -1,17 +1,30 @@ // Copyright (c) 2024 PSForever package net.psforever.objects.serverobject.doors -import net.psforever.objects.geometry.VolumetricEnvironmentCollision +import net.psforever.objects.geometry.{GeometryForm, VolumetricEnvironmentCollision} import net.psforever.objects.serverobject.environment.{EnvironmentAttribute, EnvironmentCollision, EnvironmentTrait, PieceOfEnvironment} -final case class InteriorDoorPassage(door: Door) +final case class InteriorDoorPassage( + door: Door, + cylinderHeight: Option[Float] = None, + centerOn: Boolean = false + ) extends PieceOfEnvironment { - assert(door.Definition.geometryInteractionRadius.nonEmpty, s"door ${door.GUID} needs an interaction radius to be volumetric") - //assert(door.Outwards != Vector3.Zero, s"door ${door.GUID} does not have an outwards direction") + assert(door.Definition.UseRadius > 0f, s"door ${door.GUID} needs an interaction radius to be positive") + private lazy val collisionObject = { + val radius = door.Definition.UseRadius + val g = (cylinderHeight, centerOn) match { + case (Some(h), false) => GeometryForm.representByCylinder(radius, h) _ + case (Some(h), true) => GeometryForm.representByRaisedCylinder(radius, h) _ + case (None, false) => GeometryForm.representBySphereOnBase(radius) _ + case _ => GeometryForm.representBySphere(radius) _ + } + VolumetricEnvironmentCollision(g.apply(door)) + } /** a general description of this environment */ override def attribute: EnvironmentTrait = EnvironmentAttribute.InteriorField /** a special representation of the region that qualifies as "this environment" */ - override def collision: EnvironmentCollision = VolumetricEnvironmentCollision(door) + override def collision: EnvironmentCollision = collisionObject } diff --git a/src/main/scala/net/psforever/objects/serverobject/structures/AmenityDefinition.scala b/src/main/scala/net/psforever/objects/serverobject/structures/AmenityDefinition.scala index 5141819fd..cd1f27c85 100644 --- a/src/main/scala/net/psforever/objects/serverobject/structures/AmenityDefinition.scala +++ b/src/main/scala/net/psforever/objects/serverobject/structures/AmenityDefinition.scala @@ -2,15 +2,25 @@ package net.psforever.objects.serverobject.structures import net.psforever.objects.definition.ObjectDefinition +import net.psforever.objects.serverobject.environment.{EnvironmentTrait, PieceOfEnvironment} import net.psforever.objects.vital.damage.DamageCalculations import net.psforever.objects.vital._ import net.psforever.objects.vital.resistance.ResistanceProfileMutators import net.psforever.objects.vital.resolution.DamageResistanceModel +import scala.annotation.unused + final case class AutoRepairStats(amount: Float, start: Long, repeat: Long, drain: Float) +trait CreateEnvironmentField { + //todo a way to probe for this property from create(...)'s output + def attribute: EnvironmentTrait + + def create(@unused obj: Amenity): PieceOfEnvironment +} + abstract class AmenityDefinition(objectId: Int) - extends ObjectDefinition(objectId) + extends ObjectDefinition(objectId) with ResistanceProfileMutators with DamageResistanceModel with VitalityDefinition { @@ -21,10 +31,23 @@ abstract class AmenityDefinition(objectId: Int) var autoRepair: Option[AutoRepairStats] = None + var fields: Seq[CreateEnvironmentField] = Seq() + def autoRepair_=(auto: AutoRepairStats): Option[AutoRepairStats] = { autoRepair = Some(auto) autoRepair } def hasAutoRepair: Boolean = autoRepair.nonEmpty + + def environmentField: Seq[CreateEnvironmentField] = fields + + def environmentField_=(theField: CreateEnvironmentField): Seq[CreateEnvironmentField] = { + environmentField_=(Seq(theField)) + } + + def environmentField_=(theFields: Seq[CreateEnvironmentField]): Seq[CreateEnvironmentField] = { + fields = fields ++ theFields + environmentField + } } diff --git a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala index adb0f99e1..f2397994f 100644 --- a/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala +++ b/src/main/scala/net/psforever/objects/serverobject/terminals/ProximityDefinition.scala @@ -2,7 +2,6 @@ package net.psforever.objects.serverobject.terminals import net.psforever.objects.PlanetSideGameObject -import net.psforever.objects.definition.ObjectDefinition import net.psforever.objects.equipment.EffectTarget import scala.collection.mutable @@ -16,13 +15,12 @@ import scala.concurrent.duration.{Duration, FiniteDuration} * between the server and client using `ProximityTerminalUseMessage` game packets. */ trait ProximityDefinition { - this: ObjectDefinition => - private var interval: FiniteDuration = Duration(0, "seconds") - private var useRadius: Float = 0f //TODO belongs on a wider range of object definitions private val targetValidation: mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject => Boolean] = new mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject => Boolean]() + def UseRadius: Float + def Interval: FiniteDuration = interval def Interval_=(amount: Int): FiniteDuration = { @@ -34,13 +32,6 @@ trait ProximityDefinition { Interval } - def UseRadius: Float = useRadius - - def UseRadius_=(radius: Float): Float = { - useRadius = radius - UseRadius - } - def TargetValidation: mutable.HashMap[EffectTarget.Category.Value, PlanetSideGameObject => Boolean] = targetValidation def Validations: Seq[PlanetSideGameObject => Boolean] = { diff --git a/src/main/scala/net/psforever/objects/zones/Zone.scala b/src/main/scala/net/psforever/objects/zones/Zone.scala index 446465435..70a459cef 100644 --- a/src/main/scala/net/psforever/objects/zones/Zone.scala +++ b/src/main/scala/net/psforever/objects/zones/Zone.scala @@ -40,6 +40,7 @@ import net.psforever.objects.guid.pool.NumberPool import net.psforever.objects.serverobject.PlanetSideServerObject import net.psforever.objects.serverobject.affinity.FactionAffinity import net.psforever.objects.serverobject.doors.Door +import net.psforever.objects.serverobject.environment.EnvironmentAttribute import net.psforever.objects.serverobject.interior.{InteriorAware, Sidedness} import net.psforever.objects.serverobject.locks.IFFLock import net.psforever.objects.serverobject.pad.VehicleSpawnPad @@ -966,7 +967,7 @@ object Zone { map.doorToLock .map { case (door, lock) => (guid(door), guid(lock)) } .collect { case (Some(door: Door), Some(lock: IFFLock)) - if door.Definition.geometryInteractionRadius.nonEmpty => + if door.Definition.environmentField.exists(f => f.attribute == EnvironmentAttribute.InteriorField) => door.WhichSide = Sidedness.StrictlyBetweenSides lock.WhichSide = Sidedness.OutsideOf } @@ -1103,7 +1104,7 @@ object Zone { .map { case (door, lock) => (guid(door), guid(lock))} .collect { case (Some(door: Door), Some(lock: IFFLock)) - if door.Definition.geometryInteractionRadius.nonEmpty => + if door.Definition.environmentField.exists(f => f.attribute == EnvironmentAttribute.InteriorField) => lock.WhichSide = Sidedness.OutsideOf } //medical terminals are always inside diff --git a/src/main/scala/net/psforever/objects/zones/blockmap/Sector.scala b/src/main/scala/net/psforever/objects/zones/blockmap/Sector.scala index a193c5f2c..531d64502 100644 --- a/src/main/scala/net/psforever/objects/zones/blockmap/Sector.scala +++ b/src/main/scala/net/psforever/objects/zones/blockmap/Sector.scala @@ -4,7 +4,6 @@ package net.psforever.objects.zones.blockmap import net.psforever.objects.ballistics.Projectile import net.psforever.objects.ce.Deployable import net.psforever.objects.equipment.Equipment -import net.psforever.objects.serverobject.doors.{Door, InteriorDoorPassage} import net.psforever.objects.serverobject.environment.PieceOfEnvironment import net.psforever.objects.serverobject.structures.{Amenity, Building} import net.psforever.objects.{Player, Vehicle} @@ -200,14 +199,12 @@ class Sector(val longitude: Int, val latitude: Int, val span: Int) deployables.list.size < deployables.addTo(d).size case b: Building => buildings.list.size < buildings.addTo(b).size - case d: Door => - val doorAdded = amenities.list.size < amenities.addTo(d).size - d.Definition.geometryInteractionRadius.collect { - case _ if doorAdded => environment.addTo(InteriorDoorPassage(d)) - } - doorAdded case a: Amenity => - amenities.list.size < amenities.addTo(a).size + val added = amenities.list.size < amenities.addTo(a).size + if (added) { + a.Definition.environmentField.foreach(field => environment.addTo(field.create(a))) + } + added case e: PieceOfEnvironment => environment.list.size < environment.addTo(e).size case p: Projectile =>