Merge pull request #180 from Fate-JH/all-zones

All Zones
This commit is contained in:
Fate-JH 2017-12-28 19:04:52 -05:00 committed by GitHub
commit abbd5c35ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 417 additions and 337 deletions

View file

@ -0,0 +1,62 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject
import akka.actor.ActorContext
import net.psforever.objects.guid.NumberPoolHub
/**
* Customizable native entity instantiation logic at the `ZoneMap` level.
* Produces environmental constants such as `Terminal` objects and `Door` objects.<br>
* <br>
* `ZoneMap` is the expected position where this class is defined.
* Within `Zone.Init` is where this class is expected to be fully executed.
* The former is a blueprint which provides as many emitted entities based on how many `Zone` objects utilize it.
* `constructor` is required to have the form `(Int, ActorContext) => A` by the point where it executes
* due to invocation of the `Build` method.
* For that reason, it must exist in an `Actor` which has an `ActorContext` to lend, hence the `Zone`'s `Actor`.
* Furthermore, the requirement of a `NumberPoolHub` means the region is accessible to and defined by
* a closed number space, which is also the `Zone`.
* It utilizes those qualities of the enclosing region to construct the entity within that region.<br>
* <br>
* Example: `ServerObjectBuilder(n, function)`
* Example: `new ServerBuilderObject[A](n, function)`, where `function` is a `(Int,Context)=>A`
* @see `ZoneMap`
* @see `Zone.Init`
* @param id the unique id that will be assigned to this entity
* @param constructor the logic that initializes the emitted entity
* @tparam A any object that extends from PlanetSideServerObject that will be produced by this class;
* can be inferred from the output of `constructor`
*/
class ServerObjectBuilder[A <: PlanetSideServerObject](private val id : Int,
private val constructor : (Int, ActorContext) => A
) {
/**
* Instantiate and configure the given server object.
* Specific configuration should have been handled by curried parameters into `constructor`, i.e.,
* `constructor(foo : Bar) => constructor(Int, ActorContext) => A`.
* The main activity performed locally registers the created object to the provided number space.
* @param context a context to allow the object to properly set up `ActorSystem` functionality;
* defaults to `null`
* @param guid the local globally unique identifier system to complete the process of object introduction;
* defaults to `null`
* @return the object that was created and integrated into the `Zone`
*/
def Build(implicit context : ActorContext = null, guid : NumberPoolHub = null) : A = {
val obj : A = constructor(id, context)
guid.register(obj, id)
obj
}
}
object ServerObjectBuilder {
/**
* Overloaded constructor.
* @param id the unqiue id that will be assigned to this entity
* @param constructor the logic that initializes the emitted entity
* @tparam A any object that extends from PlanetSideServerObject that will be produced by this class
* @return a `ServerObjectBuilder` object
*/
def apply[A <: PlanetSideServerObject](id : Int, constructor : (Int, ActorContext) => A) : ServerObjectBuilder[A] = {
new ServerObjectBuilder[A](id, constructor)
}
}

View file

@ -1,34 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.builders
import akka.actor.Props
import net.psforever.objects.serverobject.doors.{Door, DoorControl, DoorDefinition}
/**
* Wrapper `Class` designed to instantiate a `Door` server object.
* @param ddef a `DoorDefinition` object, indicating the specific functionality of the resulting `Door`
* @param id the globally unique identifier to which this `Door` will be registered
*/
class DoorObjectBuilder(private val ddef : DoorDefinition, private val id : Int) extends ServerObjectBuilder[Door] {
import akka.actor.ActorContext
import net.psforever.objects.guid.NumberPoolHub
def Build(implicit context : ActorContext, guid : NumberPoolHub) : Door = {
val obj = Door(ddef)
guid.register(obj, id) //non-Actor GUID registration
obj.Actor = context.actorOf(Props(classOf[DoorControl], obj), s"${ddef.Name}_${obj.GUID.guid}")
obj
}
}
object DoorObjectBuilder {
/**
* Overloaded constructor for a `DoorObjectBuilder`.
* @param ddef a `DoorDefinition` object
* @param id a globally unique identifier
* @return a `DoorObjectBuilder` object
*/
def apply(ddef : DoorDefinition, id : Int) : DoorObjectBuilder = {
new DoorObjectBuilder(ddef, id)
}
}

View file

