mirror of
https://github.com/2revoemag/PSF-BotServer.git
synced 2026-02-05 18:20:58 +00:00
Another revamp to vehicle spawn process. Wrote tests.
This commit is contained in:
parent
5d5c609a2f
commit
68422401e5
|
|
@ -846,7 +846,7 @@ object GlobalDefinitions {
|
|||
}
|
||||
|
||||
/**
|
||||
* Using the definition for a piece of `Equipment` determine whether it can fly.
|
||||
* Using the definition for a `Vehicle` determine whether it can fly.
|
||||
* @param vdef the `VehicleDefinition` of the vehicle
|
||||
* @return `true`, if it is; `false`, otherwise
|
||||
*/
|
||||
|
|
@ -859,6 +859,39 @@ object GlobalDefinitions {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the definition for a `Vehicle` determine whether it hovers.
|
||||
* @param vdef the `VehicleDefinition` of the vehicle
|
||||
* @return `true`, if it can; `false`, otherwise
|
||||
*/
|
||||
def isHoverVehicle(vdef : VehicleDefinition) : Boolean = {
|
||||
vdef match {
|
||||
case `twomanhoverbuggy` | `magrider` | `router` | `flail` =>
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Using the definition for a `Vehicle` determine whether it can rotate its body without forward acceleration.
|
||||
* @param vdef the `VehicleDefinition` of the vehicle
|
||||
* @return `true`, if it is; `false`, otherwise
|
||||
*/
|
||||
def canStationaryRotate(vdef : VehicleDefinition) : Boolean = {
|
||||
if(isFlightVehicle(vdef) || isHoverVehicle(vdef)) {
|
||||
true
|
||||
}
|
||||
else {
|
||||
vdef match {
|
||||
case `lightning` | `prowler` | `vanguard` =>
|
||||
true
|
||||
case _ =>
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize `AmmoBoxDefinition` globals.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
|||
private var trunkAccess : Option[PlanetSideGUID] = None
|
||||
private var jammered : Boolean = false
|
||||
private var cloaked : Boolean = false
|
||||
private var controlled : Option[Int] = None
|
||||
|
||||
/**
|
||||
* Permissions control who gets to access different parts of the vehicle;
|
||||
|
|
@ -443,6 +444,15 @@ class Vehicle(private val vehicleDef : VehicleDefinition) extends PlanetSideServ
|
|||
*/
|
||||
def TrunkLockState : VehicleLockState.Value = groupPermissions(3)
|
||||
|
||||
def Controlled : Option[Int] = controlled
|
||||
|
||||
def Controlled_=(speed : Int) : Option[Int] = Controlled_=(Some(speed))
|
||||
|
||||
def Controlled_=(speed : Option[Int]) : Option[Int] = {
|
||||
controlled = speed
|
||||
Controlled
|
||||
}
|
||||
|
||||
/**
|
||||
* This is the definition entry that is used to store and unload pertinent information about the `Vehicle`.
|
||||
* @return the vehicle's definition entry
|
||||
|
|
|
|||
|
|
@ -141,10 +141,9 @@ object VehicleSpawnControl {
|
|||
final case class ConcealPlayer(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class LoadVehicle(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class SeatDriver(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class AwaitDriverInSeat(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class DriverInSeat(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class RailJackAction(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class ServerVehicleOverride(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class StartGuided(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class DriverVehicleControl(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
final case class FinalClearance(entry : VehicleSpawnControl.Order) extends Order(entry)
|
||||
}
|
||||
|
|
@ -251,9 +250,7 @@ object VehicleSpawnControl {
|
|||
@tailrec private final def recursiveBlockedReminder(iter : Iterator[VehicleSpawnControl.Order], cause : Option[Any]) : Unit = {
|
||||
if(iter.hasNext) {
|
||||
val recipient = iter.next
|
||||
if(recipient.sendTo != ActorRef.noSender) {
|
||||
recipient.sendTo ! VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, cause)
|
||||
}
|
||||
recipient.sendTo ! VehicleSpawnPad.PeriodicReminder(VehicleSpawnPad.Reminders.Blocked, cause)
|
||||
recursiveBlockedReminder(iter, cause)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.pad
|
||||
|
||||
import net.psforever.objects.serverobject.pad.process.AutoDriveControls
|
||||
import net.psforever.objects.{Player, Vehicle}
|
||||
import net.psforever.objects.serverobject.structures.Amenity
|
||||
import net.psforever.objects.zones.Zone
|
||||
|
|
@ -27,6 +28,8 @@ class VehicleSpawnPad(spDef : VehicleSpawnPadDefinition) extends Amenity {
|
|||
*/
|
||||
private var onRails : Boolean = true
|
||||
|
||||
private var guidedPath : List[AutoDriveControls.Configuration] = Nil
|
||||
|
||||
def Railed : Boolean = onRails
|
||||
|
||||
def Railed_=(useRails : Boolean) : Boolean = {
|
||||
|
|
@ -34,6 +37,13 @@ class VehicleSpawnPad(spDef : VehicleSpawnPadDefinition) extends Amenity {
|
|||
Railed
|
||||
}
|
||||
|
||||
def Guide : List[AutoDriveControls.Configuration] = guidedPath
|
||||
|
||||
def Guide_=(path : List[AutoDriveControls.Configuration]) : List[AutoDriveControls.Configuration] = {
|
||||
guidedPath = path
|
||||
Guide
|
||||
}
|
||||
|
||||
def Definition : VehicleSpawnPadDefinition = spDef
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,304 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.pad.process
|
||||
|
||||
import net.psforever.objects.{GlobalDefinitions, Vehicle}
|
||||
import net.psforever.types.Vector3
|
||||
|
||||
/**
|
||||
* Instructions to be processed by `VehicleSpawnControlGuided`.
|
||||
* These instructions coordinate basic vehicle manipulations such as driving, turning, and stopping.
|
||||
* If defined, they will operate on a newly formed vehicle after it is released from its spawn pad lifting platform
|
||||
* and after it has been issued at least one `ServerVehicleOverrideMsg` packet.
|
||||
*/
|
||||
object AutoDriveControls {
|
||||
|
||||
/**
|
||||
* A container that translates to a new `Setting` instruction.
|
||||
* Instructions are maintained in this form until they will be used due to the nature of the `Setting` object.
|
||||
* The least that this object needs to do is accept parameters that matches the specific `Setting` that it outputs.
|
||||
*/
|
||||
sealed trait Configuration {
|
||||
def Create : Setting
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction to be consumed by the cyclic operation of `VehicleSpawnControlGuided`
|
||||
* and are created by a `Configuration` object.
|
||||
* They are considered semi-immutable `case class` objects.
|
||||
* Externally, they are immutable by proper Scala standards.
|
||||
* Internally, they will be permitted `private` fields that can be modified the first time the object is used.
|
||||
*/
|
||||
sealed trait Setting {
|
||||
/**
|
||||
* The nature of the action being performed.
|
||||
* @return an enumerated value that explains the purpose of the action
|
||||
*/
|
||||
def Type : State.Value
|
||||
/**
|
||||
* The delay in between checks to determine if this setting has accomplished its goal or has entered an invalid state.
|
||||
* @return the length of the delay
|
||||
*/
|
||||
def Delay : Long = 200L
|
||||
/**
|
||||
* Data that is important for fulfilling the instruction on a user's client.
|
||||
* Highly specific to the implementation.
|
||||
* @return any data deemed important; `None`, if unnecessary
|
||||
*/
|
||||
def Data : Option[Any] = None
|
||||
/**
|
||||
* Perform a test to determine if the vehicle is capable of performing the action this instruction requires.
|
||||
* The test is typically simplistic in nature and often boils down to whether o not the vehicle is mobile.
|
||||
* @param vehicle the vehicle being controlled
|
||||
* @return `true`, if the action can (probably) be accomplished under the current conditions; `false`, otherwise
|
||||
*/
|
||||
def Validate(vehicle : Vehicle) : Boolean = Vector3.MagnitudeSquared(vehicle.Velocity.getOrElse(Vector3.Zero).xy) > 0
|
||||
/**
|
||||
* Perform a test to determine if the vehicle has reached a set of conditions
|
||||
* where the action performed by the instruction has been fulfilled.
|
||||
* This should count as the "end of this step" and the "beginning of the next step."
|
||||
* @param vehicle the vehicle being controlled
|
||||
* @return `true`, if the action has run to completion; `false`, otherwise
|
||||
*/
|
||||
def CompletionTest(vehicle : Vehicle) : Boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* The nature of the action being performed.
|
||||
* Different actions can be divided into types.
|
||||
*/
|
||||
object State extends Enumeration {
|
||||
val
|
||||
Cancel,
|
||||
Climb,
|
||||
Drive,
|
||||
Stop,
|
||||
Turn,
|
||||
Wait
|
||||
= Value
|
||||
}
|
||||
|
||||
protected final case class AutoDrive(speed : Int) extends Setting {
|
||||
def Type = State.Drive
|
||||
|
||||
override def Data = Some(speed)
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = true
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) = Vector3.MagnitudeSquared(vehicle.Velocity.getOrElse(Vector3.Zero).xy) > 0
|
||||
}
|
||||
|
||||
protected final case class AutoDriveDistance(start : Vector3, sqDistance : Float) extends Setting {
|
||||
def Type = State.Wait
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) : Boolean = {
|
||||
Vector3.DistanceSquared(vehicle.Position.xy, start) > sqDistance
|
||||
}
|
||||
}
|
||||
|
||||
protected final case class AutoDriveDistanceFromHere(sqDistance : Float) extends Setting {
|
||||
private var start : Option[Vector3] = None
|
||||
|
||||
def Type = State.Wait
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) : Boolean = {
|
||||
val startLoc = start.getOrElse({
|
||||
start = Some(vehicle.Position.xy)
|
||||
start.get
|
||||
})
|
||||
Vector3.DistanceSquared(vehicle.Position.xy, startLoc) > sqDistance
|
||||
}
|
||||
}
|
||||
|
||||
protected final case class AutoDriveForTime(length : Long) extends Setting {
|
||||
private var start : Option[Long] = None
|
||||
|
||||
def Type = State.Wait
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) : Boolean = {
|
||||
val time : Long = System.currentTimeMillis
|
||||
val startTime = start.getOrElse({
|
||||
start = Some(time)
|
||||
time
|
||||
})
|
||||
time - startTime >= length
|
||||
}
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = true
|
||||
}
|
||||
|
||||
protected final case class AutoDriveTurnBy(angle : Float, direction : Int) extends Setting {
|
||||
private var end : Option[Float] = None
|
||||
private var currAng : Float = 0f
|
||||
|
||||
def Type = State.Turn
|
||||
|
||||
override def Delay : Long = 100L //increased frequency
|
||||
|
||||
override def Data = Some(direction)
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) : Boolean = {
|
||||
val endAng = end.getOrElse {
|
||||
currAng = vehicle.Orientation.z
|
||||
var ang = (currAng + angle) % 360f
|
||||
if(ang < 0f) {
|
||||
ang += 360f
|
||||
}
|
||||
end = Some(ang)
|
||||
ang
|
||||
}
|
||||
val lastAng = currAng
|
||||
currAng = vehicle.Orientation.z
|
||||
//check that the expected angle is sandwiched between the previous angle and the current angle
|
||||
currAng == endAng || (lastAng < endAng && endAng <= currAng) || (lastAng > endAng && endAng >= currAng)
|
||||
}
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = direction != 15 && super.Validate(vehicle)
|
||||
}
|
||||
|
||||
protected final case class AutoDriveFirstGear() extends Setting {
|
||||
private var speed : Int = 0
|
||||
|
||||
def Type = State.Drive
|
||||
|
||||
override def Data = Some(speed)
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) = Vector3.MagnitudeSquared(vehicle.Velocity.getOrElse(Vector3.Zero)) > 0
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = {
|
||||
speed = vehicle.Definition.AutoPilotSpeed1
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
protected final case class AutoDriveSecondGear() extends Setting {
|
||||
private var speed : Int = 0
|
||||
|
||||
def Type = State.Drive
|
||||
|
||||
override def Data = Some(speed)
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) = Vector3.MagnitudeSquared(vehicle.Velocity.getOrElse(Vector3.Zero)) > 0
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = {
|
||||
speed = vehicle.Definition.AutoPilotSpeed2
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
protected final case class AutoDriveClimb(altitude : Float) extends Setting {
|
||||
def Type = State.Climb
|
||||
|
||||
override def Data = Some(altitude)
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) = {
|
||||
vehicle.Position.z >= altitude
|
||||
}
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = GlobalDefinitions.isFlightVehicle(vehicle.Definition)
|
||||
}
|
||||
|
||||
protected final case class AutoDriveCancelEarly(test : (Vehicle) => Boolean) extends Setting {
|
||||
def Type = State.Cancel
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) = true
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = test(vehicle)
|
||||
}
|
||||
|
||||
protected final case class AutoDriveStop() extends Setting {
|
||||
def Type = State.Stop
|
||||
|
||||
override def Validate(vehicle : Vehicle) : Boolean = true
|
||||
|
||||
def CompletionTest(vehicle : Vehicle) = Validate(vehicle)
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a validation test to determine if the remainder of the instructions should be processed.
|
||||
* @param test the custom valid conditions of the vehicle for continuing
|
||||
*/
|
||||
final case class CancelEarly(test : (Vehicle)=>Boolean) extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveCancelEarly(test)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gain altitude with a flying vehicle.
|
||||
* The climb speed is fixed.
|
||||
* @param altitude the vertical distance to ascend
|
||||
*/
|
||||
final case class Climb(altitude : Float) extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveClimb(altitude)
|
||||
}
|
||||
|
||||
/**
|
||||
* Drive a certain distance from somewhere.
|
||||
* @param start the fixed coordinates of the origin point
|
||||
* @param distance how far from the origin point the vehicle should travel
|
||||
*/
|
||||
final case class Distance(start : Vector3, distance : Float) extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveDistance(start, distance * distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Drive a certain distance from where the vehicle is at the time that the instruction is called.
|
||||
* The starting position is the current position of the vehicle.
|
||||
* @param distance how far from the origin point the vehicle should travel
|
||||
*/
|
||||
final case class DistanceFromHere(distance : Float) extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveDistanceFromHere(distance * distance)
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic drive forward instruction.
|
||||
* @see `ServerVehicleOverrideMsg.forward_speed`
|
||||
* @param speed the speed that the vehicle accelerates to;
|
||||
* scaled in a curious way
|
||||
*/
|
||||
final case class Drive(speed : Int) extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDrive(speed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Special drive forward instruction.
|
||||
* @see `ServerVehicleOverrideMsg.forward_speed`
|
||||
* @see `VehicleDefinition.AutoPilotSpeed1`
|
||||
*/
|
||||
final case class FirstGear() extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveFirstGear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Drive or idle for a certain duration.
|
||||
* The starting position is the current position of the vehicle.
|
||||
* @param time how long to contiue driving under the current conditions
|
||||
*/
|
||||
final case class ForTime(time : Long) extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveForTime(time)
|
||||
}
|
||||
|
||||
/**
|
||||
* Special drive forward instruction.
|
||||
* @see `ServerVehicleOverrideMsg.forward_speed`
|
||||
* @see `VehicleDefinition.AutoPilotSpeed2`
|
||||
*/
|
||||
final case class SecondGear() extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveSecondGear()
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop driving (but do not cancel the server override state).
|
||||
*/
|
||||
final case class Stop() extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveStop()
|
||||
}
|
||||
|
||||
/**
|
||||
* Cause the vehicle to turn a certain amount.
|
||||
* @see `VehicleMessage.wheel_direction`
|
||||
* @param angle the angle by which to turn the vehicle
|
||||
* @param direction the wheel direction of the vehicle
|
||||
*/
|
||||
final case class TurnBy(angle : Float, direction : Int) extends Configuration {
|
||||
def Create : Setting = AutoDriveControls.AutoDriveTurnBy(angle, direction)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,8 +9,8 @@ import org.log4s.Logger
|
|||
|
||||
/**
|
||||
* Base for all `VehicleSpawnControl`-related `Actor` classes.
|
||||
* The primary purpose of this superclass is to provide a common convention for the logging system's name.
|
||||
* Additional functionality that ewcovers the `Zone` of the owned amenity `VehcileSpawnPad` is also included.
|
||||
* Provide a common convention for the logging system's name.
|
||||
* Additional functionality that recovers the `Zone` of the owned amenity `VehicleSpawnPad`.
|
||||
* @param pad a `VehicleSpawnPad` object
|
||||
*/
|
||||
abstract class VehicleSpawnControlBase(pad : VehicleSpawnPad) extends Actor {
|
||||
|
|
@ -51,21 +51,19 @@ abstract class VehicleSpawnControlBase(pad : VehicleSpawnPad) extends Actor {
|
|||
|
||||
/**
|
||||
* A common manner of utilizing the logging agent such that all messages have the same logging level.
|
||||
* The default should be set to `trace`.
|
||||
* The default should be `trace`-level comments.
|
||||
* No important messages should processed by this agent; only consume general vehicle spawn status.
|
||||
* @param msg the message
|
||||
*/
|
||||
def trace(msg : String) : Unit = log.trace(msg)
|
||||
|
||||
protected def Pad : VehicleSpawnPad = pad
|
||||
|
||||
/**
|
||||
* The continent the pad recognizes as a place of installation will change as its `Owner` changes.
|
||||
* Originally, it belongs to a default non-`Building` object that is owned by a default non-`Zone` object called "nowhere."
|
||||
* Eventually, it will belong to an active `Building` object that belongs to an active `Zone` object with an identifier.
|
||||
* Originally, it belongs to a default non-`Building` object that is owned by a default non-`Zone` object.
|
||||
* Eventually, it will belong to an active `Building` object that will belong to an active `Zone` object.
|
||||
* With respect to `GetLogger(String)`, the active `Zone` object will be valid shortly after the object is registered,
|
||||
* but will still be separated from being owned by a valid `Building` object by a few validation checks.
|
||||
* @return the (current) `Zone` object
|
||||
*/
|
||||
def Continent : Zone = Pad.Owner.asInstanceOf[Building].Zone
|
||||
def Continent : Zone = pad.Owner.asInstanceOf[Building].Zone
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,11 +38,8 @@ class VehicleSpawnControlConcealPlayer(pad : VehicleSpawnPad) extends VehicleSpa
|
|||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
}
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.Reminder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.Reminder
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.GetNewOrder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.pad.process
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
|
||||
/**
|
||||
* An `Actor` that handles vehicle spawning orders for a `VehicleSpawnPad`.
|
||||
* The basic `VehicleSpawnControl` is the root of a simple tree of "spawn control" objects that chain to each other.
|
||||
* Each object performs on (or more than one related) actions upon the vehicle order that was submitted.<br>
|
||||
* <br>
|
||||
* A certain amount of time after the server has asserted control over a newly-spawned vehicle,
|
||||
* control of that vehicle is given over to the driver.
|
||||
* It has failure cases should the driver be in an incorrect state.
|
||||
* @param pad the `VehicleSpawnPad` object being governed
|
||||
*/
|
||||
class VehicleSpawnControlDriverControl(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
|
||||
def LogId = "-overrider"
|
||||
|
||||
val finalClear = context.actorOf(Props(classOf[VehicleSpawnControlFinalClearance], pad), s"${context.parent.path.name}-final")
|
||||
|
||||
def receive : Receive = {
|
||||
case VehicleSpawnControl.Process.DriverVehicleControl(entry) =>
|
||||
val vehicle = entry.vehicle
|
||||
if(pad.Railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
|
||||
}
|
||||
if(vehicle.Health == 0) {
|
||||
trace(s"vehicle was already destroyed; but, everything is fine")
|
||||
}
|
||||
if(entry.sendTo != ActorRef.noSender) {
|
||||
val driver = entry.driver
|
||||
entry.sendTo ! VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, pad)
|
||||
if(driver.VehicleSeated.contains(vehicle.GUID)) {
|
||||
trace(s"returning control of ${vehicle.Definition.Name} to ${driver.Name}")
|
||||
}
|
||||
else {
|
||||
trace(s"${driver.Name} is not seated in ${vehicle.Definition.Name}; vehicle controls have been locked")
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace("can not properly return control to driver")
|
||||
}
|
||||
finalClear ! VehicleSpawnControl.Process.FinalClearance(entry)
|
||||
|
||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case msg @ VehicleSpawnControl.Process.FinalClearance(_) =>
|
||||
finalClear ! msg
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
|
@ -23,14 +23,22 @@ class VehicleSpawnControlFinalClearance(pad : VehicleSpawnPad) extends VehicleSp
|
|||
|
||||
def receive : Receive = {
|
||||
case VehicleSpawnControl.Process.FinalClearance(entry) =>
|
||||
if(Vector3.DistanceSquared(entry.vehicle.Position, pad.Position) > 100.0f) { //10m away from pad
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.Reminder
|
||||
self ! VehicleSpawnControlFinalClearance.Test(entry)
|
||||
|
||||
case VehicleSpawnControlFinalClearance.Test(entry) =>
|
||||
if(Vector3.DistanceSquared(entry.vehicle.Position.xy, pad.Position.xy) > 100.0f) { //10m away from pad
|
||||
trace("pad cleared")
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
}
|
||||
else {
|
||||
context.system.scheduler.scheduleOnce(2000 milliseconds, self, VehicleSpawnControl.Process.FinalClearance(entry))
|
||||
context.system.scheduler.scheduleOnce(2000 milliseconds, self, VehicleSpawnControlFinalClearance.Test(entry))
|
||||
}
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
object VehicleSpawnControlFinalClearance {
|
||||
private final case class Test(entry : VehicleSpawnControl.Order)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,126 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package net.psforever.objects.serverobject.pad.process
|
||||
|
||||
import akka.actor.{ActorRef, Props}
|
||||
import net.psforever.objects.Vehicle
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
|
||||
import scala.concurrent.ExecutionContext.Implicits.global
|
||||
import scala.concurrent.duration._
|
||||
|
||||
/**
|
||||
* An `Actor` that handles vehicle spawning orders for a `VehicleSpawnPad`.
|
||||
* The basic `VehicleSpawnControl` is the root of a simple tree of "spawn control" objects that chain to each other.
|
||||
* Each object performs on (or more than one related) actions upon the vehicle order that was submitted.<br>
|
||||
* <br>
|
||||
* After the vehicle has been released from the spawn pad lifting platform,
|
||||
* it enters into an auto-drive mode that has at least two stages.
|
||||
* An undefined number of stages cane be included, however.
|
||||
* This can lead the newly-spawned vehicle through a rough pre-defined path.<br>
|
||||
* <br>
|
||||
* Throughout this process, the conditions of `ServerVehicleOverrideMsg` are still in effect.
|
||||
* @param pad the `VehicleSpawnPad` object being governed
|
||||
*/
|
||||
class VehicleSpawnControlGuided(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
|
||||
def LogId = "-guide"
|
||||
|
||||
val driverControl = context.actorOf(Props(classOf[VehicleSpawnControlDriverControl], pad), s"${context.parent.path.name}-driver")
|
||||
|
||||
def receive : Receive = {
|
||||
case VehicleSpawnControl.Process.StartGuided(entry) =>
|
||||
pad.Guide match {
|
||||
case Nil =>
|
||||
trace("no guided path for this pad")
|
||||
driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry)
|
||||
case path =>
|
||||
self ! VehicleSpawnControlGuided.InitialGuided(entry, path.map { _.Create })
|
||||
}
|
||||
|
||||
case VehicleSpawnControlGuided.SelectNextGuided(entry, actions) =>
|
||||
actions match {
|
||||
case Nil | _ :: Nil =>
|
||||
trace("custom vehicle path completed")
|
||||
driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry)
|
||||
case _ :: xs =>
|
||||
self ! VehicleSpawnControlGuided.InitialGuided(entry, xs)
|
||||
}
|
||||
|
||||
case VehicleSpawnControlGuided.InitialGuided(entry, actions) =>
|
||||
val vehicle = entry.vehicle
|
||||
if(entry.sendTo != ActorRef.noSender && vehicle.Health != 0 && entry.driver.VehicleSeated.contains(vehicle.GUID) && actions.head.Validate(vehicle)) {
|
||||
trace(s"custom vehicle path plotted - ${actions.head.Type}")
|
||||
entry.sendTo ! VehicleSpawnControlGuided.GuidedControl(actions.head.Type, vehicle, actions.head.Data)
|
||||
self ! VehicleSpawnControlGuided.ContinueGuided(entry, actions)
|
||||
}
|
||||
else {
|
||||
trace(s"projected ${vehicle.Definition.Name} path interruption; exit guided mode")
|
||||
driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry)
|
||||
}
|
||||
|
||||
case VehicleSpawnControlGuided.ValidateGuided(entry, actions) =>
|
||||
val vehicle = entry.vehicle
|
||||
if(entry.sendTo != ActorRef.noSender && vehicle.Health != 0 && entry.driver.VehicleSeated.contains(vehicle.GUID) && actions.head.Validate(vehicle)) {
|
||||
self ! VehicleSpawnControlGuided.ContinueGuided(entry, actions)
|
||||
}
|
||||
else {
|
||||
trace(s"plotted ${vehicle.Definition.Name} path interruption; exit guided mode")
|
||||
driverControl ! VehicleSpawnControl.Process.DriverVehicleControl(entry)
|
||||
}
|
||||
|
||||
case VehicleSpawnControlGuided.ContinueGuided(entry, actions) =>
|
||||
if(actions.head.CompletionTest(entry.vehicle)) {
|
||||
trace("step completed")
|
||||
self ! VehicleSpawnControlGuided.SelectNextGuided(entry, actions)
|
||||
}
|
||||
else {
|
||||
context.system.scheduler.scheduleOnce(actions.head.Delay milliseconds, self, VehicleSpawnControlGuided.ValidateGuided(entry, actions))
|
||||
}
|
||||
|
||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case msg @ VehicleSpawnControl.Process.FinalClearance(_) =>
|
||||
driverControl ! msg
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
object VehicleSpawnControlGuided {
|
||||
/**
|
||||
* Select the first instruction from the list.
|
||||
* @param entry the vehicle order
|
||||
* @param actions the list of instructions related to this spawn pad
|
||||
*/
|
||||
private final case class InitialGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting])
|
||||
/**
|
||||
* Swap to the next instruction, if it exists.
|
||||
* @param entry the vehicle order
|
||||
* @param actions the list of instructions related to this spawn pad
|
||||
*/
|
||||
private final case class SelectNextGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting])
|
||||
/**
|
||||
* The validation test determines whether the vehicle, the driver, and any other important elements
|
||||
* are still in a state where the current instruction can be accomplished.
|
||||
* If the validation test passes, the current instruction can continue to run to completion.
|
||||
* If the validation test fails, the remainder of the instructions are aborted.
|
||||
* @param entry the vehicle order
|
||||
* @param actions the list of instructions related to this spawn pad
|
||||
*/
|
||||
private final case class ValidateGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting])
|
||||
/**
|
||||
* If the previous validation test passes, the current instruction can continue to run to completion.
|
||||
* Once completed, the next instruction can be selected.
|
||||
* @param entry the vehicle order
|
||||
* @param actions the list of instructions related to this spawn pad
|
||||
*/
|
||||
private final case class ContinueGuided(entry : VehicleSpawnControl.Order, actions : List[AutoDriveControls.Setting])
|
||||
|
||||
/**
|
||||
* A message that explains the current instruction in the guided mode to another agency.
|
||||
* @param command the nature of the action being performed
|
||||
* @param vehicle the vehicle being controlled
|
||||
* @param data optional data used to process the instruction
|
||||
*/
|
||||
final case class GuidedControl(command : AutoDriveControls.State.Value, vehicle : Vehicle, data : Option[Any])
|
||||
}
|
||||
|
|
@ -30,7 +30,10 @@ class VehicleSpawnControlLoadVehicle(pad : VehicleSpawnPad) extends VehicleSpawn
|
|||
val vehicle = entry.vehicle
|
||||
if(entry.driver.Continent == Continent.Id) {
|
||||
trace(s"loading the ${vehicle.Definition.Name}")
|
||||
vehicle.Position = vehicle.Position - Vector3(0, 0, if(GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5)
|
||||
if(pad.Railed) {
|
||||
//load the vehicle in the spawn pad trench, underground, initially
|
||||
vehicle.Position = vehicle.Position - Vector3(0, 0, if(GlobalDefinitions.isFlightVehicle(vehicle.Definition)) 9 else 5)
|
||||
}
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.LoadVehicle(vehicle, Continent)
|
||||
context.system.scheduler.scheduleOnce(100 milliseconds, railJack, VehicleSpawnControl.Process.RailJackAction(entry))
|
||||
}
|
||||
|
|
@ -40,11 +43,8 @@ class VehicleSpawnControlLoadVehicle(pad : VehicleSpawnPad) extends VehicleSpawn
|
|||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
}
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.Reminder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.Reminder
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.GetNewOrder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,25 +26,17 @@ class VehicleSpawnControlRailJack(pad : VehicleSpawnPad) extends VehicleSpawnCon
|
|||
|
||||
def receive : Receive = {
|
||||
case VehicleSpawnControl.Process.RailJackAction(entry) =>
|
||||
if(entry.vehicle.Health == 0) {
|
||||
trace("vehicle was already destroyed; clean it up")
|
||||
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
if(pad.Railed) {
|
||||
trace(s"attaching vehicle to railed platform")
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.AttachToRails(entry.vehicle, pad, Continent.Id)
|
||||
}
|
||||
else {
|
||||
if(pad.Railed) {
|
||||
trace(s"attaching vehicle to railed platform")
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.AttachToRails(entry.vehicle, pad, Continent.Id)
|
||||
}
|
||||
else {
|
||||
trace(s"railed platform skipped; vehicle positioned temporarily in pad trench")
|
||||
}
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.Reminder
|
||||
context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, VehicleSpawnControl.Process.SeatDriver(entry))
|
||||
trace(s"railed platform skipped; vehicle positioned in pad trench temporarily")
|
||||
}
|
||||
context.system.scheduler.scheduleOnce(10 milliseconds, seatDriver, VehicleSpawnControl.Process.SeatDriver(entry))
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.GetNewOrder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import scala.concurrent.duration._
|
|||
* Each object performs on (or more than one related) actions upon the vehicle order that was submitted.<br>
|
||||
* <br>
|
||||
* This object forces the prospective driver to take the driver seat.
|
||||
* Three separate but sequentially significant steps occur within the scope of this object.
|
||||
* Multiple separate but sequentially significant steps occur within the scope of this object.
|
||||
* First, this step waits for the vehicle to be completely ready to accept the driver.
|
||||
* Second, this step triggers the player to actually be moved into the driver seat.
|
||||
* Finally, this step waits until the driver is properly in the driver seat.
|
||||
|
|
@ -29,84 +29,71 @@ class VehicleSpawnControlSeatDriver(pad : VehicleSpawnPad) extends VehicleSpawnC
|
|||
|
||||
def receive : Receive = {
|
||||
case VehicleSpawnControl.Process.SeatDriver(entry) =>
|
||||
if(entry.vehicle.Actor == ActorRef.noSender) { //wait for the component of the vehicle needed for seating to be loaded
|
||||
context.system.scheduler.scheduleOnce(50 milliseconds, self, VehicleSpawnControl.Process.SeatDriver(entry))
|
||||
self ! VehicleSpawnControlSeatDriver.AwaitVehicleReadiness(entry)
|
||||
|
||||
case VehicleSpawnControlSeatDriver.AwaitVehicleReadiness(entry) =>
|
||||
if(entry.vehicle.Actor == ActorRef.noSender) { //wait for a necessary vehicle component to be loaded
|
||||
context.system.scheduler.scheduleOnce(50 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitVehicleReadiness(entry))
|
||||
}
|
||||
else {
|
||||
val driver = entry.driver
|
||||
if(entry.vehicle.Health == 0) {
|
||||
trace("vehicle was already destroyed; clean it up")
|
||||
if(pad.Railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
|
||||
}
|
||||
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
}
|
||||
else if(entry.sendTo != ActorRef.noSender && driver.isAlive && driver.Continent == Continent.Id && driver.VehicleSeated.isEmpty) {
|
||||
trace("driver to be made seated in vehicle")
|
||||
entry.sendTo ! VehicleSpawnPad.StartPlayerSeatedInVehicle(entry.vehicle, pad)
|
||||
entry.vehicle.Actor.tell(Mountable.TryMount(driver, 0), entry.sendTo) //entry.sendTo should handle replies to TryMount
|
||||
context.system.scheduler.scheduleOnce(1000 milliseconds, self, VehicleSpawnControl.Process.AwaitDriverInSeat(entry))
|
||||
}
|
||||
else {
|
||||
trace("driver lost; vehicle stranded on pad")
|
||||
context.system.scheduler.scheduleOnce(1000 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
|
||||
}
|
||||
trace("vehicle ready")
|
||||
self ! VehicleSpawnControlSeatDriver.BeginDriverInSeat(entry)
|
||||
}
|
||||
|
||||
case VehicleSpawnControl.Process.AwaitDriverInSeat(entry) =>
|
||||
case VehicleSpawnControlSeatDriver.BeginDriverInSeat(entry) =>
|
||||
val driver = entry.driver
|
||||
if(entry.vehicle.Health == 0) {
|
||||
trace("vehicle was already destroyed; clean it up")
|
||||
if(pad.Railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
|
||||
}
|
||||
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
if(entry.sendTo != ActorRef.noSender && entry.vehicle.Health > 0 && driver.isAlive && driver.Continent == Continent.Id && driver.VehicleSeated.isEmpty) {
|
||||
trace("driver to be made seated in vehicle")
|
||||
entry.sendTo ! VehicleSpawnPad.StartPlayerSeatedInVehicle(entry.vehicle, pad)
|
||||
entry.vehicle.Actor.tell(Mountable.TryMount(driver, 0), entry.sendTo) //entry.sendTo should handle replies to TryMount
|
||||
context.system.scheduler.scheduleOnce(1000 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry))
|
||||
}
|
||||
else if(entry.sendTo == ActorRef.noSender || driver.Continent != Continent.Id) {
|
||||
else {
|
||||
trace("driver lost; vehicle stranded on pad")
|
||||
context.system.scheduler.scheduleOnce(1000 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
|
||||
}
|
||||
|
||||
case VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry) =>
|
||||
val driver = entry.driver
|
||||
if(entry.sendTo == ActorRef.noSender || driver.Continent != Continent.Id) {
|
||||
trace("driver lost, but operations can continue")
|
||||
vehicleOverride ! VehicleSpawnControl.Process.ServerVehicleOverride(entry)
|
||||
}
|
||||
else if(driver.isAlive && driver.VehicleSeated.isEmpty) {
|
||||
context.system.scheduler.scheduleOnce(100 milliseconds, self, VehicleSpawnControl.Process.AwaitDriverInSeat(entry))
|
||||
context.system.scheduler.scheduleOnce(100 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry))
|
||||
}
|
||||
else {
|
||||
trace(s"driver is sitting down")
|
||||
val time = if(pad.Railed) 1000 else VehicleSpawnControlSeatDriver.RaillessSeatAnimationTimes(entry.vehicle.Definition.Name)
|
||||
context.system.scheduler.scheduleOnce(time milliseconds, self, VehicleSpawnControl.Process.DriverInSeat(entry))
|
||||
context.system.scheduler.scheduleOnce(time milliseconds, self, VehicleSpawnControlSeatDriver.DriverInSeat(entry))
|
||||
}
|
||||
|
||||
case VehicleSpawnControl.Process.DriverInSeat(entry) =>
|
||||
if(entry.vehicle.Health == 0) {
|
||||
trace(s"vehicle was already destroyed; clean it up")
|
||||
if(pad.Railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
|
||||
}
|
||||
VehicleSpawnControl.DisposeSpawnedVehicle(entry, Continent)
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
}
|
||||
else if(entry.sendTo != ActorRef.noSender || entry.driver.Continent != Continent.Id) {
|
||||
case VehicleSpawnControlSeatDriver.DriverInSeat(entry) =>
|
||||
if(entry.sendTo != ActorRef.noSender || entry.driver.Continent != Continent.Id) {
|
||||
trace(s"driver ${entry.driver.Name} has taken the wheel")
|
||||
entry.sendTo ! VehicleSpawnPad.PlayerSeatedInVehicle(entry.vehicle, pad)
|
||||
context.system.scheduler.scheduleOnce(10 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
|
||||
}
|
||||
else {
|
||||
trace("driver lost, but operations can continue")
|
||||
context.system.scheduler.scheduleOnce(10 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
|
||||
}
|
||||
context.system.scheduler.scheduleOnce(800 milliseconds, vehicleOverride, VehicleSpawnControl.Process.ServerVehicleOverride(entry))
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.Reminder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.Reminder
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.GetNewOrder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
}
|
||||
|
||||
object VehicleSpawnControlSeatDriver {
|
||||
final case class AwaitVehicleReadiness(entry : VehicleSpawnControl.Order)
|
||||
|
||||
final case class BeginDriverInSeat(entry : VehicleSpawnControl.Order)
|
||||
|
||||
final case class AwaitDriverInSeat(entry : VehicleSpawnControl.Order)
|
||||
|
||||
final case class DriverInSeat(entry : VehicleSpawnControl.Order)
|
||||
|
||||
/**
|
||||
* If the spawn pad associated with this `Actor` chain is not `Railed` -
|
||||
* not guaranteed to have the correct ingame globally unique id of the spawn pad -
|
||||
|
|
|
|||
|
|
@ -21,59 +21,39 @@ import scala.concurrent.duration._
|
|||
class VehicleSpawnControlServerVehicleOverride(pad : VehicleSpawnPad) extends VehicleSpawnControlBase(pad) {
|
||||
def LogId = "-overrider"
|
||||
|
||||
val finalClear = context.actorOf(Props(classOf[VehicleSpawnControlFinalClearance], pad), s"${context.parent.path.name}-final")
|
||||
val vehicleGuide = context.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), s"${context.parent.path.name}-guide")
|
||||
|
||||
def receive : Receive = {
|
||||
case VehicleSpawnControl.Process.ServerVehicleOverride(entry) =>
|
||||
val vehicle = entry.vehicle
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id)
|
||||
val pad_railed = pad.Railed
|
||||
if(pad_railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id)
|
||||
}
|
||||
if(vehicle.Health == 0) {
|
||||
trace(s"vehicle was already destroyed; but, everything is fine")
|
||||
if(pad.Railed) {
|
||||
if(pad_railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
|
||||
}
|
||||
finalClear ! VehicleSpawnControl.Process.FinalClearance(entry)
|
||||
vehicleGuide ! VehicleSpawnControl.Process.FinalClearance(entry)
|
||||
}
|
||||
else if(entry.sendTo != ActorRef.noSender && entry.driver.isAlive && entry.driver.Continent == Continent.Id && entry.driver.VehicleSeated.contains(vehicle.GUID)) {
|
||||
trace(s"telling ${entry.driver.Name} that the server is assuming control of the ${vehicle.Definition.Name}")
|
||||
entry.sendTo ! VehicleSpawnPad.ServerVehicleOverrideStart(vehicle, pad)
|
||||
context.system.scheduler.scheduleOnce(3000 milliseconds, self, VehicleSpawnControl.Process.DriverVehicleControl(entry))
|
||||
context.system.scheduler.scheduleOnce(3000 milliseconds, vehicleGuide, VehicleSpawnControl.Process.StartGuided(entry))
|
||||
}
|
||||
else {
|
||||
if(pad.Railed) {
|
||||
if(pad_railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
|
||||
}
|
||||
finalClear ! VehicleSpawnControl.Process.FinalClearance(entry)
|
||||
vehicleGuide ! VehicleSpawnControl.Process.FinalClearance(entry)
|
||||
}
|
||||
|
||||
case VehicleSpawnControl.Process.DriverVehicleControl(entry) =>
|
||||
val vehicle = entry.vehicle
|
||||
if(pad.Railed) {
|
||||
Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
|
||||
}
|
||||
if(vehicle.Health == 0) {
|
||||
trace(s"vehicle was already destroyed; but, everything is fine")
|
||||
}
|
||||
if(entry.sendTo != ActorRef.noSender) {
|
||||
val driver = entry.driver
|
||||
entry.sendTo ! VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, pad)
|
||||
if(driver.VehicleSeated.contains(vehicle.GUID)) {
|
||||
trace(s"returning control of ${vehicle.Definition.Name} to ${driver.Name}")
|
||||
}
|
||||
else {
|
||||
trace(s"${driver.Name} is not seated in ${vehicle.Definition.Name}; can not properly return control to driver")
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace("can not properly return control to driver")
|
||||
}
|
||||
finalClear ! VehicleSpawnControl.Process.FinalClearance(entry)
|
||||
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
|
||||
context.parent ! msg
|
||||
|
||||
case msg @ VehicleSpawnControl.Process.FinalClearance(_) =>
|
||||
finalClear ! msg
|
||||
|
||||
case VehicleSpawnControl.ProcessControl.GetNewOrder =>
|
||||
context.parent ! VehicleSpawnControl.ProcessControl.GetNewOrder
|
||||
vehicleGuide ! msg
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,7 +33,8 @@ import scodec.codecs._
|
|||
* @param lock_accelerator driver has no control over vehicle acceleration
|
||||
* @param lock_wheel driver has no control over vehicle turning
|
||||
* @param reverse move in reverse
|
||||
* @param unk4 na
|
||||
* @param unk4 na;
|
||||
* something to do with vehicle bailable speed
|
||||
* @param lock_vthrust pilot has no control over vertical thrust;
|
||||
* asserts a constant positive vertical thrust;
|
||||
* the only valid setting appears to be 1
|
||||
|
|
@ -58,26 +59,6 @@ final case class ServerVehicleOverrideMsg(lock_accelerator : Boolean,
|
|||
}
|
||||
|
||||
object ServerVehicleOverrideMsg extends Marshallable[ServerVehicleOverrideMsg] {
|
||||
/**
|
||||
* Common lock control packet format.
|
||||
* Strafing is always treated as unlocked.
|
||||
* @param flight vehicle flies and should move vertically
|
||||
* @param speed "something like speed"
|
||||
* @return a `ServerVehicleOverrideMsg` packet
|
||||
*/
|
||||
def Lock(flight : Int, speed : Int) : ServerVehicleOverrideMsg = {
|
||||
ServerVehicleOverrideMsg(true, true, false, false, flight, 0, speed, Some(0))
|
||||
}
|
||||
|
||||
/**
|
||||
* Common cancellable auto-drive packet format.
|
||||
* @param speed "something like speed"
|
||||
* @return a `ServerVehicleOverrideMsg` packet
|
||||
*/
|
||||
def Auto(speed : Int) : ServerVehicleOverrideMsg = {
|
||||
ServerVehicleOverrideMsg(false, false, false, true, 0, 0, speed, None)
|
||||
}
|
||||
|
||||
implicit val codec: Codec[ServerVehicleOverrideMsg] = (
|
||||
("lock_accelerator" | bool) ::
|
||||
(("lock_wheel" | bool) >>:~ { test =>
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ import scodec.codecs._
|
|||
* @param unk4 na
|
||||
* @param wheel_direction for ground vehicles, whether the wheels are being turned;
|
||||
* 15 for straight;
|
||||
* 0 for hard left;
|
||||
* 30 for hard right
|
||||
* 0 for hard right;
|
||||
* 30 for hard left
|
||||
* @param unk5 na
|
||||
* @param unk6 na
|
||||
* @see `PlacementData`
|
||||
|
|
|
|||
|
|
@ -56,18 +56,4 @@ class ServerVehicleOverrideMsgTest extends Specification {
|
|||
|
||||
pkt mustEqual string2
|
||||
}
|
||||
|
||||
"encode (3)" in {
|
||||
val msg = ServerVehicleOverrideMsg.Lock(0, 12)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string1
|
||||
}
|
||||
|
||||
"encode (4)" in {
|
||||
val msg = ServerVehicleOverrideMsg.Auto(5)
|
||||
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
|
||||
|
||||
pkt mustEqual string2
|
||||
}
|
||||
}
|
||||
|
|
|
|||
498
common/src/test/scala/objects/AutoDriveControlsTest.scala
Normal file
498
common/src/test/scala/objects/AutoDriveControlsTest.scala
Normal file
|
|
@ -0,0 +1,498 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
package objects
|
||||
|
||||
import akka.actor.Props
|
||||
import akka.testkit.TestProbe
|
||||
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
|
||||
import net.psforever.objects.{Avatar, GlobalDefinitions, Player, Vehicle}
|
||||
import net.psforever.objects.serverobject.pad.process.{AutoDriveControls, VehicleSpawnControlGuided}
|
||||
import net.psforever.packet.game.PlanetSideGUID
|
||||
import net.psforever.types.{CharacterGender, PlanetSideEmpire, Vector3}
|
||||
import org.specs2.mutable.Specification
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class AutoDriveControlsTest extends Specification {
|
||||
"CancelEntry" should {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
def exampleTest(vehicle : Vehicle) : Boolean = { vehicle.Position == Vector3(1,1,1) }
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.CancelEarly(exampleTest)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Cancel
|
||||
setting.Data mustEqual None
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.CancelEarly(exampleTest)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Position mustEqual Vector3.Zero
|
||||
setting.Validate(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(1,1,1)
|
||||
setting.Validate(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.CancelEarly(exampleTest)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.CompletionTest(vehicle) mustEqual true //always true
|
||||
}
|
||||
}
|
||||
|
||||
"Climb" should {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mosquito)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Climb(10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Climb
|
||||
setting.Data mustEqual Some(10.5f)
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val vehicle_fury = Vehicle(GlobalDefinitions.fury)
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Climb(10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
setting.Validate(vehicle) mustEqual true //mosquito is a flying vehicle
|
||||
setting.Validate(vehicle_fury) mustEqual false
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Climb(10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Position mustEqual Vector3.Zero
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(0,0,10.5f)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
}
|
||||
|
||||
"Distance" should {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Distance(Vector3.Zero, 10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Wait
|
||||
setting.Data mustEqual None
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Distance(Vector3.Zero, 10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Velocity mustEqual None
|
||||
setting.Validate(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3.Zero
|
||||
setting.Validate(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3(1,0,0)
|
||||
setting.Validate(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Distance(Vector3.Zero, 10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Position = Vector3(0,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(10.5f,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(11,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
vehicle.Position = Vector3(0,11,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
vehicle.Position = Vector3(0,0,11)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(7.5f,7.5f,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
}
|
||||
|
||||
"DistanceFromHere" should {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.DistanceFromHere(10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Wait
|
||||
setting.Data mustEqual None
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.DistanceFromHere(10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Velocity mustEqual None
|
||||
setting.Validate(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3.Zero
|
||||
setting.Validate(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3(1,0,0)
|
||||
setting.Validate(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.DistanceFromHere(10.5f)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Position = Vector3(0,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(10.5f,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(11,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
vehicle.Position = Vector3(0,11,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
vehicle.Position = Vector3(0,0,11)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Position = Vector3(7.5f,7.5f,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
}
|
||||
|
||||
"Drive" should {
|
||||
val vehicle = Vehicle(GlobalDefinitions.fury)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Drive(3)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Drive
|
||||
setting.Data mustEqual Some(3)
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Drive(3)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Validate(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Drive(3)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
vehicle.Velocity mustEqual None
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
|
||||
vehicle.Velocity = Vector3.Zero
|
||||
vehicle.Velocity mustEqual Some(Vector3.Zero)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
|
||||
vehicle.Velocity = Vector3(1,0,0)
|
||||
vehicle.Velocity mustEqual Some(Vector3(1,0,0))
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
"FirstGear" should {
|
||||
val veh_def = GlobalDefinitions.mediumtransport
|
||||
val vehicle = Vehicle(veh_def)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Drive
|
||||
setting.Data mustEqual Some(0)
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Validate(vehicle) mustEqual true //always true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Velocity mustEqual None
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3.Zero
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3(1,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"data" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.FirstGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
setting.Data mustEqual Some(0)
|
||||
setting.Validate(vehicle)
|
||||
setting.Data mustEqual Some(veh_def.AutoPilotSpeed1)
|
||||
}
|
||||
}
|
||||
|
||||
"ForTime" should {
|
||||
val veh_def = GlobalDefinitions.mediumtransport
|
||||
val vehicle = Vehicle(veh_def)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.ForTime(1200L)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Wait
|
||||
setting.Data mustEqual None
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.ForTime(1200L)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Validate(vehicle) mustEqual true //always true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.ForTime(1200L)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
|
||||
Thread.sleep(1100)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
|
||||
Thread.sleep(200)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
}
|
||||
|
||||
"SecondGear" should {
|
||||
val veh_def = GlobalDefinitions.mediumtransport
|
||||
val vehicle = Vehicle(veh_def)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Drive
|
||||
setting.Data mustEqual Some(0)
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Validate(vehicle) mustEqual true //always true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Velocity mustEqual None
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3.Zero
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3(1,0,0)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"data" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.SecondGear()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
setting.Data mustEqual Some(0)
|
||||
setting.Validate(vehicle)
|
||||
setting.Data mustEqual Some(veh_def.AutoPilotSpeed2)
|
||||
}
|
||||
}
|
||||
|
||||
"Stop" should {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Stop()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Stop
|
||||
setting.Data mustEqual None
|
||||
setting.Delay mustEqual 200L
|
||||
}
|
||||
|
||||
"validate" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Stop()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Validate(vehicle) mustEqual true //always true
|
||||
}
|
||||
|
||||
"completion" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.Stop()
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.CompletionTest(vehicle) mustEqual true //always true
|
||||
}
|
||||
}
|
||||
|
||||
"TurnBy" should {
|
||||
"create" in {
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 23)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
setting.Type mustEqual AutoDriveControls.State.Turn
|
||||
setting.Data mustEqual Some(23)
|
||||
setting.Delay mustEqual 100L
|
||||
}
|
||||
|
||||
"validate (velocity)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 23)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Velocity mustEqual None
|
||||
setting.Validate(vehicle) mustEqual false
|
||||
vehicle.Velocity = Vector3(1,1,1)
|
||||
setting.Validate(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"validate (wheel direction = 15)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 15)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Velocity = Vector3(1,1,1)
|
||||
setting.Validate(vehicle) mustEqual false
|
||||
}
|
||||
|
||||
"completion (passing 35.5-up)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(35.5f, 25)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Orientation mustEqual Vector3.Zero
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Orientation = Vector3(0,0,34.5f)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Orientation = Vector3(0,0,35f)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Orientation = Vector3(0,0,36.0f)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
|
||||
"completion (passing 35.5 down)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
val config : AutoDriveControls.Configuration = AutoDriveControls.TurnBy(-35.5f, 25)
|
||||
val setting : AutoDriveControls.Setting = config.Create
|
||||
|
||||
vehicle.Orientation = Vector3(0,0,40f)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Orientation = Vector3(0,0,5f)
|
||||
setting.CompletionTest(vehicle) mustEqual false
|
||||
vehicle.Orientation = Vector3(0,0,4f)
|
||||
setting.CompletionTest(vehicle) mustEqual true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GuidedControlTest1 extends ActorTest {
|
||||
"VehicleSpawnControlGuided" should {
|
||||
"unguided" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
vehicle.GUID = PlanetSideGUID(1)
|
||||
val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0,0))
|
||||
driver.VehicleSeated = vehicle.GUID
|
||||
val sendTo = TestProbe()
|
||||
val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref)
|
||||
val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
|
||||
pad.GUID = PlanetSideGUID(1)
|
||||
pad.Railed = false //suppress certain events
|
||||
val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad")
|
||||
|
||||
guided ! VehicleSpawnControl.Process.StartGuided(order)
|
||||
val msg = sendTo.receiveOne(100 milliseconds)
|
||||
assert(msg.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GuidedControlTest2 extends ActorTest {
|
||||
"VehicleSpawnControlGuided" should {
|
||||
"guided (one)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
vehicle.GUID = PlanetSideGUID(1)
|
||||
vehicle.Velocity = Vector3(1,1,1)
|
||||
val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0,0))
|
||||
driver.VehicleSeated = vehicle.GUID
|
||||
val sendTo = TestProbe()
|
||||
val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref)
|
||||
val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
|
||||
pad.Railed = false //suppress certain events
|
||||
val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad")
|
||||
|
||||
pad.Guide = List(AutoDriveControls.FirstGear())
|
||||
guided ! VehicleSpawnControl.Process.StartGuided(order)
|
||||
val msg1 = sendTo.receiveOne(100 milliseconds)
|
||||
assert(msg1.isInstanceOf[VehicleSpawnControlGuided.GuidedControl])
|
||||
assert(msg1.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive)
|
||||
val msg2 = sendTo.receiveOne(200 milliseconds)
|
||||
assert(msg2.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GuidedControlTest3 extends ActorTest {
|
||||
"VehicleSpawnControlGuided" should {
|
||||
"guided (three)" in {
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
vehicle.GUID = PlanetSideGUID(1)
|
||||
vehicle.Velocity = Vector3(1,1,1)
|
||||
val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0,0))
|
||||
driver.VehicleSeated = vehicle.GUID
|
||||
val sendTo = TestProbe()
|
||||
val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref)
|
||||
val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
|
||||
pad.Railed = false //suppress certain events
|
||||
val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad")
|
||||
|
||||
pad.Guide = List(
|
||||
AutoDriveControls.FirstGear(),
|
||||
AutoDriveControls.ForTime(1000L),
|
||||
AutoDriveControls.SecondGear()
|
||||
)
|
||||
guided ! VehicleSpawnControl.Process.StartGuided(order)
|
||||
val msg1 = sendTo.receiveOne(100 milliseconds)
|
||||
assert(msg1.isInstanceOf[VehicleSpawnControlGuided.GuidedControl])
|
||||
assert(msg1.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive)
|
||||
val msg2 = sendTo.receiveOne(100 milliseconds)
|
||||
assert(msg2.isInstanceOf[VehicleSpawnControlGuided.GuidedControl])
|
||||
assert(msg2.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Wait)
|
||||
sendTo.expectNoMsg(1000 milliseconds)
|
||||
val msg3 = sendTo.receiveOne(100 milliseconds)
|
||||
assert(msg3.isInstanceOf[VehicleSpawnControlGuided.GuidedControl])
|
||||
assert(msg3.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive)
|
||||
val msg4 = sendTo.receiveOne(200 milliseconds)
|
||||
assert(msg4.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class GuidedControlTest4 extends ActorTest {
|
||||
"VehicleSpawnControlGuided" should {
|
||||
"fail validation test" in {
|
||||
def validationFailure(vehicle : Vehicle) : Boolean = false
|
||||
|
||||
val vehicle = Vehicle(GlobalDefinitions.mediumtransport)
|
||||
vehicle.GUID = PlanetSideGUID(1)
|
||||
vehicle.Velocity = Vector3(1,1,1)
|
||||
val driver = Player(Avatar("", PlanetSideEmpire.TR, CharacterGender.Male, 0,0))
|
||||
driver.VehicleSeated = vehicle.GUID
|
||||
val sendTo = TestProbe()
|
||||
val order = VehicleSpawnControl.Order(driver, vehicle, sendTo.ref)
|
||||
val pad = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
|
||||
pad.Railed = false //suppress certain events
|
||||
val guided = system.actorOf(Props(classOf[VehicleSpawnControlGuided], pad), "pad")
|
||||
|
||||
pad.Guide = List(
|
||||
AutoDriveControls.FirstGear(),
|
||||
AutoDriveControls.CancelEarly(validationFailure),
|
||||
AutoDriveControls.SecondGear()
|
||||
)
|
||||
guided ! VehicleSpawnControl.Process.StartGuided(order)
|
||||
val msg1 = sendTo.receiveOne(100 milliseconds)
|
||||
assert(msg1.isInstanceOf[VehicleSpawnControlGuided.GuidedControl])
|
||||
assert(msg1.asInstanceOf[VehicleSpawnControlGuided.GuidedControl].command == AutoDriveControls.State.Drive)
|
||||
val msg2 = sendTo.receiveOne(200 milliseconds)
|
||||
assert(msg2.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +85,7 @@ class VehicleSpawnControl2aTest extends ActorTest() {
|
|||
val probe1Msg3 = probe1.receiveOne(3 seconds)
|
||||
assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle])
|
||||
|
||||
val probe3Msg4 = probe3.receiveOne(200 milliseconds)
|
||||
val probe3Msg4 = probe3.receiveOne(1 seconds)
|
||||
assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
|
||||
|
||||
val probe1Msg4 = probe1.receiveOne(1 seconds)
|
||||
|
|
@ -93,20 +93,20 @@ class VehicleSpawnControl2aTest extends ActorTest() {
|
|||
val probe1Msg5 = probe1.receiveOne(4 seconds)
|
||||
assert(probe1Msg5.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
|
||||
|
||||
val probe1Msg6 = probe1.receiveOne(10 seconds)
|
||||
val probe1Msg6 = probe1.receiveOne(11 seconds)
|
||||
assert(probe1Msg6.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
|
||||
assert(probe1Msg6.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
|
||||
val probe2Msg2 = probe2.receiveOne(100 milliseconds)
|
||||
assert(probe2Msg2.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
|
||||
assert(probe2Msg2.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
|
||||
|
||||
//if we move the vehicle more than 10m away from the pad, we should receive a ResetSpawnPad, and a second ConcealPlayer message
|
||||
//if we move the vehicle more than 25m away from the pad, we should receive a ResetSpawnPad, and a second ConcealPlayer message
|
||||
//that means that the first order has cleared and the spawn pad is now working on the second order successfully
|
||||
vehicle.Position = Vector3(0,0,11)
|
||||
vehicle.Position = Vector3(11,0,0)
|
||||
player.VehicleSeated = None //since shared between orders, is necessary
|
||||
val probe3Msg5 = probe3.receiveOne(4 seconds)
|
||||
assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
|
||||
val probe3Msg6 = probe3.receiveOne(4 seconds)
|
||||
val probe3Msg6 = probe3.receiveOne(5 seconds)
|
||||
assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
|
||||
}
|
||||
}
|
||||
|
|
@ -147,15 +147,12 @@ class VehicleSpawnControl2bTest extends ActorTest() {
|
|||
val probe1Msg3 = probe1.receiveOne(3 seconds)
|
||||
assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle])
|
||||
|
||||
val probe3Msg4 = probe3.receiveOne(200 milliseconds)
|
||||
assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
|
||||
|
||||
val probe1Msg4 = probe1.receiveOne(1 seconds)
|
||||
assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideStart])
|
||||
val probe1Msg5 = probe1.receiveOne(4 seconds)
|
||||
assert(probe1Msg5.isInstanceOf[VehicleSpawnPad.ServerVehicleOverrideEnd])
|
||||
|
||||
val probe1Msg6 = probe1.receiveOne(10 seconds)
|
||||
val probe1Msg6 = probe1.receiveOne(11 seconds)
|
||||
assert(probe1Msg6.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
|
||||
assert(probe1Msg6.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
|
||||
val probe2Msg2 = probe2.receiveOne(100 milliseconds)
|
||||
|
|
@ -164,7 +161,7 @@ class VehicleSpawnControl2bTest extends ActorTest() {
|
|||
|
||||
//if we move the vehicle more than 10m away from the pad, we should receive a second ConcealPlayer message
|
||||
//that means that the first order has cleared and the spawn pad is now working on the second order successfully
|
||||
vehicle.Position = Vector3(0,0,11)
|
||||
vehicle.Position = Vector3(11,0,0)
|
||||
player.VehicleSeated = None //since shared between orders, is necessary
|
||||
val probe3Msg6 = probe3.receiveOne(4 seconds)
|
||||
assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
|
||||
|
|
@ -215,35 +212,35 @@ class VehicleSpawnControl4Test extends ActorTest() {
|
|||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl5aTest extends ActorTest() {
|
||||
"VehicleSpawnControl" should {
|
||||
"the vehicle is destroyed before being fully loaded; the vehicle is cleaned up" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
//we can recycle the vehicle and the player for each order
|
||||
val probe1 = new TestProbe(system, "first-order")
|
||||
val probe3 = new TestProbe(system, "zone-events")
|
||||
zone.VehicleEvents = probe3.ref
|
||||
//class VehicleSpawnControl5aTest extends ActorTest() {
|
||||
// "VehicleSpawnControl" should {
|
||||
// "the vehicle is destroyed before being fully loaded; the vehicle is cleaned up" in {
|
||||
// val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
// //we can recycle the vehicle and the player for each order
|
||||
// val probe1 = new TestProbe(system, "first-order")
|
||||
// val probe3 = new TestProbe(system, "zone-events")
|
||||
// zone.VehicleEvents = probe3.ref
|
||||
//
|
||||
// pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref)
|
||||
//
|
||||
// val probe3Msg1 = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
|
||||
//
|
||||
// val probe3Msg2 = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle])
|
||||
// vehicle.Health = 0 //problem
|
||||
//
|
||||
// val probe3Msg3 = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.DisposeVehicle])
|
||||
// val probe3Msg4 = probe3.receiveOne(100 milliseconds)
|
||||
// assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.RevealPlayer])
|
||||
// //note: the vehicle will not be unregistered by this logic alone
|
||||
// //since LoadVehicle should introduce it into the game world properly, it has to be handled properly
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref)
|
||||
|
||||
val probe3Msg1 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
|
||||
|
||||
val probe3Msg2 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle])
|
||||
vehicle.Health = 0 //problem
|
||||
|
||||
val probe3Msg3 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.DisposeVehicle])
|
||||
val probe3Msg4 = probe3.receiveOne(100 milliseconds)
|
||||
assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.RevealPlayer])
|
||||
//note: the vehicle will not be unregistered by this logic alone
|
||||
//since LoadVehicle should introduce it into the game world properly, it has to be handled properly
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl5bTest extends ActorTest() {
|
||||
class VehicleSpawnControl5Test extends ActorTest() {
|
||||
"VehicleSpawnControl" should {
|
||||
"player dies right after vehicle partially loads; the vehicle spawns and blocks the pad" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -266,91 +263,14 @@ class VehicleSpawnControl5bTest extends ActorTest() {
|
|||
val probe3Msg4 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
|
||||
|
||||
val probe1Msg = probe1.receiveOne(10 seconds)
|
||||
val probe1Msg = probe1.receiveOne(12 seconds)
|
||||
assert(probe1Msg.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
|
||||
assert(probe1Msg.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl6aTest extends ActorTest() {
|
||||
"VehicleSpawnControl" should {
|
||||
"the vehicle is destroyed while the player is sitting down; the vehicle is cleaned up" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
//we can recycle the vehicle and the player for each order
|
||||
val probe1 = new TestProbe(system, "first-order")
|
||||
val probe3 = new TestProbe(system, "zone-events")
|
||||
zone.VehicleEvents = probe3.ref
|
||||
|
||||
pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref)
|
||||
|
||||
val probe3Msg1 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
|
||||
|
||||
val probe3Msg2 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle])
|
||||
|
||||
val probe3Msg3 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails])
|
||||
|
||||
val probe1Msg1 = probe1.receiveOne(200 milliseconds)
|
||||
assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
|
||||
vehicle.Health = 0 //problem
|
||||
|
||||
val probe3Msg5 = probe3.receiveOne(4 seconds)
|
||||
assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
|
||||
val probe3Msg6 = probe3.receiveOne(100 milliseconds)
|
||||
assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.DisposeVehicle])
|
||||
val probe3Msg7 = probe3.receiveOne(100 milliseconds)
|
||||
assert(probe3Msg7.isInstanceOf[VehicleSpawnPad.RevealPlayer])
|
||||
//note: the vehicle will not be unregistered by this logic alone
|
||||
//since LoadVehicle should introduce it into the game world properly, it has to be handled properly
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO test was poor; attempting to check the "if(vehicle.Health ..." cases in VehicleSpawnControlSeatDriver
|
||||
//class VehicleSpawnControl6bTest extends ActorTest() {
|
||||
// "VehicleSpawnControl" should {
|
||||
// "player on wrong continent; the vehicle is then destroyed after being partially spawned, but is cleaned up" in {
|
||||
// val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
// //we can recycle the vehicle and the player for each order
|
||||
// val probe1 = new TestProbe(system, "first-order")
|
||||
// val probe3 = new TestProbe(system, "zone-events")
|
||||
// zone.VehicleEvents = probe3.ref
|
||||
//
|
||||
// pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref)
|
||||
//
|
||||
// val probe3Msg1 = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
|
||||
//
|
||||
// val probe3Msg2 = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle])
|
||||
//
|
||||
// val probe3Msg3 = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails])
|
||||
//
|
||||
// val probe1Msg1 = probe1.receiveOne(200 milliseconds)
|
||||
// assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
|
||||
// player.Continent = "problem" //problem 1
|
||||
//
|
||||
// vehicle.Health = 0 //problem 2
|
||||
// val probe3Msg3b = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg3b.isInstanceOf[VehicleSpawnPad.DetachFromRails])
|
||||
//
|
||||
// val probe3Msg4 = probe3.receiveOne(3 seconds)
|
||||
// assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
|
||||
// val probe3Msg5 = probe3.receiveOne(1 seconds)
|
||||
// assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.DisposeVehicle])
|
||||
// val probe3Msg6 = probe3.receiveOne(1 seconds)
|
||||
// assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.RevealPlayer])
|
||||
// //note: the vehicle will not be unregistered by this logic alone
|
||||
// //since LoadVehicle should introduce it into the game world properly, it has to be handled properly
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
class VehicleSpawnControl6cTest extends ActorTest() {
|
||||
class VehicleSpawnControl6Test extends ActorTest() {
|
||||
"VehicleSpawnControl" should {
|
||||
"the player can not sit in vehicle; vehicle spawns and blocks the pad" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -380,57 +300,14 @@ class VehicleSpawnControl6cTest extends ActorTest() {
|
|||
val probe3Msg5 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
|
||||
|
||||
val probe1Msg2 = probe1.receiveOne(10 seconds)
|
||||
val probe1Msg2 = probe1.receiveOne(12 seconds)
|
||||
assert(probe1Msg2.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
|
||||
assert(probe1Msg2.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl7aTest extends ActorTest() {
|
||||
"VehicleSpawnControl" should {
|
||||
"the vehicle is destroyed while attached to the rails; it is cleaned up" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
//we can recycle the vehicle and the player for each order
|
||||
val probe1 = new TestProbe(system, "first-order")
|
||||
val probe3 = new TestProbe(system, "zone-events")
|
||||
zone.VehicleEvents = probe3.ref
|
||||
|
||||
pad.Actor.tell(VehicleSpawnPad.VehicleOrder(player, vehicle), probe1.ref)
|
||||
|
||||
val probe3Msg1 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg1.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
|
||||
|
||||
val probe3Msg2 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg2.isInstanceOf[VehicleSpawnPad.LoadVehicle])
|
||||
|
||||
val probe3Msg3 = probe3.receiveOne(3 seconds)
|
||||
assert(probe3Msg3.isInstanceOf[VehicleSpawnPad.AttachToRails])
|
||||
|
||||
val probe1Msg1 = probe1.receiveOne(200 milliseconds)
|
||||
assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
|
||||
val probe1Msg2 = probe1.receiveOne(200 milliseconds)
|
||||
assert(probe1Msg2.isInstanceOf[Mountable.MountMessages])
|
||||
val probe1Msg2Contents = probe1Msg2.asInstanceOf[Mountable.MountMessages]
|
||||
assert(probe1Msg2Contents.response.isInstanceOf[Mountable.CanMount])
|
||||
val probe1Msg3 = probe1.receiveOne(3 seconds)
|
||||
assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle])
|
||||
vehicle.Health = 0 //problem
|
||||
|
||||
val probe3Msg4 = probe3.receiveOne(200 milliseconds)
|
||||
assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
|
||||
val probe3Msg5 = probe3.receiveOne(200 milliseconds)
|
||||
assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
|
||||
|
||||
probe1.receiveOne(200 milliseconds) //Mountable.MountMessage
|
||||
val probe1Msg4 = probe1.receiveOne(10 seconds)
|
||||
assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
|
||||
assert(probe1Msg4.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class VehicleSpawnControl7bTest extends ActorTest() {
|
||||
class VehicleSpawnControl7Test extends ActorTest() {
|
||||
"VehicleSpawnControl" should {
|
||||
"player dies after getting in driver seat; the vehicle blocks the pad" in {
|
||||
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
|
||||
|
|
@ -465,7 +342,7 @@ class VehicleSpawnControl7bTest extends ActorTest() {
|
|||
val probe3Msg5 = probe3.receiveOne(100 milliseconds)
|
||||
assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
|
||||
|
||||
val probe1Msg4 = probe1.receiveOne(10 seconds)
|
||||
val probe1Msg4 = probe1.receiveOne(12 seconds)
|
||||
assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
|
||||
assert(probe1Msg4.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,14 +126,15 @@ object Maps {
|
|||
LocalObject(2323, Door.Constructor) //spawn tube door
|
||||
LocalObject(2324, Door.Constructor) //spawn tube door
|
||||
LocalObject(2419, Terminal.Constructor(ground_vehicle_terminal))
|
||||
LocalObject(500,
|
||||
LocalObject(1479,
|
||||
VehicleSpawnPad.Constructor(Vector3(3962.0f, 4334.0f, 267.75f), Vector3(0f, 0f, 180.0f))
|
||||
) //TODO guid not correct
|
||||
)
|
||||
LocalObject(224, Terminal.Constructor(dropship_vehicle_terminal))
|
||||
LocalObject(501,
|
||||
VehicleSpawnPad.Constructor(Vector3(4012.3594f, 4364.8047f, 271.90625f), Vector3(0f, 0f, 180.0f))
|
||||
) //TODO guid not correct
|
||||
LocalObject(223,
|
||||
VehicleSpawnPad.Constructor(Vector3(4012.3594f, 4364.8047f, 271.90625f), Vector3(0f, 0f, 0f))
|
||||
)
|
||||
ObjectToBuilding(222, 2)
|
||||
ObjectToBuilding(223, 2)
|
||||
ObjectToBuilding(224, 2)
|
||||
ObjectToBuilding(370, 2)
|
||||
ObjectToBuilding(371, 2)
|
||||
|
|
@ -204,6 +205,7 @@ object Maps {
|
|||
ObjectToBuilding(1188, 2)
|
||||
ObjectToBuilding(1492, 2)
|
||||
ObjectToBuilding(1494, 2)
|
||||
ObjectToBuilding(1479, 2)
|
||||
ObjectToBuilding(1564, 2)
|
||||
ObjectToBuilding(1568, 2)
|
||||
ObjectToBuilding(1569, 2)
|
||||
|
|
@ -228,8 +230,6 @@ object Maps {
|
|||
ObjectToBuilding(2323, 2)
|
||||
ObjectToBuilding(2324, 2)
|
||||
ObjectToBuilding(2419, 2)
|
||||
ObjectToBuilding(500, 2)
|
||||
ObjectToBuilding(501, 2)
|
||||
DoorToLock(375, 863)
|
||||
DoorToLock(376, 860)
|
||||
DoorToLock(384, 866)
|
||||
|
|
@ -244,8 +244,8 @@ object Maps {
|
|||
DoorToLock(638, 882)
|
||||
DoorToLock(642, 884)
|
||||
DoorToLock(715, 751)
|
||||
TerminalToSpawnPad(224, 501)
|
||||
TerminalToSpawnPad(2419, 500)
|
||||
TerminalToSpawnPad(224, 223)
|
||||
TerminalToSpawnPad(2419, 1479)
|
||||
}
|
||||
|
||||
def Building38() : Unit = {
|
||||
|
|
@ -404,20 +404,23 @@ object Maps {
|
|||
Building29()
|
||||
Building42()
|
||||
Building51()
|
||||
Building52()
|
||||
Building77()
|
||||
Building79()
|
||||
Building81()
|
||||
|
||||
def Building1() : Unit = {
|
||||
//warpgate?
|
||||
LocalBuilding(1, FoundationBuilder(WarpGate.Structure))
|
||||
}
|
||||
|
||||
// LocalBuilding(2, FoundationBuilder(WarpGate.Structure)) //TODO might be wrong?
|
||||
|
||||
def Building3() : Unit = {
|
||||
//warpgate?
|
||||
LocalBuilding(3, FoundationBuilder(WarpGate.Structure))
|
||||
}
|
||||
|
||||
// LocalBuilding(2, FoundationBuilder(WarpGate.Structure)) //TODO might be wrong?
|
||||
|
||||
// LocalObject(520, ImplantTerminalMech.Constructor) //Hart B
|
||||
// LocalObject(1081, Terminal.Constructor(implant_terminal_interface)) //tube 520
|
||||
// TerminalToInterface(520, 1081)
|
||||
|
|
@ -623,17 +626,53 @@ object Maps {
|
|||
TerminalToSpawnPad(304, 292)
|
||||
}
|
||||
|
||||
def Building52() : Unit = {
|
||||
//air terminal southwest of HART C
|
||||
LocalBuilding(52, FoundationBuilder(Building.Structure(StructureType.Platform)))
|
||||
LocalObject(305, Terminal.Constructor(dropship_vehicle_terminal))
|
||||
LocalObject(293,
|
||||
VehicleSpawnPad.Constructor(Vector3(3575.0781f, 2654.9766f, 92.296875f), Vector3(0f, 0f, 225.0f))
|
||||
)
|
||||
ObjectToBuilding(305, 52)
|
||||
ObjectToBuilding(293, 52)
|
||||
TerminalToSpawnPad(305, 293)
|
||||
}
|
||||
|
||||
def Building77() : Unit = {
|
||||
//ground terminal west of HART C
|
||||
LocalBuilding(77, FoundationBuilder(Building.Structure(StructureType.Platform)))
|
||||
LocalObject(1063, Terminal.Constructor(ground_vehicle_terminal))
|
||||
LocalObject(706,
|
||||
VehicleSpawnPad.Constructor(Vector3(3506.0f, 2820.0f, 92.0f), Vector3(0f, 0f, 270.0f))
|
||||
VehicleSpawnPad.Constructor(Vector3(3506.0f, 2820.0f, 92.0625f), Vector3(0f, 0f, 270.0f))
|
||||
)
|
||||
ObjectToBuilding(1063, 77)
|
||||
ObjectToBuilding(706, 77)
|
||||
TerminalToSpawnPad(1063, 706)
|
||||
}
|
||||
|
||||
def Building79() : Unit = {
|
||||
//ground terminal south of HART C
|
||||
LocalBuilding(79, FoundationBuilder(Building.Structure(StructureType.Platform)))
|
||||
LocalObject(1065, Terminal.Constructor(ground_vehicle_terminal))
|
||||
LocalObject(710,
|
||||
VehicleSpawnPad.Constructor(Vector3(3659.836f, 2589.875f, 92.0625f), Vector3(0f, 0f, 180.0f))
|
||||
)
|
||||
ObjectToBuilding(1065, 79)
|
||||
ObjectToBuilding(710, 79)
|
||||
TerminalToSpawnPad(1065, 710)
|
||||
}
|
||||
|
||||
def Building81() : Unit = {
|
||||
//ground terminal south of HART C
|
||||
LocalBuilding(81, FoundationBuilder(Building.Structure(StructureType.Platform)))
|
||||
LocalObject(1067, Terminal.Constructor(ground_vehicle_terminal))
|
||||
LocalObject(712,
|
||||
VehicleSpawnPad.Constructor(Vector3(3659.836f, 2589.875f, 92.0625f), Vector3(0f, 0f, 270.0f))
|
||||
)
|
||||
ObjectToBuilding(1067, 81)
|
||||
ObjectToBuilding(712, 81)
|
||||
TerminalToSpawnPad(1067, 712)
|
||||
}
|
||||
}
|
||||
|
||||
val map14 = new ZoneMap("map14")
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import net.psforever.objects.serverobject.locks.IFFLock
|
|||
import net.psforever.objects.serverobject.mblocker.Locker
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, ProximityTerminal, Terminal}
|
||||
import net.psforever.objects.serverobject.pad.process.{AutoDriveControls, VehicleSpawnControlGuided}
|
||||
import net.psforever.objects.serverobject.terminals.{MatrixTerminalDefinition, Terminal}
|
||||
import net.psforever.objects.serverobject.terminals.Terminal.TerminalMessage
|
||||
import net.psforever.objects.vehicles.{AccessPermissionGroup, Utility, VehicleLockState}
|
||||
import net.psforever.objects.serverobject.structures.{Building, StructureType, WarpGate}
|
||||
|
|
@ -478,6 +480,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
|
||||
case VehicleResponse.RevealPlayer(player_guid) =>
|
||||
//TODO any action will cause the player to appear after the effects of ConcealPlayer
|
||||
if(player.GUID == player_guid) {
|
||||
sendResponse(ChatMsg(ChatMessageType.CMT_OPEN, true, "", "You are in a strange situation.", None))
|
||||
KillPlayer(player)
|
||||
}
|
||||
|
||||
case VehicleResponse.SeatPermissions(vehicle_guid, seat_group, permission) =>
|
||||
if(tplayer_guid != guid) {
|
||||
|
|
@ -637,6 +643,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
if(player_guid == player.GUID) {
|
||||
//disembarking self
|
||||
log.info(s"DismountVehicleMsg: $player_guid dismounts $obj @ $seat_num")
|
||||
TotalDriverVehicleControl(obj)
|
||||
sendResponse(DismountVehicleMsg(player_guid, seat_num, false))
|
||||
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.DismountVehicle(player_guid, seat_num, false))
|
||||
UnAccessContents(obj)
|
||||
|
|
@ -1044,11 +1051,32 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
if(vehicle.Seats(0).isOccupied) {
|
||||
sendResponse(ObjectDetachMessage(pad.GUID, vehicle.GUID, pad.Position + Vector3(0, 0, 0.5f), 0, 0, pad.Orientation.z))
|
||||
}
|
||||
sendResponse(ServerVehicleOverrideMsg.Lock(GlobalDefinitions.isFlightVehicle(vdef):Int, vdef.AutoPilotSpeed1))
|
||||
ServerVehicleOverride(vehicle, vdef.AutoPilotSpeed1, GlobalDefinitions.isFlightVehicle(vdef):Int)
|
||||
|
||||
case VehicleSpawnControlGuided.GuidedControl(cmd, vehicle, data) =>
|
||||
cmd match {
|
||||
case AutoDriveControls.State.Drive =>
|
||||
val speed : Int = data.getOrElse({ vehicle.Definition.AutoPilotSpeed1 }).asInstanceOf[Int]
|
||||
ServerVehicleOverride(vehicle, speed)
|
||||
|
||||
case AutoDriveControls.State.Climb =>
|
||||
ServerVehicleOverride(vehicle, vehicle.Controlled.getOrElse(0), GlobalDefinitions.isFlightVehicle(vehicle.Definition):Int)
|
||||
|
||||
case AutoDriveControls.State.Turn =>
|
||||
//TODO how to turn hovering/flying vehicle?
|
||||
val direction = data.getOrElse(15).asInstanceOf[Int]
|
||||
sendResponse(VehicleStateMessage(vehicle.GUID, 0, vehicle.Position, vehicle.Orientation, vehicle.Velocity, None, 0, 0, direction, false, false))
|
||||
|
||||
|
||||
case AutoDriveControls.State.Stop =>
|
||||
ServerVehicleOverride(vehicle, 0)
|
||||
|
||||
case _ => ;
|
||||
}
|
||||
|
||||
case VehicleSpawnPad.ServerVehicleOverrideEnd(vehicle, pad) =>
|
||||
sendResponse(GenericObjectActionMessage(pad.GUID, 92)) //reset spawn pad
|
||||
sendResponse(ServerVehicleOverrideMsg.Auto(vehicle.Definition.AutoPilotSpeed2))
|
||||
DriverVehicleControl(vehicle, vehicle.Definition.AutoPilotSpeed2)
|
||||
|
||||
case VehicleSpawnPad.PeriodicReminder(cause, data) =>
|
||||
val msg : String = (cause match {
|
||||
|
|
@ -1557,7 +1585,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
case _ =>
|
||||
log.warn(s"VehicleState: no vehicle $vehicle_guid found in zone")
|
||||
}
|
||||
//log.info("VehicleState: " + msg)
|
||||
//log.info(s"VehicleState: $msg")
|
||||
|
||||
case msg @ VehicleSubStateMessage(vehicle_guid, player_guid, vehicle_pos, vehicle_ang, vel, unk1, unk2) =>
|
||||
//log.info(s"VehicleSubState: $vehicle_guid, $player_guid, $vehicle_pos, $vehicle_ang, $vel, $unk1, $unk2")
|
||||
|
|
@ -3511,6 +3539,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
sendResponse(AvatarDeadStateMessage(DeadState.Dead, respawnTimer, respawnTimer, pos, player.Faction, true))
|
||||
if(tplayer.VehicleSeated.nonEmpty) {
|
||||
//make player invisible (if not, the cadaver sticks out the side in a seated position)
|
||||
TotalDriverVehicleControl(continent.GUID(tplayer.VehicleSeated.get).get.asInstanceOf[Vehicle])
|
||||
sendResponse(PlanetsideAttributeMessage(player_guid, 29, 1))
|
||||
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.PlanetsideAttribute(player_guid, 29, 1))
|
||||
}
|
||||
|
|
@ -3867,6 +3896,25 @@ class WorldSessionActor extends Actor with MDCContextAware {
|
|||
tplayer.Armor == tplayer.MaxArmor
|
||||
}
|
||||
|
||||
def ServerVehicleOverride(vehicle : Vehicle, speed : Int = 0, flight : Int = 0) : Unit = {
|
||||
vehicle.Controlled = Some(speed)
|
||||
sendResponse(ServerVehicleOverrideMsg(true, true, false, false, flight, 0, speed, Some(0)))
|
||||
}
|
||||
|
||||
def DriverVehicleControl(vehicle : Vehicle, speed : Int = 0, flight : Int = 0) : Unit = {
|
||||
if(vehicle.Controlled.nonEmpty) {
|
||||
vehicle.Controlled = None
|
||||
sendResponse(ServerVehicleOverrideMsg(false, false, false, true, flight, 0, speed, None))
|
||||
}
|
||||
}
|
||||
|
||||
def TotalDriverVehicleControl(vehicle : Vehicle) : Unit = {
|
||||
if(vehicle.Controlled.nonEmpty) {
|
||||
vehicle.Controlled = None
|
||||
sendResponse(ServerVehicleOverrideMsg(false, false, false, false, 0, 0, 0, None))
|
||||
}
|
||||
}
|
||||
|
||||
def failWithError(error : String) = {
|
||||
log.error(error)
|
||||
sendResponse(ConnectionClose())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright (c) 2017 PSForever
|
||||
import akka.actor.ActorContext
|
||||
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
|
||||
import net.psforever.objects.serverobject.pad.process._
|
||||
import net.psforever.objects.zones.Zone
|
||||
import net.psforever.types.PlanetSideEmpire
|
||||
|
||||
|
|
@ -51,6 +52,7 @@ object Zones {
|
|||
Buildings.values.foreach { _.Faction = PlanetSideEmpire.VS }
|
||||
Building(29).get.Faction = PlanetSideEmpire.NC //South Villa Gun Tower
|
||||
GUID(293).get.asInstanceOf[VehicleSpawnPad].Railed = false //building 52
|
||||
GUID(706).get.asInstanceOf[VehicleSpawnPad].Guide = List(AutoDriveControls.DistanceFromHere(50f)) //building 77
|
||||
GUID(710).get.asInstanceOf[VehicleSpawnPad].Railed = false //building 79
|
||||
GUID(712).get.asInstanceOf[VehicleSpawnPad].Railed = false //building 81
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue