diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala
index 22f87d59e..a5ce3bbdd 100644
--- a/common/src/main/scala/net/psforever/objects/Vehicle.scala
+++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala
@@ -22,7 +22,15 @@ import scala.annotation.tailrec
* Following that are the mounted weapons and other utilities.
* Trunk space starts being indexed afterwards.
*
- * To keep it simple, infantry seating, mounted weapons, and utilities are stored separately.
+ * To keep it simple, infantry seating, mounted weapons, and utilities are stored separately.
+ *
+ * Vehicles maintain a `Map` of `Utility` objects in given index positions.
+ * Positive indices and zero are considered "represented" and must be assigned a globally unique identifier
+ * and must be present in the containing vehicle's `ObjectCreateMessage` packet.
+ * The index is the seat position, reflecting the position in the zero-index inventory.
+ * Negative indices are expected to be excluded from this conversion.
+ * The value of the negative index does not have a specific meaning.
+ * @see `Vehicle.EquipmentUtilities`
* @param vehicleDef the vehicle's definition entry';
* stores and unloads pertinent information about the `Vehicle`'s configuration;
* used in the initialization process (`loadVehicleDefinition`)
@@ -493,6 +501,14 @@ object Vehicle {
new Vehicle(vehicleDef)
}
+ /**
+ * Given a `Map` of `Utility` objects, only return the objects with a positive or zero-index position.
+ * @return a map of applicable utilities
+ */
+ def EquipmentUtilities(utilities : Map[Int, Utility]) : Map[Int, Utility] = {
+ utilities.filter({ case(index : Int, _ : Utility) => index > -1 })
+ }
+
/**
* Use the `*Definition` that was provided to this object to initialize its fields and settings.
* @param vehicle the `Vehicle` being initialized
diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala
index 6bef162c4..137ad6c0e 100644
--- a/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala
+++ b/common/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala
@@ -44,7 +44,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
}
protected def MakeUtilities(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
- obj.Utilities.map({
+ Vehicle.EquipmentUtilities(obj.Utilities).map({
case(index, utilContainer) =>
val util = utilContainer()
val utilDef = util.Definition
diff --git a/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala b/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala
index 95b03452c..95d92bced 100644
--- a/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala
+++ b/common/src/main/scala/net/psforever/objects/guid/GUIDTask.scala
@@ -151,7 +151,7 @@ object GUIDTask {
def RegisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
import net.psforever.objects.inventory.InventoryItem
val weaponTasks = vehicle.Weapons.map({ case(_ : Int, entry : EquipmentSlot) => RegisterEquipment(entry.Equipment.get)}).toList
- val utilTasks = vehicle.Utilities.map({case (_ : Int, util : Utility) => RegisterObjectTask(util())}).toList
+ val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).map({case (_ : Int, util : Utility) => RegisterObjectTask(util())}).toList
val inventoryTasks = vehicle.Trunk.Items.map({ case((_ : Int, entry : InventoryItem)) => RegisterEquipment(entry.obj)})
TaskResolver.GiveTask(RegisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
}
@@ -255,7 +255,7 @@ object GUIDTask {
def UnregisterVehicle(vehicle : Vehicle)(implicit guid : ActorRef) : TaskResolver.GiveTask = {
import net.psforever.objects.inventory.InventoryItem
val weaponTasks = vehicle.Weapons.map({ case(_ : Int, entry : EquipmentSlot) => UnregisterTool(entry.Equipment.get.asInstanceOf[Tool]) }).toList
- val utilTasks = vehicle.Utilities.map({case (_ : Int, util : Utility) => UnregisterObjectTask(util())}).toList
+ val utilTasks = Vehicle.EquipmentUtilities(vehicle.Utilities).map({case (_ : Int, util : Utility) => UnregisterObjectTask(util())}).toList
val inventoryTasks = vehicle.Trunk.Items.map({ case((_ : Int, entry : InventoryItem)) => UnregisterEquipment(entry.obj)})
TaskResolver.GiveTask(UnregisterObjectTask(vehicle).task, weaponTasks ++ utilTasks ++ inventoryTasks)
}
diff --git a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala
index 683b4fc85..5259c3255 100644
--- a/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala
+++ b/common/src/main/scala/net/psforever/objects/vehicles/Utility.scala
@@ -56,6 +56,12 @@ class Utility(util : UtilityType.Value, vehicle : Vehicle) {
* @param context an `ActorContext` potentially useful for the function
*/
def Setup(implicit context : ActorContext) : Unit = setupFunc(obj, context)
+
+ /**
+ * Recover the original value used to initialize this object.
+ * @return the type of the `Amenity` object that was created
+ */
+ def UtilType : UtilityType.Value = util
}
object Utility {
diff --git a/common/src/test/scala/objects/ConverterTest.scala b/common/src/test/scala/objects/ConverterTest.scala
index 612637405..723c248f7 100644
--- a/common/src/test/scala/objects/ConverterTest.scala
+++ b/common/src/test/scala/objects/ConverterTest.scala
@@ -298,7 +298,7 @@ class ConverterTest extends Specification {
}
"Vehicle" should {
- "convert to packet" in {
+ "convert to packet (1)" in {
val hellfire_ammo = AmmoBoxDefinition(Ammo.hellfire_ammo.id)
val fury_weapon_systema_def = ToolDefinition(ObjectClass.fury_weapon_systema)
@@ -333,5 +333,16 @@ class ConverterTest extends Specification {
fury.Definition.Packet.ConstructorData(fury).isSuccess mustEqual true
ok //TODO write more of this test
}
+
+ "convert to packet (2)" in {
+ val
+ ams = Vehicle(GlobalDefinitions.ams)
+ ams.GUID = PlanetSideGUID(413)
+ ams.Utilities(3)().GUID = PlanetSideGUID(414)
+ ams.Utilities(4)().GUID = PlanetSideGUID(415)
+
+ ams.Definition.Packet.ConstructorData(ams).isSuccess mustEqual true
+ ok //TODO write more of this test
+ }
}
}
\ No newline at end of file
diff --git a/common/src/test/scala/objects/UtilityTest.scala b/common/src/test/scala/objects/UtilityTest.scala
index 5ac6740a4..ef78af4bf 100644
--- a/common/src/test/scala/objects/UtilityTest.scala
+++ b/common/src/test/scala/objects/UtilityTest.scala
@@ -14,6 +14,7 @@ class UtilityTest extends Specification {
"Utility" should {
"create an order_terminala object" in {
val obj = Utility(UtilityType.order_terminala, UtilityTest.vehicle)
+ obj.UtilType mustEqual UtilityType.order_terminala
obj().isInstanceOf[Terminal] mustEqual true
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 613
obj().asInstanceOf[Terminal].Actor == ActorRef.noSender
@@ -21,6 +22,7 @@ class UtilityTest extends Specification {
"create an order_terminalb object" in {
val obj = Utility(UtilityType.order_terminalb, UtilityTest.vehicle)
+ obj.UtilType mustEqual UtilityType.order_terminalb
obj().isInstanceOf[Terminal] mustEqual true
obj().asInstanceOf[Terminal].Definition.ObjectId mustEqual 614
obj().asInstanceOf[Terminal].Actor == ActorRef.noSender
diff --git a/common/src/test/scala/objects/VehicleTest.scala b/common/src/test/scala/objects/VehicleTest.scala
index 1bd7abfaf..e7e6f2e39 100644
--- a/common/src/test/scala/objects/VehicleTest.scala
+++ b/common/src/test/scala/objects/VehicleTest.scala
@@ -3,7 +3,7 @@ package objects
import akka.actor.Props
import net.psforever.objects.{GlobalDefinitions, Player, Vehicle}
-import net.psforever.objects.definition.SeatDefinition
+import net.psforever.objects.definition.{SeatDefinition, VehicleDefinition}
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.vehicles._
import net.psforever.packet.game.PlanetSideGUID
@@ -256,6 +256,26 @@ class VehicleTest extends Specification {
harasser_vehicle.WeaponControlledFromSeat(0) mustEqual None
harasser_vehicle.WeaponControlledFromSeat(1) mustEqual chaingun_p
}
+
+ "can filter utilities with indices that are natural numbers" in {
+ val objDef = VehicleDefinition(1)
+ objDef.Utilities += -1 -> UtilityType.order_terminala
+ objDef.Utilities += 0 -> UtilityType.order_terminalb
+ objDef.Utilities += 2 -> UtilityType.order_terminalb
+ val obj = Vehicle(objDef)
+
+ obj.Utilities.size mustEqual 3
+ obj.Utilities(-1).UtilType mustEqual UtilityType.order_terminala
+ obj.Utilities(0).UtilType mustEqual UtilityType.order_terminalb
+ obj.Utilities.get(1) mustEqual None
+ obj.Utilities(2).UtilType mustEqual UtilityType.order_terminalb
+
+ val filteredMap = Vehicle.EquipmentUtilities(obj.Utilities)
+ filteredMap.size mustEqual 2
+ filteredMap.get(-1) mustEqual None
+ filteredMap(0).UtilType mustEqual UtilityType.order_terminalb
+ filteredMap(2).UtilType mustEqual UtilityType.order_terminalb
+ }
}
}