@ -1,34 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.builders
import akka.actor.Props
import net.psforever.objects.serverobject.locks.{IFFLock, IFFLockControl, IFFLockDefinition}
/**
* Wrapper `Class` designed to instantiate a door lock server object that is sensitive to user faction affiliation.
* @param idef a `IFFLockDefinition` object, indicating the specific functionality
* @param id the globally unique identifier to which this `IFFLock` will be registered
*/
class IFFLockObjectBuilder(private val idef : IFFLockDefinition, private val id : Int) extends ServerObjectBuilder[IFFLock] {
import akka.actor.ActorContext
import net.psforever.objects.guid.NumberPoolHub
def Build(implicit context : ActorContext, guid : NumberPoolHub) : IFFLock = {
val obj = IFFLock(idef)
guid.register(obj, id) //non-Actor GUID registration
obj.Actor = context.actorOf(Props(classOf[IFFLockControl], obj), s"${idef.Name}_${obj.GUID.guid}")
obj
}
}
object IFFLockObjectBuilder {
/**
* Overloaded constructor for a `IFFLockObjectBuilder`.
* @param idef an `IFFLock` object
* @param id a globally unique identifier
* @return an `IFFLockObjectBuilder` object
*/
def apply(idef : IFFLockDefinition, id : Int) : IFFLockObjectBuilder = {
new IFFLockObjectBuilder(idef, id)
}
}

View file

@ -1,34 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.builders
import akka.actor.Props
import net.psforever.objects.serverobject.implantmech.{ImplantTerminalMech, ImplantTerminalMechControl, ImplantTerminalMechDefinition}
/**
* Wrapper `Class` designed to instantiate a `ImplantTerminalMech` server object.
* @param idef a `ImplantTerminalMechDefinition` object, indicating the specific functionality of the resulting `Door`
* @param id the globally unique identifier to which this "tube" will be registered
*/
class ImplantTerminalMechObjectBuilder(private val idef : ImplantTerminalMechDefinition, private val id : Int) extends ServerObjectBuilder[ImplantTerminalMech] {
import akka.actor.ActorContext
import net.psforever.objects.guid.NumberPoolHub
def Build(implicit context : ActorContext, guid : NumberPoolHub) : ImplantTerminalMech = {
val obj = ImplantTerminalMech(idef)
guid.register(obj, id) //non-Actor GUID registration
obj.Actor = context.actorOf(Props(classOf[ImplantTerminalMechControl], obj), s"${idef.Name}_${obj.GUID.guid}")
obj
}
}
object ImplantTerminalMechObjectBuilder {
/**
* Overloaded constructor for a `DoorObjectBuilder`.
* @param idef a `DoorDefinition` object
* @param id a globally unique identifier
* @return a `DoorObjectBuilder` object
*/
def apply(idef : ImplantTerminalMechDefinition, id : Int) : ImplantTerminalMechObjectBuilder = {
new ImplantTerminalMechObjectBuilder(idef, id)
}
}

View file

@ -1,29 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.builders
import akka.actor.ActorContext
import net.psforever.objects.PlanetSideGameObject
import net.psforever.objects.guid.NumberPoolHub
/**
* Wrapper `Trait` designed to be extended to implement custom object instantiation logic at the `ZoneMap` level.
* @tparam A any object that extends from PlanetSideGameObject
* @see `Zone.Init`
*/
//TODO can we changed PlanetSideGameObject -> PlanetSideServerObject?
trait ServerObjectBuilder[A <: PlanetSideGameObject] {
/**
* Instantiate and configure the given server object
* (at a later time compared to the construction of the builder class).<br>
* <br>
* Externally, it expects a `context` to properly integrate within an `ActorSystem`
* and is provided with a source for globally unique identifiers to integrate into the `Zone`.
* Neither is required of the `return` type, however.
* @param context a context to allow the object to properly set up `ActorSystem` functionality;
* defaults to `null`
* @param guid the local globally unique identifier system to complete the process of object introduction;
* defaults to `null`
* @return the object that was created and integrated into the `Zone`
*/
def Build(implicit context : ActorContext = null, guid : NumberPoolHub = null) : A
}

View file

@ -1,34 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.builders
import akka.actor.Props
import net.psforever.objects.serverobject.terminals.{Terminal, TerminalControl, TerminalDefinition}
/**
* Wrapper `Class` designed to instantiate a `Terminal` server object.
* @param tdef a `TerminalDefinition` object, indicating the specific functionality of the resulting `Terminal`
* @param id the globally unique identifier to which this `Terminal` will be registered
*/
class TerminalObjectBuilder(private val tdef : TerminalDefinition, private val id : Int) extends ServerObjectBuilder[Terminal] {
import akka.actor.ActorContext
import net.psforever.objects.guid.NumberPoolHub
def Build(implicit context : ActorContext, guid : NumberPoolHub) : Terminal = {
val obj = Terminal(tdef)
guid.register(obj, id) //non-Actor GUID registration
obj.Actor = context.actorOf(Props(classOf[TerminalControl], obj), s"${tdef.Name}_${obj.GUID.guid}")
obj
}
}
object TerminalObjectBuilder {
/**
* Overloaded constructor for a `TerminalObjectBuilder`.
* @param tdef a `TerminalDefinition` object
* @param id a globally unique identifier
* @return a `TerminalObjectBuilder` object
*/
def apply(tdef : TerminalDefinition, id : Int) : TerminalObjectBuilder = {
new TerminalObjectBuilder(tdef, id)
}
}

View file

@ -1,35 +0,0 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.serverobject.builders
import akka.actor.Props
import net.psforever.objects.definition.ObjectDefinition
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
/**
* Wrapper `Class` designed to instantiate a `VehicleSpawnPad` server object.
* @param spdef an `ObjectDefinition` object ...
* @param id the globally unique identifier to which this `VehicleSpawnPad` will be registered
*/
class VehicleSpawnPadObjectBuilder(private val spdef : ObjectDefinition, private val id : Int) extends ServerObjectBuilder[VehicleSpawnPad] {
import akka.actor.ActorContext
import net.psforever.objects.guid.NumberPoolHub
def Build(implicit context : ActorContext, guid : NumberPoolHub) : VehicleSpawnPad = {
val obj = VehicleSpawnPad(spdef)
guid.register(obj, id) //non-Actor GUID registration
obj.Actor = context.actorOf(Props(classOf[VehicleSpawnControl], obj), s"${spdef.Name}_${obj.GUID.guid}")
obj
}
}
object VehicleSpawnPadObjectBuilder {
/**
* Overloaded constructor for a `DoorObjectBuilder`.
* @param spdef an `ObjectDefinition` object
* @param id a globally unique identifier
* @return a `VehicleSpawnPadObjectBuilder` object
*/
def apply(spdef : ObjectDefinition, id : Int) : VehicleSpawnPadObjectBuilder = {
new VehicleSpawnPadObjectBuilder(spdef, id)
}
}

View file

@ -76,4 +76,20 @@ object Door {
def apply(tdef : DoorDefinition) : Door = {
new Door(tdef)
}
import akka.actor.ActorContext
/**
* Instantiate an configure a `Door` object
* @param id the unique id that will be assigned to this entity
* @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `Door` object
*/
def Constructor(id : Int, context : ActorContext) : Door = {
import akka.actor.Props
import net.psforever.objects.GlobalDefinitions
val obj = Door(GlobalDefinitions.door)
obj.Actor = context.actorOf(Props(classOf[DoorControl], obj), s"${GlobalDefinitions.door.Name}_$id")
obj
}
}

View file

@ -36,7 +36,27 @@ class ImplantTerminalMech(private val idef : ImplantTerminalMechDefinition) exte
}
object ImplantTerminalMech {
/**
* Overloaded constructor.
* @param idef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
*/
def apply(idef : ImplantTerminalMechDefinition) : ImplantTerminalMech = {
new ImplantTerminalMech(idef)
}
import akka.actor.ActorContext
/**
* Instantiate an configure a `ImplantTerminalMech` object
* @param id the unique id that will be assigned to this entity
* @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `ImplantTerminalMech` object
*/
def Constructor(id : Int, context : ActorContext) : ImplantTerminalMech = {
import akka.actor.Props
import net.psforever.objects.GlobalDefinitions
val obj = ImplantTerminalMech(GlobalDefinitions.implant_terminal_mech)
obj.Actor = context.actorOf(Props(classOf[ImplantTerminalMechControl], obj), s"${GlobalDefinitions.implant_terminal_mech.Name}_$id")
obj
}
}

View file

@ -63,4 +63,20 @@ object IFFLock {
def apply(idef : IFFLockDefinition) : IFFLock = {
new IFFLock(idef)
}
import akka.actor.ActorContext
/**
* Instantiate an configure a `IFFLock` object
* @param id the unique id that will be assigned to this entity
* @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `IFFLock` object
*/
def Constructor(id : Int, context : ActorContext) : IFFLock = {
import akka.actor.Props
import net.psforever.objects.GlobalDefinitions
val obj = IFFLock(GlobalDefinitions.lock_external)
obj.Actor = context.actorOf(Props(classOf[IFFLockControl], obj), s"${GlobalDefinitions.lock_external.Name}_$id")
obj
}
}

View file

