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

This commit is contained in:
Fate-JH 2024-03-19 20:29:37 -04:00
parent 84b3d2297a
commit 86acd94fd7
13 changed files with 103 additions and 70 deletions

View file

@ -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)
}

View file

@ -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 = {

View file

@ -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

View file

@ -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

View file

@ -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
}
}

View file

@ -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

View file

@ -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"

View file

@ -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)
}

View file

@ -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
}

View file

@ -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
}
}

View file

@ -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] = {

View file

@ -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

View file

@ -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 =>