@ -86,4 +86,26 @@ object VehicleSpawnPad {
def apply(spDef : ObjectDefinition) : VehicleSpawnPad = {
new VehicleSpawnPad(spDef)
}
import akka.actor.ActorContext
import net.psforever.types.Vector3
/**
* Instantiate an configure a `VehicleSpawnPad` object
* @param pos the position (used to determine spawn point)
* @param orient the orientation (used to indicate spawn direction)
* @param id the unique id that will be assigned to this entity
* @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `VehicleSpawnPad` object
*/
def Constructor(pos : Vector3, orient : Vector3)(id : Int, context : ActorContext) : VehicleSpawnPad = {
import akka.actor.Props
import net.psforever.objects.GlobalDefinitions
val obj = VehicleSpawnPad(GlobalDefinitions.spawn_pad)
obj.Position = pos
obj.Orientation = orient
obj.Actor = context.actorOf(Props(classOf[VehicleSpawnControl], obj), s"${GlobalDefinitions.spawn_pad.Name}_$id")
obj
}
}

View file

@ -3,11 +3,9 @@ package net.psforever.objects.serverobject.terminals
import net.psforever.objects.Player
import net.psforever.objects.definition.ImplantDefinition
import net.psforever.objects.equipment.Equipment
import net.psforever.objects.inventory.InventoryItem
import net.psforever.objects.serverobject.PlanetSideServerObject
import net.psforever.packet.game.{ItemTransactionMessage, PlanetSideGUID}
import net.psforever.types.{ExoSuitType, TransactionType, Vector3}
import net.psforever.types.{TransactionType, Vector3}
/**
* A structure-owned server object that is a "terminal" that can be accessed for amenities and services.
@ -113,6 +111,8 @@ object Terminal {
* A result of a processed request.
*/
final case class NoDeal() extends Exchange
import net.psforever.types.ExoSuitType
/**
* The `Player` exo-suit will be changed to the prescribed one.
* The subtype will be important if the user is swapping to an `ExoSuitType.MAX` exo-suit.
@ -121,6 +121,8 @@ object Terminal {
* @param subtype the exo-suit subtype, if any
*/
final case class BuyExosuit(exosuit : ExoSuitType.Value, subtype : Int = 0) extends Exchange
import net.psforever.objects.equipment.Equipment
/**
* A single piece of `Equipment` has been selected and will be given to the `Player`.
* The `Player` must decide what to do with it once it is in their control.
@ -128,16 +130,15 @@ object Terminal {
* @param item the `Equipment` being given to the player
*/
final case class BuyEquipment(item : Equipment) extends Exchange
/**
* A roundabout message oft-times.
* Most `Terminals` should always allow `Player`s to dispose of some piece of `Equipment`.
* A result of a processed request.
*/
//TODO if there are exceptions, find them
final case class SellEquipment() extends Exchange
final case class SellEquipment() extends Exchange //TODO if there are exceptions, find them
import net.psforever.types.CertificationType
/**
* Provide the certification type unlocked by the player.
* @param cert the certification unlocked
@ -173,6 +174,7 @@ object Terminal {
*/
final case class BuyVehicle(vehicle : Vehicle, weapons : List[InventoryItem], inventory : List[InventoryItem]) extends Exchange
import net.psforever.objects.inventory.InventoryItem
/**
* Recover a former exo-suit and `Equipment` configuration that the `Player` possessed.
* A result of a processed request.
@ -190,4 +192,20 @@ object Terminal {
def apply(tdef : TerminalDefinition) : Terminal = {
new Terminal(tdef)
}
import akka.actor.ActorContext
/**
* Instantiate an configure a `Terminal` object
* @param tdef the `ObjectDefinition` that constructs this object and maintains some of its immutable fields
* @param id the unique id that will be assigned to this entity
* @param context a context to allow the object to properly set up `ActorSystem` functionality
* @return the `Terminal` object
*/
def Constructor(tdef : TerminalDefinition)(id : Int, context : ActorContext) : Terminal = {
import akka.actor.Props
val obj = Terminal(tdef)
obj.Actor = context.actorOf(Props(classOf[TerminalControl], obj), s"${tdef.Name}_$id")
obj
}
}

View file

@ -1,7 +1,7 @@
// Copyright (c) 2017 PSForever
package net.psforever.objects.zones
import net.psforever.objects.serverobject.builders.ServerObjectBuilder
import net.psforever.objects.serverobject.ServerObjectBuilder
/**
* The fixed instantiation and relation of a series of server objects.<br>

View file

@ -2,23 +2,23 @@
package objects
import akka.actor.{Actor, Props}
import net.psforever.objects.GlobalDefinitions
import net.psforever.objects.GlobalDefinitions.order_terminal
import net.psforever.objects.guid.NumberPoolHub
import net.psforever.packet.game.PlanetSideGUID
import net.psforever.objects.serverobject.builders.ServerObjectBuilder
import net.psforever.objects.serverobject.ServerObjectBuilder
import net.psforever.types.Vector3
import scala.concurrent.duration.Duration
class DoorObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.doors.Door
import net.psforever.objects.serverobject.builders.DoorObjectBuilder
"DoorObjectBuilder" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], DoorObjectBuilder(GlobalDefinitions.door, 1), hub), "door")
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Door.Constructor), hub), "door")
actor ! "!"
val reply = receiveOne(Duration.create(100, "ms"))
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Door])
assert(reply.asInstanceOf[Door].HasGUID)
assert(reply.asInstanceOf[Door].GUID == PlanetSideGUID(1))
@ -29,14 +29,13 @@ class DoorObjectBuilderTest extends ActorTest {
class IFFLockObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.locks.IFFLock
import net.psforever.objects.serverobject.builders.IFFLockObjectBuilder
"IFFLockObjectBuilder" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], IFFLockObjectBuilder(GlobalDefinitions.lock_external, 1), hub), "lock")
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, IFFLock.Constructor), hub), "lock")
actor ! "!"
val reply = receiveOne(Duration.create(100, "ms"))
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[IFFLock])
assert(reply.asInstanceOf[IFFLock].HasGUID)
assert(reply.asInstanceOf[IFFLock].GUID == PlanetSideGUID(1))
@ -47,14 +46,13 @@ class IFFLockObjectBuilderTest extends ActorTest {
class ImplantTerminalMechObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.implantmech.ImplantTerminalMech
import net.psforever.objects.serverobject.builders.ImplantTerminalMechObjectBuilder
"IFFLockObjectBuilder" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ImplantTerminalMechObjectBuilder(GlobalDefinitions.implant_terminal_mech, 1), hub), "mech")
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, ImplantTerminalMech.Constructor), hub), "mech")
actor ! "!"
val reply = receiveOne(Duration.create(100, "ms"))
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[ImplantTerminalMech])
assert(reply.asInstanceOf[ImplantTerminalMech].HasGUID)
assert(reply.asInstanceOf[ImplantTerminalMech].GUID == PlanetSideGUID(1))
@ -65,14 +63,13 @@ class ImplantTerminalMechObjectBuilderTest extends ActorTest {
class TerminalObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.terminals.Terminal
import net.psforever.objects.serverobject.builders.TerminalObjectBuilder
"TerminalObjectBuilder" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], TerminalObjectBuilder(GlobalDefinitions.order_terminal, 1), hub), "term")
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1, Terminal.Constructor(order_terminal)), hub), "term")
actor ! "!"
val reply = receiveOne(Duration.create(100, "ms"))
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[Terminal])
assert(reply.asInstanceOf[Terminal].HasGUID)
assert(reply.asInstanceOf[Terminal].GUID == PlanetSideGUID(1))
@ -83,17 +80,20 @@ class TerminalObjectBuilderTest extends ActorTest {
class VehicleSpawnPadObjectBuilderTest extends ActorTest {
import net.psforever.objects.serverobject.pad.VehicleSpawnPad
import net.psforever.objects.serverobject.builders.VehicleSpawnPadObjectBuilder
"TerminalObjectBuilder" should {
"build" in {
val hub = ServerObjectBuilderTest.NumberPoolHub
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], VehicleSpawnPadObjectBuilder(GlobalDefinitions.spawn_pad, 1), hub), "pad")
val actor = system.actorOf(Props(classOf[ServerObjectBuilderTest.BuilderTestActor], ServerObjectBuilder(1,
VehicleSpawnPad.Constructor(Vector3(1.1f, 2.2f, 3.3f), Vector3(4.4f, 5.5f, 6.6f))
), hub), "pad")
actor ! "!"
val reply = receiveOne(Duration.create(100, "ms"))
val reply = receiveOne(Duration.create(1000, "ms"))
assert(reply.isInstanceOf[VehicleSpawnPad])
assert(reply.asInstanceOf[VehicleSpawnPad].HasGUID)
assert(reply.asInstanceOf[VehicleSpawnPad].GUID == PlanetSideGUID(1))
assert(reply.asInstanceOf[VehicleSpawnPad].Position == Vector3(1.1f, 2.2f, 3.3f))
assert(reply.asInstanceOf[VehicleSpawnPad].Orientation == Vector3(4.4f, 5.5f, 6.6f))
assert(reply == hub(1).get)
}
}