diff --git a/common/src/main/scala/net/psforever/objects/Vehicle.scala b/common/src/main/scala/net/psforever/objects/Vehicle.scala
index 6dabd99a..1291ca07 100644
--- a/common/src/main/scala/net/psforever/objects/Vehicle.scala
+++ b/common/src/main/scala/net/psforever/objects/Vehicle.scala
@@ -21,14 +21,42 @@ import scala.annotation.tailrec
* Generally, all seating is declared first - the driver and passengers and and gunners.
* 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.
- *
- * Vehicles maintain a `Map` of `Utility` objects in given index positions.
+ * To keep it simple, infantry seating, mounted weapons, and utilities are stored separately herein.
+ * The `Map` of `Utility` objects is given using the same inventory 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.
+ * The value of the negative index does not have a specific meaning.
+ *
+ * The importance of a vehicle's owner can not be overlooked.
+ * The owner is someone who can control who can sit in the vehicle's seats
+ * either through broad categorization or discriminating sleection ("kicking")
+ * and who has access to and can allow access to the vehicle's trunk capacity.
+ * The driver is the only player that can access a vehicle's saved loadouts through a repair/rearm silo
+ * and can procure equipment from the said silo.
+ * The owner of a vehicle and the driver of a vehicle as mostly interchangeable terms for this reason
+ * and it can be summarized that the player who has access to the driver seat meets the qualifications for the "owner"
+ * so long as that player is the last person to have sat in that seat.
+ * All previous ownership information is replaced just as soon as someone else sits in the driver's seat.
+ * Ownership is also transferred as players die and respawn (from and to the same client)
+ * and when they leave a continent without taking the vehicle they currently own with them.
+ * (They also lose ownership when they leave the game, of course.)
+ *
+ * All seats have vehicle-level properties on top of their own internal properties.
+ * A seat has a glyph projected onto the ground when the vehicle is not moving
+ * that is used to mark where the seat can be accessed, as well as broadcasting the current access condition of the seat.
+ * As indicated previously, seats are composed into categories and the categories used to control access.
+ * The "driver" group has already been mentioned and is usually composed of a single seat, the "first" one.
+ * The driver seat is typically locked to the person who can sit in it - the owner - unless manually unlocked.
+ * Any seat besides the "driver" that has a weapon controlled from the seat is called a "gunner" seats.
+ * Any other seat besides the "driver" seat and "gunner" seats is called a "passenger" seat.
+ * All of these seats are typically unlocked normally.
+ * The "trunk" also counts as an access group even though it is not directly attached to a seat and starts as "locked."
+ * The categories all have their own glyphs,
+ * sharing a red cross glyph as a "can not access" state,
+ * and may also use their lack of visibility to express state.
+ * In terms of individual access, each seat can have its current occupant ejected, save for the driver's seat.
* @see `Vehicle.EquipmentUtilities`
* @param vehicleDef the vehicle's definition entry';
* stores and unloads pertinent information about the `Vehicle`'s configuration;
diff --git a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
index e07210b8..15dc1c55 100644
--- a/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
+++ b/common/src/main/scala/net/psforever/objects/definition/converter/AvatarConverter.scala
@@ -12,9 +12,8 @@ import scala.util.{Success, Try}
class AvatarConverter extends ObjectCreateConverter[Player]() {
override def ConstructorData(obj : Player) : Try[PlayerData] = {
import AvatarConverter._
- val MaxArmor = obj.MaxArmor
- if(obj.VehicleSeated.isEmpty) {
- Success(
+ Success(
+ if(obj.VehicleSeated.isEmpty) {
PlayerData(
PlacementData(obj.Position, obj.Orientation, obj.Velocity),
MakeAppearanceData(obj),
@@ -22,43 +21,38 @@ class AvatarConverter extends ObjectCreateConverter[Player]() {
MakeInventoryData(obj),
GetDrawnSlot(obj)
)
- )
- }
- else {
- Success(
+ }
+ else {
PlayerData(
MakeAppearanceData(obj),
MakeCharacterData(obj),
MakeInventoryData(obj),
- GetDrawnSlot(obj)
+ DrawnSlot.None
)
- )
- }
+ }
+ )
}
override def DetailedConstructorData(obj : Player) : Try[DetailedPlayerData] = {
import AvatarConverter._
Success(
- DetailedPlayerData.apply(
- PlacementData(obj.Position, obj.Orientation, obj.Velocity),
- MakeAppearanceData(obj),
- DetailedCharacterData(
- obj.BEP,
- obj.CEP,
- obj.MaxHealth,
- obj.Health,
- obj.Armor,
- obj.MaxStamina,
- obj.Stamina,
- obj.Certifications.toList.sortBy(_.id), //TODO is sorting necessary?
- MakeImplantEntries(obj),
- List.empty[String], //TODO fte list
- List.empty[String], //TODO tutorial list
- MakeCosmetics(obj.BEP)
- ),
- InventoryData((MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot)),
- GetDrawnSlot(obj)
- )
+ if(obj.VehicleSeated.isEmpty) {
+ DetailedPlayerData.apply(
+ PlacementData(obj.Position, obj.Orientation, obj.Velocity),
+ MakeAppearanceData(obj),
+ MakeDetailedCharacterData(obj),
+ MakeDetailedInventoryData(obj),
+ GetDrawnSlot(obj)
+ )
+ }
+ else {
+ DetailedPlayerData.apply(
+ MakeAppearanceData(obj),
+ MakeDetailedCharacterData(obj),
+ MakeDetailedInventoryData(obj),
+ DrawnSlot.None
+ )
+ }
)
}
}
@@ -107,8 +101,29 @@ object AvatarConverter {
)
}
+ def MakeDetailedCharacterData(obj : Player) : (Option[Int])=>DetailedCharacterData = {
+ DetailedCharacterData(
+ obj.BEP,
+ obj.CEP,
+ obj.MaxHealth,
+ obj.Health,
+ obj.Armor,
+ obj.MaxStamina,
+ obj.Stamina,
+ obj.Certifications.toList.sortBy(_.id), //TODO is sorting necessary?
+ MakeImplantEntries(obj),
+ List.empty[String], //TODO fte list
+ List.empty[String], //TODO tutorial list
+ MakeCosmetics(obj.BEP)
+ )
+ }
+
def MakeInventoryData(obj : Player) : InventoryData = {
- InventoryData(MakeHolsters(obj, BuildEquipment).sortBy(_.parentSlot)) //TODO is sorting necessary?
+ InventoryData(MakeHolsters(obj, BuildEquipment).sortBy(_.parentSlot))
+ }
+
+ def MakeDetailedInventoryData(obj : Player) : InventoryData = {
+ InventoryData((MakeHolsters(obj, BuildDetailedEquipment) ++ MakeFifthSlot(obj) ++ MakeInventory(obj)).sortBy(_.parentSlot))
}
/**
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 e354e8e8..eea2f688 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
@@ -13,16 +13,22 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
Failure(new Exception("VehicleConverter should not be used to generate detailed VehicleData (nothing should)"))
override def ConstructorData(obj : Vehicle) : Try[VehicleData] = {
+ val health = 255 * obj.Health / obj.MaxHealth //TODO not precise
Success(
VehicleData(
- CommonFieldData(
- PlacementData(obj.Position, obj.Orientation, obj.Velocity),
- obj.Faction,
- 0,
- PlanetSideGUID(0) //if(obj.Owner.isDefined) { obj.Owner.get } else { PlanetSideGUID(0) } //TODO is this really Owner?
- ),
+ PlacementData(obj.Position, obj.Orientation, obj.Velocity),
+ obj.Faction,
+ false, //bops
+ health < 3, //destroyed
0,
- 255 * obj.Health / obj.MaxHealth, //TODO not precise
+ obj.Jammered, //jammered
+ false,
+ obj.Owner match {
+ case Some(owner) => owner
+ case None => PlanetSideGUID(0)
+ },
+ false,
+ health,
false, false,
obj.DeploymentState,
false,
@@ -35,11 +41,9 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
}
private def MakeSeats(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
- var offset : Long = VehicleData.InitialStreamLengthToSeatEntries(true, SpecificFormatModifier)
- obj.Seats
- .filter({ case(_, seat) => seat.isOccupied })
- .map({ case(index, seat) =>
- val player = seat.Occupant.get
+ val offset : Long = VehicleData.InitialStreamLengthToSeatEntries(true, SpecificFormatModifier)
+ obj.Seats(0).Occupant match { //TODO just the driver for now to avoid issues with seat permissions
+ case Some(player) =>
val mountedPlayer = VehicleData.PlayerData(
AvatarConverter.MakeAppearanceData(player),
AvatarConverter.MakeCharacterData(player),
@@ -47,11 +51,13 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() {
AvatarConverter.GetDrawnSlot(player),
offset
)
- val entry = InventoryItemData(ObjectClass.avatar, player.GUID, index, mountedPlayer)
- println(s"seat $index offset: $offset, size: ${entry.bitsize}")
- offset += entry.bitsize
- entry
- }).toList
+ val entry = InventoryItemData(ObjectClass.avatar, player.GUID, 0, mountedPlayer)
+ //println(s"seat 0 offset: $offset, size: ${entry.bitsize}, pad: ${mountedPlayer.basic_appearance.NamePadding}")
+ //offset += entry.bitsize
+ List(entry)
+ case None =>
+ Nil
+ }
}
private def MakeMountings(obj : Vehicle) : List[InventoryItemData.InventoryItem] = {
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala
index 2b67fa47..2fb0f248 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlSeatDriver.scala
@@ -4,6 +4,7 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.{ActorRef, Props}
import net.psforever.objects.serverobject.mount.Mountable
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
+import net.psforever.types.Vector3
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -46,7 +47,7 @@ class VehicleSpawnControlSeatDriver(pad : VehicleSpawnPad) extends VehicleSpawnC
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))
+ context.system.scheduler.scheduleOnce(1500 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry))
}
else {
trace("driver lost; vehicle stranded on pad")
@@ -55,11 +56,18 @@ class VehicleSpawnControlSeatDriver(pad : VehicleSpawnPad) extends VehicleSpawnC
case VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry) =>
val driver = entry.driver
- if(entry.sendTo == ActorRef.noSender || driver.Continent != Continent.Id) {
+ if(entry.sendTo == ActorRef.noSender || !driver.isAlive || driver.Continent != Continent.Id) {
trace("driver lost, but operations can continue")
vehicleOverride ! VehicleSpawnControl.Process.ServerVehicleOverride(entry)
}
+ else if(entry.vehicle.Health == 0 || entry.vehicle.Position == Vector3.Zero) {
+ //skip ahead for cleanup
+ vehicleOverride ! VehicleSpawnControl.Process.ServerVehicleOverride(entry)
+ }
else if(driver.isAlive && driver.VehicleSeated.isEmpty) {
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(entry.vehicle, pad, Continent.Id)
+ }
context.system.scheduler.scheduleOnce(100 milliseconds, self, VehicleSpawnControlSeatDriver.AwaitDriverInSeat(entry))
}
else {
diff --git a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala
index 41194d46..d7331618 100644
--- a/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala
+++ b/common/src/main/scala/net/psforever/objects/serverobject/pad/process/VehicleSpawnControlServerVehicleOverride.scala
@@ -3,6 +3,7 @@ package net.psforever.objects.serverobject.pad.process
import akka.actor.{ActorRef, Props}
import net.psforever.objects.serverobject.pad.{VehicleSpawnControl, VehicleSpawnPad}
+import net.psforever.types.Vector3
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._
@@ -26,27 +27,33 @@ class VehicleSpawnControlServerVehicleOverride(pad : VehicleSpawnPad) extends Ve
def receive : Receive = {
case VehicleSpawnControl.Process.ServerVehicleOverride(entry) =>
val vehicle = entry.vehicle
- 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) {
- Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ val vehicleFailState = vehicle.Health == 0 || vehicle.Position == Vector3.Zero
+ val driverFailState = !entry.driver.isAlive || entry.driver.Continent != Continent.Id || (if(vehicle.HasGUID) { !entry.driver.VehicleSeated.contains(vehicle.GUID) } else { true })
+ if(vehicleFailState || driverFailState) {
+ if(vehicleFailState) {
+ trace(s"vehicle was already destroyed")
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ }
}
+ else {
+ trace(s"driver is not ready")
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id)
+ }
+ }
+ Continent.VehicleEvents ! VehicleSpawnPad.RevealPlayer(entry.driver.GUID, Continent.Id)
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, vehicleGuide, VehicleSpawnControl.Process.StartGuided(entry))
- }
else {
- if(pad_railed) {
- Continent.VehicleEvents ! VehicleSpawnPad.ResetSpawnPad(pad, Continent.Id)
+ if(pad.Railed) {
+ Continent.VehicleEvents ! VehicleSpawnPad.DetachFromRails(vehicle, pad, Continent.Id)
+ }
+ if(entry.sendTo != ActorRef.noSender) {
+ 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, vehicleGuide, VehicleSpawnControl.Process.StartGuided(entry))
}
- vehicleGuide ! VehicleSpawnControl.Process.FinalClearance(entry)
}
case msg @ (VehicleSpawnControl.ProcessControl.Reminder | VehicleSpawnControl.ProcessControl.GetNewOrder) =>
diff --git a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
index adb2bd3a..0518cfc7 100644
--- a/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
+++ b/common/src/main/scala/net/psforever/objects/vehicles/VehicleControl.scala
@@ -3,9 +3,10 @@ package net.psforever.objects.vehicles
import akka.actor.Actor
import net.psforever.objects.Vehicle
-import net.psforever.objects.serverobject.mount.MountableBehavior
+import net.psforever.objects.serverobject.mount.{Mountable, MountableBehavior}
import net.psforever.objects.serverobject.affinity.{FactionAffinity, FactionAffinityBehavior}
import net.psforever.objects.serverobject.deploy.DeploymentBehavior
+import net.psforever.types.ExoSuitType
/**
* An `Actor` that handles messages being dispatched to a specific `Vehicle`.
@@ -32,9 +33,32 @@ class VehicleControl(vehicle : Vehicle) extends Actor
def Enabled : Receive = checkBehavior
.orElse(deployBehavior)
- .orElse(mountBehavior)
.orElse(dismountBehavior)
.orElse {
+ case Mountable.TryMount(user, seat_num) =>
+ val exosuit = user.ExoSuit
+ val restriction = vehicle.Seats(seat_num).ArmorRestriction
+ val seatGroup = vehicle.SeatPermissionGroup(seat_num).getOrElse(AccessPermissionGroup.Passenger)
+ val permission = vehicle.PermissionGroup(seatGroup.id).getOrElse(VehicleLockState.Empire)
+ if(
+ (if(seatGroup == AccessPermissionGroup.Driver) {
+ vehicle.Owner.contains(user.GUID) || vehicle.Owner.isEmpty || permission != VehicleLockState.Locked
+ }
+ else {
+ permission != VehicleLockState.Locked
+ }) &&
+ (exosuit match {
+ case ExoSuitType.MAX => restriction == SeatArmorRestriction.MaxOnly
+ case ExoSuitType.Reinforced => restriction != SeatArmorRestriction.NoReinforcedOrMax
+ case _ => true
+ })
+ ) {
+ mountBehavior.apply(Mountable.TryMount(user, seat_num))
+ }
+ else {
+ sender ! Mountable.MountMessages(user, Mountable.CanNotMount(vehicle, seat_num))
+ }
+
case FactionAffinity.ConvertFactionAffinity(faction) =>
val originalAffinity = vehicle.Faction
if(originalAffinity != (vehicle.Faction = faction)) {
diff --git a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
index 5d0dc875..007cbbc9 100644
--- a/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
+++ b/common/src/main/scala/net/psforever/packet/game/PlanetsideAttributeMessage.scala
@@ -126,7 +126,7 @@ import scodec.codecs._
* `11 - Gunner seat(s) permissions (same)`
* `12 - Passenger seat(s) permissions (same)`
* `13 - Trunk permissions (same)`
- * `21 - Asserts first time event eligibility / makes owner if no owner is assigned`
+ * `21 - Declare a player the vehicle's owner, by globally unique identifier`
* `22 - Toggles gunner and passenger mount points (1 = hides, 0 = reveals; this also locks their permissions)`
* `68 - ???`
* `80 - Damage vehicle (unknown value)`
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala
index 36b90591..d6221fcb 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala
@@ -125,11 +125,17 @@ final case class CharacterAppearanceData(app : BasicCharacterData,
//factor guard bool values into the base size, not its corresponding optional field
val nameStringSize : Long = StreamBitSize.stringBitSize(app.name, 16) + name_padding
val outfitStringSize : Long = StreamBitSize.stringBitSize(outfit_name, 16) +
- CharacterAppearanceData.outfitNamePadding //even if the outfit_name is blank, string always padded
+ (if(outfit_name.nonEmpty) { CharacterAppearanceData.outfitNamePadding } else { 0L }) //even if the outfit_name is blank, string always padded
val altModelSize = CharacterAppearanceData.altModelBit(this).getOrElse(0)
335L + nameStringSize + outfitStringSize + altModelSize
}
+ /**
+ * External access to the value padding on the name field.
+ * The padding will always be a number 0-7.
+ * @return the pad length in bits
+ */
+ def NamePadding : Int = name_padding
/**
* When a player is released-dead or attached to a zipline, their basic infantry model is replaced with a different one.
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala
index 8a9acb63..20b6f3e4 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/DetailedPlayerData.scala
@@ -49,33 +49,62 @@ final case class DetailedPlayerData(pos : Option[PlacementData],
object DetailedPlayerData extends Marshallable[DetailedPlayerData] {
/**
- * Overloaded constructor that ignores the coordinate information.
+ * Overloaded constructor that ignores the coordinate information but includes the inventory.
* It passes information between the three major divisions for the purposes of offset calculations.
+ * This constructor should be used for players that are mounted.
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
* @param character_data a curried function for the class-specific data that explains about the character
+ * @param inventory the player's inventory
+ * @param drawn_slot the holster that is initially drawn;
+ * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
* @return a `DetailedPlayerData` object
*/
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
val appearance = basic_appearance(5)
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(false)
}
- /** */
+
+ /**
+ * Overloaded constructor that ignores the coordinate information and the inventory.
+ * It passes information between the three major divisions for the purposes of offset calculations.
+ * This constructor should be used for players that are mounted.
+ * @param basic_appearance a curried function for the common fields regarding the the character's appearance
+ * @param character_data a curried function for the class-specific data that explains about the character
+ * @param drawn_slot the holster that is initially drawn;
+ * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
+ * @return a `DetailedPlayerData` object
+ */
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
val appearance = basic_appearance(5)
DetailedPlayerData(None, appearance, character_data(appearance.altModelBit), None, drawn_slot)(false)
}
+
/**
- * Overloaded constructor that includes the coordinate information.
+ * Overloaded constructor that includes the coordinate information and the inventory.
* It passes information between the three major divisions for the purposes of offset calculations.
+ * This constructor should be used for players that are standing apart from other containers.
+ * @param pos the optional position of the character in the world environment
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
* @param character_data a curried function for the class-specific data that explains about the character
+ * @param inventory the player's inventory
+ * @param drawn_slot the holster that is initially drawn
* @return a `DetailedPlayerData` object
*/
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), Some(inventory), drawn_slot)(true)
}
- /** */
+
+ /**
+ * Overloaded constructor that includes the coordinate information but ignores the inventory.
+ * It passes information between the three major divisions for the purposes of offset calculations.
+ * This constructor should be used for players that are standing apart from other containers.
+ * @param pos the optional position of the character in the world environment
+ * @param basic_appearance a curried function for the common fields regarding the the character's appearance
+ * @param character_data a curried function for the class-specific data that explains about the character
+ * @param drawn_slot the holster that is initially drawn
+ * @return a `DetailedPlayerData` object
+ */
def apply(pos : PlacementData, basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Option[Int])=>DetailedCharacterData, drawn_slot : DrawnSlot.Value) : DetailedPlayerData = {
val appearance = basic_appearance(PlayerData.PaddingOffset(Some(pos)))
DetailedPlayerData(Some(pos), appearance, character_data(appearance.altModelBit), None, drawn_slot)(true)
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala
index e84483d3..7452d1be 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/PlayerData.scala
@@ -53,13 +53,14 @@ final case class PlayerData(pos : Option[PlacementData],
object PlayerData extends Marshallable[PlayerData] {
/**
- * Overloaded constructor that ignores the coordinate information.
+ * Overloaded constructor that ignores the coordinate information but includes the inventory.
* It passes information between the three major divisions for the purposes of offset calculations.
* This constructor should be used for players that are mounted.
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
* @param character_data a curried function for the class-specific data that explains about the character
* @param inventory the player's inventory
- * @param drawn_slot the holster that is initially drawn
+ * @param drawn_slot the holster that is initially drawn;
+ * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
* @return a `PlayerData` object
*/
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, inventory : InventoryData, drawn_slot : DrawnSlot.Type) : PlayerData = {
@@ -72,7 +73,8 @@ object PlayerData extends Marshallable[PlayerData] {
* This constructor should be used for players that are mounted.
* @param basic_appearance a curried function for the common fields regarding the the character's appearance
* @param character_data a curried function for the class-specific data that explains about the character
- * @param drawn_slot the holster that is initially drawn
+ * @param drawn_slot the holster that is initially drawn;
+ * technically, always `DrawnSlot.None`, but the field is preserved to maintain similarity
* @return a `PlayerData` object
*/
def apply(basic_appearance : (Int)=>CharacterAppearanceData, character_data : (Boolean,Boolean)=>CharacterData, drawn_slot : DrawnSlot.Type) : PlayerData = {
@@ -81,7 +83,7 @@ object PlayerData extends Marshallable[PlayerData] {
}
/**
- * Overloaded constructor.
+ * Overloaded constructor that includes the coordinate information and the inventory.
* It passes information between the three major divisions for the purposes of offset calculations.
* This constructor should be used for players that are standing apart from other containers.
* @param pos the optional position of the character in the world environment
@@ -96,7 +98,7 @@ object PlayerData extends Marshallable[PlayerData] {
PlayerData(Some(pos), appearance, character_data(appearance.backpack, false), Some(inventory), drawn_slot)(true)
}
/**
- * Overloaded constructor that ignores the inventory.
+ * Overloaded constructor that includes the coordinate information but ignores the inventory.
* It passes information between the three major divisions for the purposes of offset calculations.
* This constructor should be used for players that are standing apart from other containers.
* @param pos the optional position of the character in the world environment
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala
index acfaa407..a767591d 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/Prefab.scala
@@ -13,22 +13,23 @@ import net.psforever.types.{DriveState, PlanetSideEmpire}
object Prefab {
object Vehicle {
def ams(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, driveState : DriveState.Value, matrix_guid : PlanetSideGUID, respawn_guid : PlanetSideGUID, term_a_guid : PlanetSideGUID, term_b_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, driveState, false, false, false, Some(UtilityVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 0), health, driveState, false, UtilityVehicleData(0),
Some(InventoryData(List(
InternalSlot(ObjectClass.matrix_terminalc, matrix_guid, 1, CommonTerminalData(faction)),
InternalSlot(ObjectClass.ams_respawn_tube, respawn_guid, 2, CommonTerminalData(faction)),
InternalSlot(ObjectClass.order_terminala, term_a_guid, 3, CommonTerminalData(faction)),
InternalSlot(ObjectClass.order_terminalb, term_b_guid, 4, CommonTerminalData(faction))
)))
- )(VehicleFormat.Utility)
+ )
}
def ant(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, driveState : DriveState.Value) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, driveState, false, false, false, Some(UtilityVehicleData(0)), None)(VehicleFormat.Utility)
+ VehicleData(CommonFieldData(loc, faction, 0), health, driveState, false, UtilityVehicleData(0), None)
}
def apc_nc(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID, weapon6_guid : PlanetSideGUID, ammo6_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.apc_weapon_systemc_nc, weapon1_guid, 11,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(8))
@@ -49,11 +50,12 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def apc_tr(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID, weapon6_guid : PlanetSideGUID, ammo6_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.apc_weapon_systemc_tr, weapon1_guid, 11,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo1_guid, 0, AmmoBoxData(8))
@@ -74,11 +76,12 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def apc_vs(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID, weapon6_guid : PlanetSideGUID, ammo6_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.apc_weapon_systemc_vs, weapon1_guid, 11,
WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo1_guid, 0, AmmoBoxData(8))
@@ -99,12 +102,13 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo6_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def aurora(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo11_guid : PlanetSideGUID, ammo12_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo21_guid : PlanetSideGUID, ammo22_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
- Some(InventoryData(
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
+ Some(InventoryData(
InventoryItemData(ObjectClass.aurora_weapon_systema, weapon1_guid, 5,
WeaponData(0x6, 0x8, 0, ObjectClass.fluxpod_ammo, ammo11_guid, 0, AmmoBoxData(0x8))
) ::
@@ -112,11 +116,12 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.fluxpod_ammo, ammo21_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def battlewagon(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.battlewagon_weapon_systema, weapon1_guid, 5,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo1_guid, 0, AmmoBoxData(0x8))
@@ -131,11 +136,12 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo4_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def dropship(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.cannon_dropship_20mm, weapon1_guid, 12,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(8))
@@ -147,32 +153,35 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo3_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def flail(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID, terminal_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.flail_weapon, weapon_guid, 1,
WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, ammo_guid, 0, AmmoBoxData(8))
) ::
InventoryItemData(ObjectClass.targeting_laser_dispenser, terminal_guid, 2, CommonTerminalData(faction, 2)) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def fury(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.fury_weapon_systema, weapon_guid, 1,
WeaponData(0x4, 0x8, ObjectClass.hellfire_ammo, ammo_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def galaxy_gunship(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon4_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID, weapon5_guid : PlanetSideGUID, ammo5_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.galaxy_gunship_cannon, weapon1_guid, 6,
WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo1_guid, 0, AmmoBoxData(8))
@@ -190,11 +199,12 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo5_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def liberator(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo4_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.liberator_weapon_system, weapon1_guid, 3,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo1_guid, 0, AmmoBoxData(8))
@@ -206,31 +216,34 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_25mm, ammo4_guid, 0 ,AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def lightgunship(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.lightgunship_weapon_system, weapon_guid, 1,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.reaver_rocket, ammo2_guid,1, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def lightning(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.lightning_weapon_system, weapon_guid, 1,
WeaponData(0x4, 0x8, 0, ObjectClass.bullet_75mm, ammo1_guid, 0, AmmoBoxData(0x0), ObjectClass.bullet_12mm, ammo2_guid, 1, AmmoBoxData(0x0))
) :: Nil)
)
- )(VehicleFormat.Normal)
+ )
}
def lodestar(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, repair1_guid : PlanetSideGUID, repair2_guid : PlanetSideGUID, veh_rearm1_guid : PlanetSideGUID, veh_rearm2_guid : PlanetSideGUID, bfr_rearm1_guid : PlanetSideGUID, bfr_rearm2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0),
Some(InventoryData(List(
InternalSlot(ObjectClass.lodestar_repair_terminal, repair1_guid, 2, CommonTerminalData(faction, 2)),
InternalSlot(ObjectClass.lodestar_repair_terminal, repair2_guid, 3, CommonTerminalData(faction, 2)),
@@ -239,11 +252,12 @@ object Prefab {
InternalSlot(ObjectClass.bfr_rearm_terminal, bfr_rearm1_guid, 6, CommonTerminalData(faction, 2)),
InternalSlot(ObjectClass.bfr_rearm_terminal, bfr_rearm2_guid, 7, CommonTerminalData(faction, 2))
)))
- )(VehicleFormat.Variant)
+ )
}
def magrider(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.particle_beam_magrider, weapon1_guid, 2,
WeaponData(0x6, 0x8, 0, ObjectClass.pulse_battery, ammo1_guid, 0, AmmoBoxData(8))
@@ -252,11 +266,12 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.heavy_rail_beam_battery, ammo2_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def mediumtransport(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID): VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.mediumtransport_weapon_systemA, weapon1_guid, 5,
WeaponData(0x6, 0x8, ObjectClass.bullet_20mm, ammo1_guid, 0, AmmoBoxData(0x8))
@@ -265,25 +280,28 @@ object Prefab {
WeaponData(0x6, 0x8, ObjectClass.bullet_20mm, ammo2_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def mosquito(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.rotarychaingun_mosquito, weapon_guid, 1,
WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def phantasm(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), None)(VehicleFormat.Variant)
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)), None)(VehicleFormat.Variant)
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0), None)
}
def prowler(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.prowler_weapon_systemA, weapon1_guid, 3,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_105mm, ammo1_guid, 0, AmmoBoxData(8))
@@ -292,53 +310,59 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_15mm, ammo2_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def quadassault(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.quadassault_weapon_system, weapon_guid, 1,
WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def quadstealth(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, false, false, false, None, None)(VehicleFormat.Normal)
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, false, false, false, None, None)(VehicleFormat.Normal)
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, None)
}
def router(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, terminal_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.Mobile, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.teleportpad_terminal, terminal_guid, 1, CommonTerminalData(faction, 2)) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def skyguard(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.skyguard_weapon_system, weapon_guid, 2,
WeaponData(0x6, 0x8, 0, ObjectClass.skyguard_flak_cannon_ammo, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.bullet_12mm, ammo2_guid, 1, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def switchblade(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, driveState : DriveState.Value, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.scythe, weapon_guid, 1,
WeaponData(0x6, 0x8, 0, ObjectClass.ancient_ammo_vehicle, ammo1_guid, 0, AmmoBoxData(0x8), ObjectClass.ancient_ammo_vehicle, ammo2_guid, 1, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def threemanheavybuggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.chaingun_p, weapon1_guid, 3,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_12mm, ammo1_guid, 0, AmmoBoxData(0x8))
@@ -347,11 +371,12 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.heavy_grenade_mortar, ammo2_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def thunderer(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.thunderer_weapon_systema, weapon1_guid, 5,
WeaponData(0x6, 0x8, 0, ObjectClass.gauss_cannon_ammo, ammo1_guid, 0, AmmoBoxData(0x8))
@@ -360,51 +385,56 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.gauss_cannon_ammo, ammo2_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def two_man_assault_buggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.chaingun_p, weapon_guid, 2,
WeaponData(0x6, 0x8, ObjectClass.bullet_12mm, ammo_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def twomanheavybuggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.advanced_missile_launcher_t, weapon_guid, 2,
WeaponData(0x6, 0x8, 0, ObjectClass.firebird_missile, ammo_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def twomanhoverbuggy(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.flux_cannon_thresher, weapon_guid, 2,
WeaponData(0x6, 0x8, 0, ObjectClass.flux_cannon_thresher_battery, ammo_guid, 0, AmmoBoxData(0x8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def vanguard(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, None,
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false,
Some(InventoryData(
InventoryItemData(ObjectClass.vanguard_weapon_system, weapon_guid, 2,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_150mm, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.bullet_20mm, ammo2_guid, 1, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Normal)
+ )
}
def vulture(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon1_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, weapon2_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID, weapon3_guid : PlanetSideGUID, ammo3_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 2), 0, health, false, false, DriveState.State7, true, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 2), health, DriveState.State7, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.vulture_nose_weapon_system, weapon1_guid, 3,
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_35mm, ammo1_guid, 0, AmmoBoxData(8))
@@ -416,17 +446,18 @@ object Prefab {
WeaponData(0x6, 0x8, 0, ObjectClass.bullet_25mm, ammo3_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
def wasp(loc : PlacementData, faction : PlanetSideEmpire.Value, health : Int, weapon_guid : PlanetSideGUID, ammo1_guid : PlanetSideGUID, ammo2_guid : PlanetSideGUID) : VehicleData = {
- VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ //VehicleData(CommonFieldData(loc, faction, 0), 0, health, false, false, DriveState.Mobile, false, false, false, Some(VariantVehicleData(0)),
+ VehicleData(CommonFieldData(loc, faction, 0), health, DriveState.Mobile, false, VariantVehicleData(0),
Some(InventoryData(
InventoryItemData(ObjectClass.wasp_weapon_system, weapon_guid, 1,
WeaponData(0x6, 0x8, 0, ObjectClass.wasp_gun_ammo, ammo1_guid, 0, AmmoBoxData(8), ObjectClass.wasp_rocket_ammo, ammo2_guid, 0, AmmoBoxData(8))
) :: Nil
))
- )(VehicleFormat.Variant)
+ )
}
}
}
diff --git a/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala b/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala
index 77e29e4f..2d13c1e3 100644
--- a/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala
+++ b/common/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala
@@ -5,9 +5,9 @@ import net.psforever.packet.game.PlanetSideGUID
import net.psforever.packet.{Marshallable, PacketHelpers}
import scodec.Attempt.{Failure, Successful}
import scodec.{Attempt, Codec, Err}
-import shapeless.HNil
+import shapeless.HNil //note: do not import shapeless.:: here; it messes up List's :: function
import scodec.codecs._
-import net.psforever.types.DriveState
+import net.psforever.types.{DriveState, PlanetSideEmpire}
import scala.collection.mutable.ListBuffer
@@ -50,100 +50,103 @@ final case class VariantVehicleData(unk : Int) extends SpecificVehicleData {
}
/**
- * A representation of a generic vehicle.
- *
- * Vehicles utilize their own packet to communicate position to the server, known as `VehicleStateMessage`.
- * This takes the place of `PlayerStateMessageUpstream` when the player avatar is in control;
- * and, it takes the place of `PlayerStateMessage` for other players when they are in control.
- * If the vehicle is sufficiently complicated, a `ChildObjectStateMessage` will be used.
- * This packet will control any turret(s) on the vehicle.
- * For very complicated vehicles, the packets `FrameVehicleStateMessage` and `VehicleSubStateMessage` will also be employed.
- * The tasks that these packets perform are different based on the vehicle that responds or generates them.
- * @param basic data common to objects
+ * A representation of a generic vehicle.
+ * @param pos where the vehicle is and how it is oriented in the game world
+ * @param faction the faction that is aligned with this vehicle
+ * @param bops this vehicle belongs to the Black Ops, regardless of the faction field;
+ * activates the green camo and adjusts permissions
+ * @param destroyed this vehicle has ben destroyed;
+ * it's health should be less than 3/255, or 0%
* @param unk1 na
- * @param health the amount of health the vehicle has, as a percentage of a filled bar (255)
+ * @param jammered this vehicle is under the influence of a jammer grenade
* @param unk2 na
+ * @param owner_guid the vehicle's (official) owner;
+ * verified as a living player in the game world on the same continent as the vehicle;
+ * sitting in the driver's seat or a `PlanetSideAttributeMessage` of type 21 can influence
+ * @param unk3 na
+ * @param health the amount of health the vehicle has, as a percentage of a filled bar (255)
+ * @param unk4 na
* @param no_mount_points do not display entry points for the seats
* @param driveState a representation for the current mobility state;
- * various vehicles also use this field to indicate "deployment," e.g., AMS
- * @param unk3 na
+ * various vehicles also use this field to indicate "deployment," e.g., the advanced mobile spawn
* @param unk5 na
- * @param cloak if a cloakable vehicle is cloaked
- * @param unk4 na
+ * @param unk6 na
+ * @param cloak if a vehicle (that can cloak) is cloaked
+ * @param vehicle_format_data extra information necessary to implement special-type vehicles;
+ * see `vehicle_type`
* @param inventory the seats, mounted weapons, and utilities (such as terminals) that are currently included;
- * will also include trunk contents
+ * will also include trunk contents;
+ * the driver is the only valid seat entry (more will cause the access permissions to act up)
* @param vehicle_type a modifier for parsing the vehicle data format differently;
+ * see `vehicle_format_data`;
* defaults to `Normal`
*/
-final case class VehicleData(basic : CommonFieldData,
+final case class VehicleData(pos : PlacementData,
+ faction : PlanetSideEmpire.Value,
+ bops : Boolean,
+ destroyed : Boolean,
unk1 : Int,
- health : Int,
+ jammered : Boolean,
unk2 : Boolean,
+ owner_guid : PlanetSideGUID,
+ unk3 : Boolean,
+ health : Int,
+ unk4 : Boolean,
no_mount_points : Boolean,
driveState : DriveState.Value,
- unk3 : Boolean,
unk5 : Boolean,
+ unk6 : Boolean,
cloak : Boolean,
- unk4 : Option[SpecificVehicleData],
- inventory : Option[InventoryData] = None
- )(val vehicle_type : VehicleFormat.Value = VehicleFormat.Normal) extends ConstructorData {
+ vehicle_format_data : Option[SpecificVehicleData],
+ inventory : Option[InventoryData] = None)
+ (val vehicle_type : VehicleFormat.Value = VehicleFormat.Normal) extends ConstructorData {
override def bitsize : Long = {
- val basicSize = basic.bitsize
- val extraBitsSize : Long = if(unk4.isDefined) { unk4.get.bitsize } else { 0L }
+ //factor guard bool values into the base size, not its corresponding optional field
+ val posSize : Long = pos.bitsize
+ val extraBitsSize : Long = if(vehicle_format_data.isDefined) { vehicle_format_data.get.bitsize } else { 0L }
val inventorySize = if(inventory.isDefined) { inventory.get.bitsize } else { 0L }
- 24L + basicSize + extraBitsSize + inventorySize
+ 47L + posSize + extraBitsSize + inventorySize
}
}
object VehicleData extends Marshallable[VehicleData] {
/**
* Overloaded constructor for specifically handling `Normal` vehicle format.
- * @param basic data common to objects
- * @param unk1 na
+ * @param basic a field that encompasses some data used by the vehicle, including `faction` and `owner`
* @param health the amount of health the vehicle has, as a percentage of a filled bar (255)
- * @param unk2 na
- * @param driveState a representation for the current mobility state;
- * @param unk3 na
- * @param unk4 na
+ * @param driveState a representation for the current mobility state
+ * @param cloak if a vehicle (that can cloak) is cloaked
* @param inventory the seats, mounted weapons, and utilities (such as terminals) that are currently included
- * @return a `VehicleData` object
*/
- def apply(basic : CommonFieldData, unk1 : Int, health : Int, unk2 : Int, driveState : DriveState.Value, unk3 : Boolean, unk4 : Int, inventory : Option[InventoryData]) : VehicleData = {
- new VehicleData(basic, unk1, health, unk2>0, false, driveState, unk3, unk4>0, false, None, inventory)(VehicleFormat.Normal)
+ def apply(basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, inventory : Option[InventoryData]) : VehicleData = {
+ VehicleData(basic.pos, basic.faction, basic.bops, basic.destroyed, 0, basic.jammered, false, basic.player_guid,
+ false, health, false, false, driveState, false, false, cloak, None, inventory)(VehicleFormat.Normal)
}
/**
* Overloaded constructor for specifically handling `Utility` vehicle format.
- * @param basic data common to objects
- * @param unk1 na
+ * @param basic a field that encompasses some data used by the vehicle, including `faction` and `owner`
* @param health the amount of health the vehicle has, as a percentage of a filled bar (255)
- * @param unk2 na
- * @param driveState a representation for the current mobility state;
- * @param unk3 na
- * @param unk4 utility-specific field
- * @param unk5 na
+ * @param driveState a representation for the current mobility state
+ * @param cloak if a vehicle (that can cloak) is cloaked
* @param inventory the seats, mounted weapons, and utilities (such as terminals) that are currently included
- * @return a `VehicleData` object
*/
- def apply(basic : CommonFieldData, unk1 : Int, health : Int, unk2 : Int, driveState : DriveState.Value, unk3 : Boolean, unk4 : UtilityVehicleData, unk5 : Int, inventory : Option[InventoryData]) : VehicleData = {
- new VehicleData(basic, unk1, health, unk2>0, false, driveState, unk3, unk5>0, false, Some(unk4), inventory)(VehicleFormat.Utility)
+ def apply(basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, format : UtilityVehicleData, inventory : Option[InventoryData]) : VehicleData = {
+ VehicleData(basic.pos, basic.faction, basic.bops, basic.destroyed, 0, basic.jammered, false, basic.player_guid,
+ false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(VehicleFormat.Utility)
}
/**
* Overloaded constructor for specifically handling `Variant` vehicle format.
- * @param basic data common to objects
- * @param unk1 na
+ * @param basic a field that encompasses some data used by the vehicle, including `faction` and `owner`
* @param health the amount of health the vehicle has, as a percentage of a filled bar (255)
- * @param unk2 na
- * @param driveState a representation for the current mobility state;
- * @param unk3 na
- * @param unk4 variant-specific field
- * @param unk5 na
+ * @param driveState a representation for the current mobility state
+ * @param cloak if a vehicle (that can cloak) is cloaked
* @param inventory the seats, mounted weapons, and utilities (such as terminals) that are currently included
- * @return a `VehicleData` object
*/
- def apply(basic : CommonFieldData, unk1 : Int, health : Int, unk2 : Int, driveState : DriveState.Value, unk3 : Boolean, unk4 : VariantVehicleData, unk5 : Int, inventory : Option[InventoryData]) : VehicleData = {
- new VehicleData(basic, unk1, health, unk2>0, false, driveState, unk3, unk5>0, false, Some(unk4), inventory)(VehicleFormat.Variant)
+ def apply(basic : CommonFieldData, health : Int, driveState : DriveState.Value, cloak : Boolean, format : VariantVehicleData, inventory : Option[InventoryData]) : VehicleData = {
+ VehicleData(basic.pos, basic.faction, basic.bops, basic.destroyed, 0, basic.jammered, false, basic.player_guid,
+ false, health, false, false, driveState, false, false, cloak, Some(format), inventory)(VehicleFormat.Variant)
}
import net.psforever.packet.game.objectcreate.{PlayerData => Player_Data}
@@ -237,41 +240,43 @@ object VehicleData extends Marshallable[VehicleData] {
def codec(vehicle_type : VehicleFormat.Value) : Codec[VehicleData] = {
import shapeless.::
(
- ("basic" | CommonFieldData.codec) >>:~ { com =>
- ("unk1" | uint2L) ::
+ ("pos" | PlacementData.codec) >>:~ { pos =>
+ ("faction" | PlanetSideEmpire.codec) ::
+ ("bops" | bool) ::
+ ("destroyed" | bool) ::
+ ("unk1" | uint2L) :: //3 - na, 2 - common, 1 - na, 0 - common?
+ ("jammered" | bool) ::
+ ("unk2" | bool) ::
+ ("owner_guid" | PlanetSideGUID.codec) ::
+ ("unk3" | bool) ::
("health" | uint8L) ::
- ("unk2" | bool) :: //usually 0
+ ("unk4" | bool) :: //usually 0
("no_mount_points" | bool) ::
("driveState" | driveState8u) :: //used for deploy state
- ("unk3" | bool) :: //unknown but generally false; can cause stream misalignment if set when unexpectedly
- ("unk4" | bool) ::
+ ("unk5" | bool) :: //unknown but generally false; can cause stream misalignment if set when unexpectedly
+ ("unk6" | bool) ::
("cloak" | bool) :: //cloak as wraith, phantasm
- conditional(vehicle_type != VehicleFormat.Normal, "unk5" | selectFormatReader(vehicle_type)) :: //padding?
- optional(bool, "inventory" | custom_inventory_codec(InitialStreamLengthToSeatEntries(com.pos.vel.isDefined, vehicle_type)))
+ conditional(vehicle_type != VehicleFormat.Normal, "vehicle_format_data" | selectFormatReader(vehicle_type)) :: //padding?
+ optional(bool, "inventory" | custom_inventory_codec(InitialStreamLengthToSeatEntries(pos.vel.isDefined, vehicle_type)))
}
).exmap[VehicleData] (
{
- case basic :: u1 :: health :: u2 :: no_mount :: driveState :: u3 :: u4 :: u5 :: cloak :: inv :: HNil =>
- Attempt.successful(new VehicleData(basic, u1, health, u2, no_mount, driveState, u3, u4, u5, cloak, inv)(vehicle_type))
+ case pos :: faction :: bops :: destroyed :: u1 :: jamd :: u2 :: owner :: u3 :: health :: u4 :: no_mount :: driveState :: u5 :: u6 :: cloak :: format :: inv :: HNil =>
+ Attempt.successful(new VehicleData(pos, faction, bops, destroyed, u1, jamd, u2, owner, u3, health, u4, no_mount, driveState, u5, u6, cloak, format, inv)(vehicle_type))
case _ =>
Attempt.failure(Err("invalid vehicle data format"))
},
{
- case obj @ VehicleData(basic, u1, health, u2, no_mount, driveState, u3, u4, cloak, Some(u5), inv) =>
- if(obj.vehicle_type == VehicleFormat.Normal) {
- Attempt.failure(Err("invalid vehicle data format; variable bits not expected; will ignore ..."))
+ case obj @ VehicleData(pos, faction, bops, destroyed, u1, jamd, u2, owner, u3, health, u4, no_mount, driveState, u5, u6, cloak, format, inv) =>
+ if(obj.vehicle_type == VehicleFormat.Normal && format.nonEmpty) {
+ Attempt.failure(Err("invalid vehicle data format; variable bits not expected"))
+ }
+ else if(obj.vehicle_type != VehicleFormat.Normal && format.isEmpty) {
+ Attempt.failure(Err(s"invalid vehicle data format; variable bits for ${obj.vehicle_type} expected"))
}
else {
- Attempt.successful(basic :: u1 :: health :: u2 :: no_mount :: driveState :: u3 :: u4 :: cloak :: Some(u5) :: inv :: HNil)
- }
-
- case obj @ VehicleData(basic, u1, health, u2, no_mount, driveState, u3, u4, cloak, None, inv) =>
- if(obj.vehicle_type != VehicleFormat.Normal) {
- Attempt.failure(Err("invalid vehicle data format; variable bits expected"))
- }
- else {
- Attempt.successful(basic :: u1 :: health :: u2 :: no_mount :: driveState :: u3 :: u4 :: cloak :: None :: inv :: HNil)
+ Attempt.successful(pos :: faction :: bops :: destroyed :: u1 :: jamd :: u2 :: owner :: u3 :: health :: u4 :: no_mount :: driveState :: u5 :: u6 :: cloak :: format :: inv :: HNil)
}
case _ =>
@@ -284,7 +289,11 @@ object VehicleData extends Marshallable[VehicleData] {
* Distance from the length field of a vehicle creation packet up until the start of the vehicle's inventory data.
* The only field excluded belongs to the original opcode for the packet.
* The parameters outline reasons why the length of the stream would be different
- * and are used to determine the exact difference value.
+ * and are used to determine the exact difference value.
+ * Note:
+ * 198 includes the `ObjectCreateMessage` packet fields, without parent data,
+ * the `VehicleData` fields,
+ * and the first three fields of the `InternalSlot`.
* @see `ObjectCreateMessage`
* @param hasVelocity the presence of a velocity field - `vel` - in the `PlacementData` object for this vehicle
* @param format the `Codec` subtype for this vehicle
@@ -333,7 +342,9 @@ object VehicleData extends Marshallable[VehicleData] {
}
/**
- * A special method of handling mounted players within the same inventory space as normal `Equipment` can be encountered.
+ * A special method of handling mounted players within the same inventory space as normal `Equipment` can be encountered
+ * before restoring normal inventory operations.
+ *
* Due to variable-length fields within `PlayerData` extracted from the input,
* the distance of the bit(stream) vector to the initial inventory entry is calculated
* to produce the initial value for padding the `PlayerData` object's name field.
@@ -341,7 +352,11 @@ object VehicleData extends Marshallable[VehicleData] {
* the remainder of the inventory must be handled as standard inventory
* and finally both groups must be repackaged into a single standard `InventoryData` object.
* Due to the unique value for the mounted players that must be updated for each entry processed,
- * the entries are temporarily formatted into a linked list before being put back into a normal `List`.
+ * the entries are temporarily formatted into a linked list before being put back into a normal `List`.
+ *
+ * 6 June 2018:
+ * Due to curious behavior in the vehicle seat access controls,
+ * please only encode and decode the driver seat even though all seats are currently reachable.
* @param length the distance in bits to the first inventory entry
* @return a `Codec` that translates `InventoryData`
*/
@@ -512,7 +527,7 @@ object VehicleData extends Marshallable[VehicleData] {
case x :: Nil =>
Some(InventorySeat(Some(x), None))
case _ :: _ =>
- var link = InventorySeat(Some(list.last), None)
+ var link = InventorySeat(Some(list.last), None) //build the chain in reverse order, starting with the last entry
list.reverse.drop(1).foreach(seat => {
link = InventorySeat(Some(seat), Some(link))
})
diff --git a/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala b/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala
index 188f762f..9f573970 100644
--- a/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala
+++ b/common/src/test/scala/game/objectcreatedetailed/DetailedCharacterDataTest.scala
@@ -503,18 +503,12 @@ class DetailedCharacterDataTest extends Specification {
Nil
)
val obj = DetailedPlayerData.apply(app, char, inv, DrawnSlot.Pistol1)
+ //it shouldn't be Pistol1 if he's seated but it's fine for the test
val msg = ObjectCreateDetailedMessage(0x79, PlanetSideGUID(75), ObjectCreateMessageParent(PlanetSideGUID(43981), 0), obj)
val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
val pkt_bitv = pkt.toBitVector
val ori_bitv = string_seated.toBitVector
-// var test = pkt_bitv
-// while(test.nonEmpty) {
-// val (printHex, save) = test.splitAt(512)
-// test = save
-// println(printHex)
-// }
- pkt_bitv.take(16) mustEqual ori_bitv.take(16)
pkt_bitv mustEqual ori_bitv
}
diff --git a/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala
index fe51669f..84b243c7 100644
--- a/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala
+++ b/common/src/test/scala/game/objectcreatevehicle/DestroyedVehiclesTest.scala
@@ -4,7 +4,6 @@ package game.objectcreatevehicle
import net.psforever.packet._
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID}
import net.psforever.packet.game.objectcreate._
-import net.psforever.types._
import org.specs2.mutable._
import scodec.bits._
diff --git a/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala
index eb15db39..393bf678 100644
--- a/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala
+++ b/common/src/test/scala/game/objectcreatevehicle/MountedVehiclesTest.scala
@@ -25,23 +25,25 @@ class MountedVehiclesTest extends Specification {
parent mustEqual None
data match {
case Some(vdata : VehicleData) =>
- vdata.basic.pos.coord mustEqual Vector3(4571.6875f, 5602.1875f, 93)
- vdata.basic.pos.orient mustEqual Vector3(11.25f, 2.8125f, 92.8125f)
- vdata.basic.pos.vel mustEqual Some(Vector3(31.71875f, 8.875f, -0.03125f))
- vdata.basic.faction mustEqual PlanetSideEmpire.TR
- vdata.basic.bops mustEqual false
- vdata.basic.destroyed mustEqual false
- vdata.basic.jammered mustEqual false
- vdata.basic.player_guid mustEqual PlanetSideGUID(1888)
- vdata.unk1 mustEqual 0
+ vdata.pos.coord mustEqual Vector3(4571.6875f, 5602.1875f, 93)
+ vdata.pos.orient mustEqual Vector3(11.25f, 2.8125f, 92.8125f)
+ vdata.pos.vel mustEqual Some(Vector3(31.71875f, 8.875f, -0.03125f))
+ vdata.faction mustEqual PlanetSideEmpire.TR
+ vdata.bops mustEqual false
+ vdata.destroyed mustEqual false
+ vdata.jammered mustEqual false
+ vdata.owner_guid mustEqual PlanetSideGUID(3776)
vdata.health mustEqual 255
- vdata.unk2 mustEqual false
vdata.no_mount_points mustEqual false
vdata.driveState mustEqual DriveState.Mobile
- vdata.unk3 mustEqual false
- vdata.unk5 mustEqual false
vdata.cloak mustEqual false
- vdata.unk4 mustEqual Some(VariantVehicleData(7))
+ vdata.unk1 mustEqual 0
+ vdata.unk2 mustEqual false
+ vdata.unk3 mustEqual false
+ vdata.unk4 mustEqual false
+ vdata.unk5 mustEqual false
+ vdata.unk6 mustEqual false
+ vdata.vehicle_format_data mustEqual Some(VariantVehicleData(7))
vdata.inventory match {
case Some(InventoryData(list)) =>
list.head.objectClass mustEqual ObjectClass.avatar
@@ -147,17 +149,18 @@ class MountedVehiclesTest extends Specification {
)
val player = VehicleData.PlayerData(app, char, inv, DrawnSlot.None, VehicleData.InitialStreamLengthToSeatEntries(true, VehicleFormat.Variant))
val obj = VehicleData(
- CommonFieldData(
- PlacementData(
- Vector3(4571.6875f, 5602.1875f, 93),
- Vector3(11.25f, 2.8125f, 92.8125f),
- Some(Vector3(31.71875f, 8.875f, -0.03125f))
- ),
- PlanetSideEmpire.TR,
- false, false, 0, false,
- PlanetSideGUID(1888)
+ PlacementData(
+ Vector3(4571.6875f, 5602.1875f, 93),
+ Vector3(11.25f, 2.8125f, 92.8125f),
+ Some(Vector3(31.71875f, 8.875f, -0.03125f))
),
- 0, 255,
+ PlanetSideEmpire.TR,
+ false, false,
+ 0,
+ false, false,
+ PlanetSideGUID(3776),
+ false,
+ 255,
false, false,
DriveState.Mobile,
false, false, false,
diff --git a/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala
index 9dd75b48..5d537227 100644
--- a/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala
+++ b/common/src/test/scala/game/objectcreatevehicle/NormalVehiclesTest.scala
@@ -24,16 +24,12 @@ class NormalVehiclesTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val fury = data.get.asInstanceOf[VehicleData]
- fury.basic.pos.coord.x mustEqual 6531.961f
- fury.basic.pos.coord.y mustEqual 1872.1406f
- fury.basic.pos.coord.z mustEqual 24.734375f
- fury.basic.pos.orient.x mustEqual 0f
- fury.basic.pos.orient.y mustEqual 0f
- fury.basic.pos.orient.z mustEqual 357.1875f
- fury.basic.pos.vel.isDefined mustEqual false
- fury.basic.faction mustEqual PlanetSideEmpire.VS
- fury.basic.unk mustEqual 2
- fury.basic.player_guid mustEqual PlanetSideGUID(0)
+ fury.pos.coord mustEqual Vector3(6531.961f, 1872.1406f,24.734375f)
+ fury.pos.orient mustEqual Vector3(0, 0, 357.1875f)
+ fury.pos.vel mustEqual None
+ fury.faction mustEqual PlanetSideEmpire.VS
+ fury.unk1 mustEqual 2
+ fury.owner_guid mustEqual PlanetSideGUID(0)
fury.health mustEqual 255
//
fury.inventory.isDefined mustEqual true
@@ -69,16 +65,14 @@ class NormalVehiclesTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val lightning = data.get.asInstanceOf[VehicleData]
- lightning.basic.pos.coord.x mustEqual 3674.8438f
- lightning.basic.pos.coord.y mustEqual 2726.789f
- lightning.basic.pos.coord.z mustEqual 91.15625f
- lightning.basic.pos.orient.x mustEqual 0f
- lightning.basic.pos.orient.y mustEqual 0f
- lightning.basic.pos.orient.z mustEqual 90.0f
- lightning.basic.faction mustEqual PlanetSideEmpire.VS
- lightning.basic.unk mustEqual 2
- lightning.basic.player_guid mustEqual PlanetSideGUID(0)
+ lightning.pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f)
+ lightning.pos.orient mustEqual Vector3(0, 0, 90)
+ lightning.pos.vel mustEqual None
+ lightning.faction mustEqual PlanetSideEmpire.VS
+ lightning.unk1 mustEqual 2
+ lightning.owner_guid mustEqual PlanetSideGUID(0)
lightning.health mustEqual 255
+
lightning.inventory.isDefined mustEqual true
lightning.inventory.get.contents.size mustEqual 1
val mounting = lightning.inventory.get.contents.head
@@ -120,22 +114,23 @@ class NormalVehiclesTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val deliverer = data.get.asInstanceOf[VehicleData]
- deliverer.basic.pos.coord.x mustEqual 6531.961f
- deliverer.basic.pos.coord.y mustEqual 1872.1406f
- deliverer.basic.pos.coord.z mustEqual 24.734375f
- deliverer.basic.pos.orient.x mustEqual 0f
- deliverer.basic.pos.orient.y mustEqual 0f
- deliverer.basic.pos.orient.z mustEqual 357.1875f
- deliverer.basic.faction mustEqual PlanetSideEmpire.NC
- deliverer.basic.unk mustEqual 2
- deliverer.basic.player_guid mustEqual PlanetSideGUID(0)
- deliverer.unk1 mustEqual 0
+ deliverer.pos.coord mustEqual Vector3(6531.961f, 1872.1406f, 24.734375f)
+ deliverer.pos.orient mustEqual Vector3(0, 0, 357.1875f)
+ deliverer.pos.vel mustEqual None
+ deliverer.faction mustEqual PlanetSideEmpire.NC
+ deliverer.owner_guid mustEqual PlanetSideGUID(0)
deliverer.health mustEqual 255
- deliverer.unk2 mustEqual false
deliverer.driveState mustEqual DriveState.State7
- deliverer.unk3 mustEqual true
- deliverer.unk4 mustEqual None
- deliverer.unk5 mustEqual false
+ deliverer.jammered mustEqual false
+ deliverer.destroyed mustEqual false
+ deliverer.cloak mustEqual false
+ deliverer.unk1 mustEqual 2
+ deliverer.unk2 mustEqual false
+ deliverer.unk3 mustEqual false
+ deliverer.unk4 mustEqual false
+ deliverer.unk5 mustEqual true
+ deliverer.unk6 mustEqual false
+ deliverer.vehicle_format_data mustEqual None
deliverer.inventory.isDefined mustEqual true
deliverer.inventory.get.contents.size mustEqual 2
//0
@@ -179,11 +174,13 @@ class NormalVehiclesTest extends Specification {
"encode (fury)" in {
val obj = VehicleData(
- CommonFieldData(
- PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
- PlanetSideEmpire.VS, 2
- ),
- 0,
+ PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
+ PlanetSideEmpire.VS,
+ false, false,
+ 2,
+ false, false,
+ PlanetSideGUID(0),
+ false,
255,
false, false,
DriveState.Mobile,
@@ -203,11 +200,13 @@ class NormalVehiclesTest extends Specification {
"encode (lightning)" in {
val obj = VehicleData(
- CommonFieldData(
- PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
- PlanetSideEmpire.VS, 2
- ),
- 0,
+ PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
+ PlanetSideEmpire.VS,
+ false, false,
+ 2,
+ false, false,
+ PlanetSideGUID(0),
+ false,
255,
false, false,
DriveState.Mobile,
@@ -227,11 +226,13 @@ class NormalVehiclesTest extends Specification {
"encode (medium transport)" in {
val obj = VehicleData(
- CommonFieldData(
- PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
- PlanetSideEmpire.NC, 2
- ),
- 0,
+ PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
+ PlanetSideEmpire.NC,
+ false, false,
+ 2,
+ false, false,
+ PlanetSideGUID(0),
+ false,
255,
false, false,
DriveState.State7,
diff --git a/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala
index 02f43faf..0c081a16 100644
--- a/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala
+++ b/common/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala
@@ -11,120 +11,122 @@ import scodec.bits._
class UtilityVehiclesTest extends Specification {
val string_ant = hex"17 C2000000 9E0 7C01 6C2D7 65535 CA16 00 00 00 4400003FC000000"
val string_ams = hex"17 B8010000 970 3D10 002D765535CA16000000 402285BB0037E4100749E1D03000000620D83A0A00000195798741C00000332E40D84800000"
- val string_ams_seated =
- hex"17ec060000970fe0f030898abda28127f007ff9c1f2f80c0001e18ff00001051e40786400000008c50004c0041006d0069006e006700790075006500540052007c00000304217c859e8080000000000000002503420022c02a002a002a002a0050004c0041002a002a002a002a00010027e300940000016c0400023c040002285a086c2f00c80000000000300210288740800000004046f17423018000002c4d6190400000001010704a86406000002bc770842000000004041c5f21d01800000e075821902000000623e84208000001950588c1800000332ea0f840000000"
+// val string_ams_seated =
+// hex"17ec060000970fe0f030898abda28127f007ff9c1f2f80c0001e18ff00001051e40786400000008c50004c0041006d0069006e006700790075006500540052007c00000304217c859e8080000000000000002503420022c02a002a002a002a0050004c0041002a002a002a002a00010027e300940000016c0400023c040002285a086c2f00c80000000000300210288740800000004046f17423018000002c4d6190400000001010704a86406000002bc770842000000004041c5f21d01800000e075821902000000623e84208000001950588c1800000332ea0f840000000"
"Utility vehicles" should {
-// "decode (ant)" in {
-// PacketCoding.DecodePacket(string_ant).require match {
-// case ObjectCreateMessage(len, cls, guid, parent, data) =>
-// len mustEqual 194L
-// cls mustEqual ObjectClass.ant
-// guid mustEqual PlanetSideGUID(380)
-// parent.isDefined mustEqual false
-// data.isDefined mustEqual true
-// data.get.isInstanceOf[VehicleData] mustEqual true
-// val ant = data.get.asInstanceOf[VehicleData]
-// ant.basic.pos.coord.x mustEqual 3674.8438f
-// ant.basic.pos.coord.y mustEqual 2726.789f
-// ant.basic.pos.coord.z mustEqual 91.15625f
-// ant.basic.pos.orient.x mustEqual 0f
-// ant.basic.pos.orient.y mustEqual 0f
-// ant.basic.pos.orient.z mustEqual 90.0f
-// ant.basic.faction mustEqual PlanetSideEmpire.VS
-// ant.basic.unk mustEqual 2
-// ant.basic.player_guid mustEqual PlanetSideGUID(0)
-// ant.health mustEqual 255
-// ant.driveState mustEqual DriveState.Mobile
-// case _ =>
-// ko
-// }
-// }
-//
-// "decode (ams)" in {
-// PacketCoding.DecodePacket(string_ams).require match {
-// case ObjectCreateMessage(len, cls, guid, parent, data) =>
-// len mustEqual 440L
-// cls mustEqual ObjectClass.ams
-// guid mustEqual PlanetSideGUID(4157)
-// parent.isDefined mustEqual false
-// data.isDefined mustEqual true
-// data.get.isInstanceOf[VehicleData] mustEqual true
-// val ams = data.get.asInstanceOf[VehicleData]
-// ams.basic.pos.coord.x mustEqual 3674.0f
-// ams.basic.pos.coord.y mustEqual 2726.789f
-// ams.basic.pos.coord.z mustEqual 91.15625f
-// ams.basic.pos.orient.x mustEqual 0f
-// ams.basic.pos.orient.y mustEqual 0f
-// ams.basic.pos.orient.z mustEqual 90.0f
-// ams.basic.faction mustEqual PlanetSideEmpire.VS
-// ams.basic.unk mustEqual 0
-// ams.basic.player_guid mustEqual PlanetSideGUID(34082)
-// ams.unk1 mustEqual 2
-// ams.health mustEqual 236
-// ams.unk2 mustEqual false
-// ams.driveState mustEqual DriveState.Deployed
-//
-// ams.inventory.isDefined mustEqual true
-// val inv = ams.inventory.get.contents
-// inv.head.objectClass mustEqual ObjectClass.matrix_terminalc
-// inv.head.guid mustEqual PlanetSideGUID(3663)
-// inv.head.parentSlot mustEqual 1
-// inv.head.obj.isInstanceOf[CommonTerminalData] mustEqual true
-// inv(1).objectClass mustEqual ObjectClass.ams_respawn_tube
-// inv(1).guid mustEqual PlanetSideGUID(3638)
-// inv(1).parentSlot mustEqual 2
-// inv(1).obj.isInstanceOf[CommonTerminalData] mustEqual true
-// inv(2).objectClass mustEqual ObjectClass.order_terminala
-// inv(2).guid mustEqual PlanetSideGUID(3827)
-// inv(2).parentSlot mustEqual 3
-// inv(2).obj.isInstanceOf[CommonTerminalData] mustEqual true
-// inv(3).objectClass mustEqual ObjectClass.order_terminalb
-// inv(3).guid mustEqual PlanetSideGUID(3556)
-// inv(3).parentSlot mustEqual 4
-// inv(3).obj.isInstanceOf[CommonTerminalData] mustEqual true
-// case _ =>
-// ko
-// }
-// }
-//
- "decode (ams, seated)" in {
- PacketCoding.DecodePacket(string_ams_seated).require match {
+ "decode (ant)" in {
+ PacketCoding.DecodePacket(string_ant).require match {
case ObjectCreateMessage(len, cls, guid, parent, data) =>
+ len mustEqual 194L
+ cls mustEqual ObjectClass.ant
+ guid mustEqual PlanetSideGUID(380)
+ parent.isDefined mustEqual false
data.isDefined mustEqual true
+ data.get.isInstanceOf[VehicleData] mustEqual true
+ val ant = data.get.asInstanceOf[VehicleData]
+ ant.pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f)
+ ant.pos.orient mustEqual Vector3(0, 0, 90)
+ ant.faction mustEqual PlanetSideEmpire.VS
+ ant.owner_guid mustEqual PlanetSideGUID(0)
+ ant.driveState mustEqual DriveState.Mobile
+ ant.health mustEqual 255
+ ant.jammered mustEqual false
+ ant.destroyed mustEqual false
+ ant.cloak mustEqual false
+ ant.unk1 mustEqual 2
+ ant.unk2 mustEqual false
+ ant.unk3 mustEqual false
+ ant.unk4 mustEqual false
+ ant.unk5 mustEqual false
+ ant.unk6 mustEqual false
case _ =>
ko
}
}
-//
-// "encode (ant)" in {
-// val obj = VehicleData(
-// CommonFieldData(
-// PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
-// PlanetSideEmpire.VS, 2
-// ),
-// 0,
-// 255,
-// false, false,
-// DriveState.Mobile,
-// false, false, false,
-// Some(UtilityVehicleData(0)),
-// None
-// )(VehicleFormat.Utility)
-// val msg = ObjectCreateMessage(ObjectClass.ant, PlanetSideGUID(380), obj)
-// val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
-//
-// pkt mustEqual string_ant
-// }
+
+ "decode (ams)" in {
+ PacketCoding.DecodePacket(string_ams).require match {
+ case ObjectCreateMessage(len, cls, guid, parent, data) =>
+ len mustEqual 440L
+ cls mustEqual ObjectClass.ams
+ guid mustEqual PlanetSideGUID(4157)
+ parent.isDefined mustEqual false
+ data.isDefined mustEqual true
+ data.get.isInstanceOf[VehicleData] mustEqual true
+ val ams = data.get.asInstanceOf[VehicleData]
+ ams.pos.coord mustEqual Vector3(3674, 2726.789f, 91.15625f)
+ ams.pos.orient mustEqual Vector3(0, 0, 90)
+ ams.pos.vel mustEqual None
+ ams.faction mustEqual PlanetSideEmpire.VS
+ ams.owner_guid mustEqual PlanetSideGUID(2885)
+ ams.driveState mustEqual DriveState.Deployed
+ ams.vehicle_format_data mustEqual Some(UtilityVehicleData(60))
+ ams.health mustEqual 236
+ ams.jammered mustEqual false
+ ams.destroyed mustEqual false
+ ams.cloak mustEqual true
+ ams.unk1 mustEqual 0
+ ams.unk2 mustEqual false
+ ams.unk3 mustEqual false
+ ams.unk4 mustEqual false
+ ams.unk5 mustEqual false
+ ams.unk6 mustEqual true
+
+ ams.inventory.isDefined mustEqual true
+ val inv = ams.inventory.get.contents
+ inv.head.objectClass mustEqual ObjectClass.matrix_terminalc
+ inv.head.guid mustEqual PlanetSideGUID(3663)
+ inv.head.parentSlot mustEqual 1
+ inv.head.obj.isInstanceOf[CommonTerminalData] mustEqual true
+ inv(1).objectClass mustEqual ObjectClass.ams_respawn_tube
+ inv(1).guid mustEqual PlanetSideGUID(3638)
+ inv(1).parentSlot mustEqual 2
+ inv(1).obj.isInstanceOf[CommonTerminalData] mustEqual true
+ inv(2).objectClass mustEqual ObjectClass.order_terminala
+ inv(2).guid mustEqual PlanetSideGUID(3827)
+ inv(2).parentSlot mustEqual 3
+ inv(2).obj.isInstanceOf[CommonTerminalData] mustEqual true
+ inv(3).objectClass mustEqual ObjectClass.order_terminalb
+ inv(3).guid mustEqual PlanetSideGUID(3556)
+ inv(3).parentSlot mustEqual 4
+ inv(3).obj.isInstanceOf[CommonTerminalData] mustEqual true
+ case _ =>
+ ko
+ }
+ }
+
+ "encode (ant)" in {
+ val obj = VehicleData(
+ PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
+ PlanetSideEmpire.VS,
+ false, false,
+ 2,
+ false, false,
+ PlanetSideGUID(0),
+ false,
+ 255,
+ false, false,
+ DriveState.Mobile,
+ false, false, false,
+ Some(UtilityVehicleData(0)),
+ None
+ )(VehicleFormat.Utility)
+ val msg = ObjectCreateMessage(ObjectClass.ant, PlanetSideGUID(380), obj)
+ val pkt = PacketCoding.EncodePacket(msg).require.toByteVector
+
+ pkt mustEqual string_ant
+ }
"encode (ams)" in {
val obj = VehicleData(
- CommonFieldData(
- PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
- PlanetSideEmpire.VS, 0,
- PlanetSideGUID(34082)
- ),
- 2,
+ PlacementData(3674.0f, 2726.789f, 91.15625f, 0f, 0f, 90.0f),
+ PlanetSideEmpire.VS,
+ false, false,
+ 0,
+ false, false,
+ PlanetSideGUID(2885),
+ false,
236,
false, false,
DriveState.Deployed,
diff --git a/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala b/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala
index c1203d6c..5924cda1 100644
--- a/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala
+++ b/common/src/test/scala/game/objectcreatevehicle/VariantVehiclesTest.scala
@@ -22,14 +22,14 @@ class VariantVehiclesTest extends Specification {
data.isDefined mustEqual true
data.get.isInstanceOf[VehicleData] mustEqual true
val switchblade = data.get.asInstanceOf[VehicleData]
- switchblade.basic.pos.coord.x mustEqual 6531.961f
- switchblade.basic.pos.coord.y mustEqual 1872.1406f
- switchblade.basic.pos.coord.z mustEqual 24.734375f
- switchblade.basic.pos.orient.x mustEqual 0f
- switchblade.basic.pos.orient.y mustEqual 0f
- switchblade.basic.pos.orient.z mustEqual 357.1875f
- switchblade.basic.faction mustEqual PlanetSideEmpire.VS
- switchblade.basic.unk mustEqual 2
+ switchblade.pos.coord.x mustEqual 6531.961f
+ switchblade.pos.coord.y mustEqual 1872.1406f
+ switchblade.pos.coord.z mustEqual 24.734375f
+ switchblade.pos.orient.x mustEqual 0f
+ switchblade.pos.orient.y mustEqual 0f
+ switchblade.pos.orient.z mustEqual 357.1875f
+ switchblade.faction mustEqual PlanetSideEmpire.VS
+ switchblade.unk1 mustEqual 2
switchblade.health mustEqual 255
switchblade.driveState mustEqual DriveState.Mobile
switchblade.inventory.isDefined mustEqual true
@@ -61,12 +61,13 @@ class VariantVehiclesTest extends Specification {
"encode (switchblade)" in {
val obj = VehicleData(
- CommonFieldData(
- PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
- PlanetSideEmpire.VS,
- 2
- ),
- 0,
+ PlacementData(6531.961f, 1872.1406f, 24.734375f, 0f, 0f, 357.1875f),
+ PlanetSideEmpire.VS,
+ false, false,
+ 2,
+ false, false,
+ PlanetSideGUID(0),
+ false,
255,
false, false,
DriveState.Mobile,
diff --git a/common/src/test/scala/objects/VehicleSpawnPadTest.scala b/common/src/test/scala/objects/VehicleSpawnPadTest.scala
index 2c9e1ba7..8e3f240c 100644
--- a/common/src/test/scala/objects/VehicleSpawnPadTest.scala
+++ b/common/src/test/scala/objects/VehicleSpawnPadTest.scala
@@ -49,7 +49,7 @@ class VehicleSpawnControl1Test extends ActorTest() {
}
class VehicleSpawnControl2aTest extends ActorTest() {
- // This long runs for a long time.
+ // This runs for a long time.
"VehicleSpawnControl" should {
"complete on a vehicle order (block a second one until the first is done and the spawn pad is cleared)" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
@@ -102,18 +102,18 @@ class VehicleSpawnControl2aTest extends ActorTest() {
//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(11,0,0)
player.VehicleSeated = None //since shared between orders, is necessary
+ vehicle.Position = Vector3(12,0,0)
val probe3Msg5 = probe3.receiveOne(4 seconds)
assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
- val probe3Msg6 = probe3.receiveOne(5 seconds)
+ val probe3Msg6 = probe3.receiveOne(4 seconds)
assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
}
}
}
class VehicleSpawnControl2bTest extends ActorTest() {
- // This long runs for a long time.
+ // This runs for a long time.
"VehicleSpawnControl" should {
"complete on a vehicle order (railless)" in {
val (vehicle, player, pad, zone) = VehicleSpawnPadControlTest.SetUpAgents(PlanetSideEmpire.TR)
@@ -144,7 +144,7 @@ class VehicleSpawnControl2bTest extends ActorTest() {
assert(probe1Msg2.isInstanceOf[Mountable.MountMessages])
val probe1Msg2Contents = probe1Msg2.asInstanceOf[Mountable.MountMessages]
assert(probe1Msg2Contents.response.isInstanceOf[Mountable.CanMount])
- val probe1Msg3 = probe1.receiveOne(3 seconds)
+ val probe1Msg3 = probe1.receiveOne(4 seconds)
assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PlayerSeatedInVehicle])
val probe1Msg4 = probe1.receiveOne(1 seconds)
@@ -161,9 +161,9 @@ 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(11,0,0)
player.VehicleSeated = None //since shared between orders, is necessary
- val probe3Msg6 = probe3.receiveOne(4 seconds)
+ vehicle.Position = Vector3(12,0,0)
+ val probe3Msg6 = probe3.receiveOne(10 seconds)
assert(probe3Msg6.isInstanceOf[VehicleSpawnPad.ConcealPlayer])
}
}
@@ -263,9 +263,12 @@ class VehicleSpawnControl5Test extends ActorTest() {
val probe3Msg4 = probe3.receiveOne(3 seconds)
assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
- val probe1Msg = probe1.receiveOne(12 seconds)
- assert(probe1Msg.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
- assert(probe1Msg.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
+ val probe1Msg1 = probe1.receiveOne(1 seconds)
+ assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.RevealPlayer])
+
+ val probe1Msg2 = probe1.receiveOne(12 seconds)
+ assert(probe1Msg2.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
+ assert(probe1Msg2.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
}
}
}
@@ -292,59 +295,17 @@ class VehicleSpawnControl6Test extends ActorTest() {
val probe1Msg1 = probe1.receiveOne(200 milliseconds)
assert(probe1Msg1.isInstanceOf[VehicleSpawnPad.StartPlayerSeatedInVehicle])
- player.Continent = "problem" //problem 1
+ player.Continent = "problem" //problem
probe1.receiveOne(200 milliseconds) //Mountable.MountMessage
val probe3Msg4 = probe3.receiveOne(3 seconds)
assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
- val probe3Msg5 = probe3.receiveOne(3 seconds)
- assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
+ val probe1Msg2 = probe1.receiveOne(3 seconds)
+ assert(probe1Msg2.isInstanceOf[VehicleSpawnPad.RevealPlayer])
- val probe1Msg2 = probe1.receiveOne(12 seconds)
- assert(probe1Msg2.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
- assert(probe1Msg2.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
- }
- }
-}
-
-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)
- //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])
- player.Die //problem
-
- val probe3Msg4 = probe3.receiveOne(3 seconds)
- assert(probe3Msg4.isInstanceOf[VehicleSpawnPad.DetachFromRails])
- val probe3Msg5 = probe3.receiveOne(100 milliseconds)
- assert(probe3Msg5.isInstanceOf[VehicleSpawnPad.ResetSpawnPad])
-
- val probe1Msg4 = probe1.receiveOne(12 seconds)
- assert(probe1Msg4.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
- assert(probe1Msg4.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
+ val probe1Msg3 = probe1.receiveOne(12 seconds)
+ assert(probe1Msg3.isInstanceOf[VehicleSpawnPad.PeriodicReminder])
+ assert(probe1Msg3.asInstanceOf[VehicleSpawnPad.PeriodicReminder].reason == VehicleSpawnPad.Reminders.Blocked)
}
}
}
@@ -383,7 +344,9 @@ object VehicleSpawnPadControlTest {
player.GUID = PlanetSideGUID(10)
player.Continent = zone.Id
player.Spawn
- //note: pad and vehicle are both at Vector3(0,0,0) so they count as blocking
+ //note: pad and vehicle are both at Vector3(1,0,0) so they count as blocking
+ pad.Position = Vector3(1,0,0)
+ vehicle.Position = Vector3(1,0,0)
(vehicle, player, pad, zone)
}
}
diff --git a/pslogin/src/main/scala/WorldSessionActor.scala b/pslogin/src/main/scala/WorldSessionActor.scala
index aa9867ad..6cbe1175 100644
--- a/pslogin/src/main/scala/WorldSessionActor.scala
+++ b/pslogin/src/main/scala/WorldSessionActor.scala
@@ -154,18 +154,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
- player.VehicleOwned match {
- case Some(vehicle_guid) =>
- continent.GUID(vehicle_guid) match {
- case Some(vehicle : Vehicle) =>
- vehicle.Owner = None
- //TODO temporary solution; to un-own, permit driver seat to Empire access level
- vehicle.PermissionGroup(10, VehicleLockState.Empire.id)
- vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SeatPermissions(player_guid, vehicle_guid, 10, VehicleLockState.Empire.id))
- case _ => ;
- }
- case None => ;
- }
+ DisownVehicle()
continent.Population ! Zone.Population.Leave(avatar)
}
}
@@ -298,9 +287,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
sendResponse(pkt)
}
- case AvatarResponse.LoadPlayer(pdata) =>
+ case AvatarResponse.LoadPlayer(pkt) =>
if(tplayer_guid != guid) {
- sendResponse(ObjectCreateMessage(ObjectClass.avatar, guid, pdata))
+ sendResponse(pkt)
}
case AvatarResponse.ObjectDelete(item_guid, unk) =>
@@ -423,8 +412,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case VehicleServiceResponse(_, guid, reply) =>
val tplayer_guid = if(player.HasGUID) { player.GUID} else { PlanetSideGUID(0) }
reply match {
- case VehicleResponse.Awareness(vehicle_guid) =>
- //resets exclamation point fte marker (once)
+ case VehicleResponse.Ownership(vehicle_guid) =>
sendResponse(PlanetsideAttributeMessage(guid, 21, vehicle_guid.guid.toLong))
case VehicleResponse.AttachToRails(vehicle_guid, pad_guid) =>
@@ -704,7 +692,13 @@ class WorldSessionActor extends Actor with MDCContextAware {
case Mountable.CanDismount(obj : Mountable, _) =>
log.warn(s"DismountVehicleMsg: $obj is some generic mountable object and nothing will happen")
- case Mountable.CanNotMount(obj, seat_num) =>
+ case Mountable.CanNotMount(obj : Vehicle, seat_num) =>
+ log.warn(s"MountVehicleMsg: $tplayer attempted to mount $obj's seat $seat_num, but was not allowed")
+ if(obj.SeatPermissionGroup(seat_num) == Some(AccessPermissionGroup.Driver)) {
+ sendResponse(ChatMsg(ChatMessageType.CMT_OPEN, false, "", "You are not the driver of this vehicle.", None))
+ }
+
+ case Mountable.CanNotMount(obj : Mountable, seat_num) =>
log.warn(s"MountVehicleMsg: $tplayer attempted to mount $obj's seat $seat_num, but was not allowed")
case Mountable.CanNotDismount(obj, seat_num) =>
@@ -1139,7 +1133,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
avatarService ! AvatarServiceMessage(continent.Id, AvatarAction.ObjectHeld(player.GUID, player.LastDrawnSlot))
}
sendResponse(PlanetsideAttributeMessage(vehicle_guid, 22, 1L)) //mount points off?
- sendResponse(PlanetsideAttributeMessage(vehicle_guid, 21, player.GUID.guid)) //fte and ownership?
+ sendResponse(PlanetsideAttributeMessage(vehicle_guid, 21, player.GUID.guid))
case VehicleSpawnPad.PlayerSeatedInVehicle(vehicle, pad) =>
val vehicle_guid = vehicle.GUID
@@ -1216,6 +1210,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
RemoveCharacterSelectScreenGUID(player)
sendResponse(CharacterInfoMessage(0, PlanetSideZoneID(1), 0, PlanetSideGUID(0), true, 0))
+ sendResponse(CharacterInfoMessage(0, PlanetSideZoneID(1), 0, PlanetSideGUID(0), true, 0))
case VehicleLoaded(_/*vehicle*/) => ;
//currently being handled by VehicleSpawnPad.LoadVehicle during testing phase
@@ -1318,6 +1313,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
}
else {
+ DisownVehicle()
continent.Population ! Zone.Population.Leave(avatar)
val original = player
//TODO check player orientation upon spawn not polluted
@@ -1450,19 +1446,29 @@ class WorldSessionActor extends Actor with MDCContextAware {
player = tplayer
val guid = tplayer.GUID
StartBundlingPackets()
- sendResponse(SetCurrentAvatarMessage(guid,0,0))
+ sendResponse(SetCurrentAvatarMessage(guid, 0, 0))
sendResponse(ChatMsg(ChatMessageType.CMT_EXPANSIONS, true, "", "1 on", None)) //CC on //TODO once per respawn?
sendResponse(PlayerStateShiftMessage(ShiftState(1, tplayer.Position, tplayer.Orientation.z)))
+ //transfer vehicle ownership
+ player.VehicleOwned match {
+ case Some(vehicle_guid) =>
+ continent.GUID(vehicle_guid) match {
+ case Some(vehicle : Vehicle) =>
+ vehicle.Owner = player
+ vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.Ownership(guid, vehicle_guid))
+ case _ =>
+ player.VehicleOwned = None
+ }
+ case None => ;
+ }
if(spectator) {
sendResponse(ChatMsg(ChatMessageType.CMT_TOGGLESPECTATORMODE, false, "", "on", None))
}
-
(0 until DetailedCharacterData.numberOfImplantSlots(tplayer.BEP)).foreach(slot => {
sendResponse(AvatarImplantMessage(guid, ImplantAction.Initialization, slot, 1)) //init implant slot
sendResponse(AvatarImplantMessage(guid, ImplantAction.Activation, slot, 0)) //deactivate implant
//TODO if this implant is Installed but does not have shortcut, add to a free slot or write over slot 61/62/63
})
-
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(0), 82, 0))
//TODO if Medkit does not have shortcut, add to a free slot or write over slot 64
sendResponse(CreateShortcutMessage(guid, 1, 0, true, Shortcut.MEDKIT))
@@ -1470,20 +1476,21 @@ class WorldSessionActor extends Actor with MDCContextAware {
//FavoritesMessage
sendResponse(SetChatFilterMessage(ChatChannel.Local, false, ChatChannel.values.toList)) //TODO will not always be "on" like this
deadState = DeadState.Alive
- sendResponse(AvatarDeadStateMessage(DeadState.Alive, 0,0, tplayer.Position, player.Faction, true))
+ sendResponse(AvatarDeadStateMessage(DeadState.Alive, 0, 0, tplayer.Position, player.Faction, true))
sendResponse(PlanetsideAttributeMessage(guid, 53, 1))
- sendResponse(AvatarSearchCriteriaMessage(guid, List(0,0,0,0,0,0)))
+ sendResponse(AvatarSearchCriteriaMessage(guid, List(0, 0, 0, 0, 0, 0)))
(1 to 73).foreach(i => {
sendResponse(PlanetsideAttributeMessage(PlanetSideGUID(i), 67, 0))
})
- (0 to 30).foreach(i => { //TODO 30 for a new character only?
+ (0 to 30).foreach(i => {
+ //TODO 30 for a new character only?
sendResponse(AvatarStatisticsMessage(2, Statistics(0L)))
})
//AvatarAwardMessage
//DisplayAwardMessage
//SquadDefinitionActionMessage and SquadDetailDefinitionUpdateMessage
- //MapObjectStateBlockMessage and ObjectCreateMessage
- //TacticsMessage
+ //MapObjectStateBlockMessage and ObjectCreateMessage?
+ //TacticsMessage?
StopBundlingPackets()
case ItemHacking(tplayer, target, tool_guid, delta, completeAction, tickAction) =>
@@ -1652,7 +1659,8 @@ class WorldSessionActor extends Actor with MDCContextAware {
continent.LivePlayers
.filterNot(tplayer => { tplayer.GUID == player.GUID || tplayer.VehicleSeated.nonEmpty })
.foreach(char => {
- sendResponse(ObjectCreateMessage(ObjectClass.avatar, char.GUID, char.Definition.Packet.ConstructorData(char).get))
+ val tdefintion = char.Definition
+ sendResponse(ObjectCreateMessage(tdefintion.ObjectId, char.GUID, char.Definition.Packet.ConstructorData(char).get))
if(char.UsingSpecial == SpecialExoSuitDefinition.Mode.Anchored) {
sendResponse(PlanetsideAttributeMessage(char.GUID, 19, 1))
}
@@ -1663,8 +1671,24 @@ class WorldSessionActor extends Actor with MDCContextAware {
}
//load active vehicles in zone
continent.Vehicles.foreach(vehicle => {
- val definition = vehicle.Definition
- sendResponse(ObjectCreateMessage(definition.ObjectId, vehicle.GUID, definition.Packet.ConstructorData(vehicle).get))
+ val vehicle_guid = vehicle.GUID
+ val vdefinition = vehicle.Definition
+ sendResponse(ObjectCreateMessage(vdefinition.ObjectId, vehicle_guid, vdefinition.Packet.ConstructorData(vehicle).get))
+ //occupants other than driver
+ vehicle.Seats
+ .filter({ case(index, seat) => seat.isOccupied && index > 0 })
+ .foreach({ case(index, seat) =>
+ val tplayer = seat.Occupant.get
+ val tdefintion = tplayer.Definition
+ sendResponse(
+ ObjectCreateMessage(
+ tdefintion.ObjectId,
+ tplayer.GUID,
+ ObjectCreateMessageParent(vehicle_guid, index),
+ tdefintion.Packet.ConstructorData(tplayer).get
+ )
+ )
+ })
ReloadVehicleAccessPermissions(vehicle)
})
//implant terminals
@@ -1675,7 +1699,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
val objDef = obj.Definition
sendResponse(
ObjectCreateMessage(
- ObjectClass.implant_terminal_interface,
+ objDef.ObjectId,
PlanetSideGUID(interface_guid),
ObjectCreateMessageParent(parent_guid, 1),
objDef.Packet.ConstructorData(obj).get
@@ -1686,18 +1710,19 @@ class WorldSessionActor extends Actor with MDCContextAware {
//seat terminal occupants
continent.GUID(terminal_guid) match {
case Some(obj : Mountable) =>
- obj.Seats
- .filter({ case(_, seat) => seat.isOccupied })
- .foreach({ case(index, seat) =>
- val tplayer = seat.Occupant.get
+ obj.Seats(0).Occupant match {
+ case Some(tplayer) =>
val tdefintion = tplayer.Definition
- sendResponse(ObjectCreateMessage(
- tdefintion.ObjectId,
- tplayer.GUID,
- ObjectCreateMessageParent(parent_guid, index),
- tdefintion.Packet.ConstructorData(tplayer).get
- ))
- })
+ sendResponse(
+ ObjectCreateMessage(
+ tdefintion.ObjectId,
+ tplayer.GUID,
+ ObjectCreateMessageParent(parent_guid, 0),
+ tdefintion.Packet.ConstructorData(tplayer).get
+ )
+ )
+ case None => ;
+ }
case _ => ;
}
})
@@ -1885,7 +1910,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case (false, _) => ;
}
-
+
// TODO: Prevents log spam, but should be handled correctly
if(messagetype != ChatMessageType.CMT_TOGGLE_GM) {
log.info("Chat: " + msg)
@@ -2516,14 +2541,15 @@ class WorldSessionActor extends Actor with MDCContextAware {
case _ => true
}) {
//access to trunk
- if(obj.AccessingTrunk.isEmpty) {
+ if(obj.AccessingTrunk.isEmpty &&
+ (!obj.PermissionGroup(AccessPermissionGroup.Trunk.id).contains(VehicleLockState.Locked) || obj.Owner.contains(player.GUID))) {
obj.AccessingTrunk = player.GUID
accessedContainer = Some(obj)
AccessContents(obj)
sendResponse(UseItemMessage(avatar_guid, unk1, object_guid, unk2, unk3, unk4, unk5, unk6, unk7, unk8, itemType))
}
else {
- log.info(s"UseItem: $player can not cut in line while player ${obj.AccessingTrunk.get} is using $obj's trunk")
+ log.info(s"UseItem: $obj's trunk is not currently accessible for $player")
}
}
else if(equipment.isDefined) {
@@ -2841,7 +2867,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
obj.Actor ! Deployment.TryDeploymentChange(deploy_state)
case _ =>
- log.error(s"DeployRequest: can not find $vehicle_guid in scope; removing ownership to mitigate confusion")
+ log.error(s"DeployRequest: can not find $vehicle_guid in scope")
player.VehicleOwned = None
}
}
@@ -2877,11 +2903,10 @@ class WorldSessionActor extends Actor with MDCContextAware {
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SeatPermissions(player.GUID, vehicle.GUID, attribute_type, attribute_value))
//kick players who should not be seated in the vehicle due to permission changes
if(allow == VehicleLockState.Locked) { //TODO only important permission atm
- vehicle.Definition.MountPoints.values.foreach(seat_num => {
- val seat = vehicle.Seat(seat_num).get
+ vehicle.Seats.foreach({ case (seat_num, seat) =>
seat.Occupant match {
case Some(tplayer) =>
- if(vehicle.SeatPermissionGroup(seat_num).contains(group) && tplayer != player) {
+ if(vehicle.SeatPermissionGroup(seat_num).contains(group) && tplayer != player) { //can not kick self
seat.Occupant = None
tplayer.VehicleSeated = None
vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.KickPassenger(tplayer.GUID, 4, false, object_guid))
@@ -3417,6 +3442,49 @@ class WorldSessionActor extends Actor with MDCContextAware {
})
}
+ /**
+ * Disassociate this client's player (oneself) from a vehicle that he owns.
+ */
+ def DisownVehicle() : Unit = DisownVehicle(player)
+
+ /**
+ * Disassociate a player from a vehicle that he owns.
+ * The vehicle must exist in the game world on the current continent.
+ * This is similar but unrelated to the natural exchange of ownership when someone else sits in the vehicle's driver seat.
+ * This is the player side of vehicle ownership removal.
+ * @see `DisownVehicle(Player, Vehicle)`
+ * @param tplayer the player
+ */
+ def DisownVehicle(tplayer : Player) : Unit = {
+ tplayer.VehicleOwned match {
+ case Some(vehicle_guid) =>
+ continent.GUID(vehicle_guid) match {
+ case Some(vehicle : Vehicle) =>
+ tplayer.VehicleOwned = None
+ DisownVehicle(tplayer, vehicle)
+ case _ =>
+ tplayer.VehicleOwned = None
+ }
+ case None => ;
+ }
+ }
+
+ /**
+ * Disassociate a vehicle from the player that owns it.
+ * When a vehicle is disowned
+ * This is the vehicle side of vehicle ownership removal.
+ * @see `DisownVehicle(Player)`
+ * @param tplayer the player
+ * @param vehicle the discovered vehicle
+ */
+ private def DisownVehicle(tplayer : Player, vehicle : Vehicle) : Unit = {
+ if(vehicle.Owner.contains(tplayer.GUID)) {
+ vehicle.Owner = None
+// vehicle.PermissionGroup(10, VehicleLockState.Empire.id)
+// vehicleService ! VehicleServiceMessage(continent.Id, VehicleAction.SeatPermissions(tplayer.GUID, vehicle.GUID, 10, VehicleLockState.Empire.id))
+ }
+ }
+
/**
* Gives a target player positive battle experience points only.
* If the player has access to more implant slots as a result of changing battle experience points, unlock those slots.
@@ -4314,14 +4382,16 @@ class WorldSessionActor extends Actor with MDCContextAware {
* It adds the `WSA`-current `Player` to the current zone and sends out the expected packets.
*/
def AvatarCreate() : Unit = {
+ player.VehicleSeated = None //TODO temp, until vehicle gating; unseat player else constructor data is messed up
player.Spawn
player.Health = 50 //TODO temp
player.Armor = 25
val packet = player.Definition.Packet
val dcdata = packet.DetailedConstructorData(player).get
- sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, player.GUID, dcdata))
- avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.LoadPlayer(player.GUID, packet.ConstructorData(player).get))
+ val player_guid = player.GUID
+ sendResponse(ObjectCreateDetailedMessage(ObjectClass.avatar, player_guid, dcdata))
continent.Population ! Zone.Population.Spawn(avatar, player)
+ avatarService ! AvatarServiceMessage(player.Continent, AvatarAction.LoadPlayer(player_guid, ObjectClass.avatar, player_guid, packet.ConstructorData(player).get, None))
log.debug(s"ObjectCreateDetailedMessage: $dcdata")
}
@@ -4379,8 +4449,9 @@ class WorldSessionActor extends Actor with MDCContextAware {
* @param tplayer the player
*/
def TurnPlayerIntoCorpse(tplayer : Player) : Unit = {
+ val guid = tplayer.GUID
sendResponse(
- ObjectCreateDetailedMessage(ObjectClass.avatar, tplayer.GUID, CorpseConverter.converter.DetailedConstructorData(tplayer).get)
+ ObjectCreateDetailedMessage(ObjectClass.avatar, guid, CorpseConverter.converter.DetailedConstructorData(tplayer).get)
)
}
@@ -4756,7 +4827,7 @@ class WorldSessionActor extends Actor with MDCContextAware {
case None => ;
}
}
-
+
def sendResponse(cont : PlanetSidePacketContainer) : Unit = {
log.trace("WORLD SEND: " + cont)
sendResponse(cont.asInstanceOf[Any])
diff --git a/pslogin/src/main/scala/services/avatar/AvatarAction.scala b/pslogin/src/main/scala/services/avatar/AvatarAction.scala
index a929cb81..40321546 100644
--- a/pslogin/src/main/scala/services/avatar/AvatarAction.scala
+++ b/pslogin/src/main/scala/services/avatar/AvatarAction.scala
@@ -6,7 +6,7 @@ import net.psforever.objects.equipment.Equipment
import net.psforever.objects.inventory.Container
import net.psforever.objects.zones.Zone
import net.psforever.packet.game.{PlanetSideGUID, PlayerStateMessageUpstream}
-import net.psforever.packet.game.objectcreate.ConstructorData
+import net.psforever.packet.game.objectcreate.{ConstructorData, ObjectCreateMessageParent}
import net.psforever.types.ExoSuitType
import scala.concurrent.duration.FiniteDuration
@@ -22,7 +22,7 @@ object AvatarAction {
final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Action
final case class DropItem(player_guid : PlanetSideGUID, item : Equipment, zone : Zone) extends Action
final case class EquipmentInHand(player_guid : PlanetSideGUID, target_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action
- final case class LoadPlayer(player_guid : PlanetSideGUID, pdata : ConstructorData) extends Action
+ final case class LoadPlayer(player_guid : PlanetSideGUID, object_id : Int, target_guid : PlanetSideGUID, cdata : ConstructorData, pdata : Option[ObjectCreateMessageParent]) extends Action
final case class ObjectDelete(player_guid : PlanetSideGUID, item_guid : PlanetSideGUID, unk : Int = 0) extends Action
final case class ObjectHeld(player_guid : PlanetSideGUID, slot : Int) extends Action
final case class PlanetsideAttribute(player_guid : PlanetSideGUID, attribute_type : Int, attribute_value : Long) extends Action
diff --git a/pslogin/src/main/scala/services/avatar/AvatarResponse.scala b/pslogin/src/main/scala/services/avatar/AvatarResponse.scala
index 3ab8e264..ba1e7ebc 100644
--- a/pslogin/src/main/scala/services/avatar/AvatarResponse.scala
+++ b/pslogin/src/main/scala/services/avatar/AvatarResponse.scala
@@ -18,7 +18,7 @@ object AvatarResponse {
final case class ConcealPlayer() extends Response
final case class EquipmentInHand(pkt : ObjectCreateMessage) extends Response
final case class DropItem(pkt : ObjectCreateMessage) extends Response
- final case class LoadPlayer(pdata : ConstructorData) extends Response
+ final case class LoadPlayer(pkt : ObjectCreateMessage) extends Response
final case class ObjectDelete(item_guid : PlanetSideGUID, unk : Int) extends Response
final case class ObjectHeld(slot : Int) extends Response
final case class PlanetsideAttribute(attribute_type : Int, attribute_value : Long) extends Response
diff --git a/pslogin/src/main/scala/services/avatar/AvatarService.scala b/pslogin/src/main/scala/services/avatar/AvatarService.scala
index 8c1f39db..87c194d4 100644
--- a/pslogin/src/main/scala/services/avatar/AvatarService.scala
+++ b/pslogin/src/main/scala/services/avatar/AvatarService.scala
@@ -86,9 +86,15 @@ class AvatarService extends Actor {
AvatarResponse.EquipmentInHand(ObjectCreateMessage(definition.ObjectId, item.GUID, containerData, objectData))
)
)
- case AvatarAction.LoadPlayer(player_guid, pdata) =>
+ case AvatarAction.LoadPlayer(player_guid, object_id, target_guid, cdata, pdata) =>
+ val pkt = pdata match {
+ case Some(data) =>
+ ObjectCreateMessage(object_id, target_guid, data, cdata)
+ case None =>
+ ObjectCreateMessage(object_id, target_guid, cdata)
+ }
AvatarEvents.publish(
- AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.LoadPlayer(pdata))
+ AvatarServiceResponse(s"/$forChannel/Avatar", player_guid, AvatarResponse.LoadPlayer(pkt))
)
case AvatarAction.ObjectDelete(player_guid, item_guid, unk) =>
AvatarEvents.publish(
diff --git a/pslogin/src/main/scala/services/vehicle/VehicleAction.scala b/pslogin/src/main/scala/services/vehicle/VehicleAction.scala
index 68c9788e..44114888 100644
--- a/pslogin/src/main/scala/services/vehicle/VehicleAction.scala
+++ b/pslogin/src/main/scala/services/vehicle/VehicleAction.scala
@@ -11,7 +11,6 @@ import net.psforever.types.{DriveState, Vector3, BailType}
object VehicleAction {
trait Action
- final case class Awareness(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID) extends Action
final case class ChildObjectState(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Action
final case class DeployRequest(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Action
final case class DismountVehicle(player_guid : PlanetSideGUID, bailType : BailType.Value, unk2 : Boolean) extends Action
@@ -20,6 +19,7 @@ object VehicleAction {
final case class KickPassenger(player_guid : PlanetSideGUID, unk1 : Int, unk2 : Boolean, vehicle_guid : PlanetSideGUID) extends Action
final case class LoadVehicle(player_guid : PlanetSideGUID, vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Action
final case class MountVehicle(player_guid : PlanetSideGUID, object_guid : PlanetSideGUID, seat : Int) extends Action
+ final case class Ownership(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID) extends Action
final case class SeatPermissions(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Action
final case class StowEquipment(player_guid : PlanetSideGUID, vehicle_guid : PlanetSideGUID, slot : Int, item : Equipment) extends Action
final case class UnloadVehicle(player_guid : PlanetSideGUID, continent : Zone, vehicle : Vehicle) extends Action
diff --git a/pslogin/src/main/scala/services/vehicle/VehicleResponse.scala b/pslogin/src/main/scala/services/vehicle/VehicleResponse.scala
index f3c9f9eb..027d7034 100644
--- a/pslogin/src/main/scala/services/vehicle/VehicleResponse.scala
+++ b/pslogin/src/main/scala/services/vehicle/VehicleResponse.scala
@@ -11,7 +11,6 @@ object VehicleResponse {
trait Response
final case class AttachToRails(vehicle_guid : PlanetSideGUID, rails_guid : PlanetSideGUID) extends Response
- final case class Awareness(vehicle_guid : PlanetSideGUID) extends Response
final case class ChildObjectState(object_guid : PlanetSideGUID, pitch : Float, yaw : Float) extends Response
final case class ConcealPlayer(player_guid : PlanetSideGUID) extends Response
final case class DeployRequest(object_guid : PlanetSideGUID, state : DriveState.Value, unk1 : Int, unk2 : Boolean, pos : Vector3) extends Response
@@ -22,6 +21,7 @@ object VehicleResponse {
final case class KickPassenger(seat_num : Int, kickedByDriver : Boolean, vehicle_guid : PlanetSideGUID) extends Response
final case class LoadVehicle(vehicle : Vehicle, vtype : Int, vguid : PlanetSideGUID, vdata : ConstructorData) extends Response
final case class MountVehicle(object_guid : PlanetSideGUID, seat : Int) extends Response
+ final case class Ownership(vehicle_guid : PlanetSideGUID) extends Response
final case class ResetSpawnPad(pad_guid : PlanetSideGUID) extends Response
final case class RevealPlayer(player_guid : PlanetSideGUID) extends Response
final case class SeatPermissions(vehicle_guid : PlanetSideGUID, seat_group : Int, permission : Long) extends Response
diff --git a/pslogin/src/main/scala/services/vehicle/VehicleService.scala b/pslogin/src/main/scala/services/vehicle/VehicleService.scala
index f4719eb4..700731f8 100644
--- a/pslogin/src/main/scala/services/vehicle/VehicleService.scala
+++ b/pslogin/src/main/scala/services/vehicle/VehicleService.scala
@@ -41,10 +41,6 @@ class VehicleService extends Actor {
case VehicleServiceMessage(forChannel, action) =>
action match {
- case VehicleAction.Awareness(player_guid, vehicle_guid) =>
- VehicleEvents.publish(
- VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.Awareness(vehicle_guid))
- )
case VehicleAction.ChildObjectState(player_guid, object_guid, pitch, yaw) =>
VehicleEvents.publish(
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.ChildObjectState(object_guid, pitch, yaw))
@@ -77,6 +73,10 @@ class VehicleService extends Actor {
VehicleEvents.publish(
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.MountVehicle(vehicle_guid, seat))
)
+ case VehicleAction.Ownership(player_guid, vehicle_guid) =>
+ VehicleEvents.publish(
+ VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.Ownership(vehicle_guid))
+ )
case VehicleAction.SeatPermissions(player_guid, vehicle_guid, seat_group, permission) =>
VehicleEvents.publish(
VehicleServiceResponse(s"/$forChannel/Vehicle", player_guid, VehicleResponse.SeatPermissions(vehicle_guid, seat_group, permission))
diff --git a/pslogin/src/test/scala/AvatarServiceTest.scala b/pslogin/src/test/scala/AvatarServiceTest.scala
index 884d0fe1..07c8a2d5 100644
--- a/pslogin/src/test/scala/AvatarServiceTest.scala
+++ b/pslogin/src/test/scala/AvatarServiceTest.scala
@@ -4,7 +4,7 @@ import akka.routing.RandomPool
import net.psforever.objects._
import net.psforever.objects.guid.{GUIDTask, TaskResolver}
import net.psforever.objects.zones.{Zone, ZoneActor, ZoneMap}
-import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectCreateMessageParent, PlacementData}
+import net.psforever.packet.game.objectcreate.{DroppedItemData, ObjectClass, ObjectCreateMessageParent, PlacementData}
import net.psforever.packet.game.{ObjectCreateMessage, PlanetSideGUID, PlayerStateMessageUpstream}
import net.psforever.types.{CharacterGender, ExoSuitType, PlanetSideEmpire, Vector3}
import services.{RemoverActor, Service, ServiceManager}
@@ -155,15 +155,28 @@ class LoadPlayerTest extends ActorTest {
val obj = Player(Avatar("TestCharacter1", PlanetSideEmpire.VS, CharacterGender.Female, 1, 1))
obj.GUID = PlanetSideGUID(10)
obj.Slot(5).Equipment.get.GUID = PlanetSideGUID(11)
- val pdata = obj.Definition.Packet.DetailedConstructorData(obj).get
+ val c1data = obj.Definition.Packet.DetailedConstructorData(obj).get
+ val pkt1 = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(10), c1data)
+ val parent = ObjectCreateMessageParent(PlanetSideGUID(12), 0)
+ obj.VehicleSeated = PlanetSideGUID(12)
+ val c2data = obj.Definition.Packet.DetailedConstructorData(obj).get
+ val pkt2 = ObjectCreateMessage(ObjectClass.avatar, PlanetSideGUID(10), parent, c2data)
"AvatarService" should {
"pass LoadPlayer" in {
ServiceManager.boot(system)
val service = system.actorOf(Props[AvatarService], AvatarServiceTest.TestName)
service ! Service.Join("test")
- service ! AvatarServiceMessage("test", AvatarAction.LoadPlayer(PlanetSideGUID(10), pdata))
- expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(10), AvatarResponse.LoadPlayer(pdata)))
+ //no parent data
+ service ! AvatarServiceMessage("test", AvatarAction.LoadPlayer(
+ PlanetSideGUID(20), ObjectClass.avatar, PlanetSideGUID(10), c1data, None)
+ )
+ expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(20), AvatarResponse.LoadPlayer(pkt1)))
+ //parent data
+ service ! AvatarServiceMessage("test", AvatarAction.LoadPlayer(
+ PlanetSideGUID(20), ObjectClass.avatar, PlanetSideGUID(10), c2data, Some(parent))
+ )
+ expectMsg(AvatarServiceResponse("/test/Avatar", PlanetSideGUID(20), AvatarResponse.LoadPlayer(pkt2)))
}
}
}
diff --git a/pslogin/src/test/scala/VehicleServiceTest.scala b/pslogin/src/test/scala/VehicleServiceTest.scala
index 261556c7..e2d48c97 100644
--- a/pslogin/src/test/scala/VehicleServiceTest.scala
+++ b/pslogin/src/test/scala/VehicleServiceTest.scala
@@ -68,15 +68,15 @@ class VehicleService5Test extends ActorTest {
}
}
-class AwarenessTest extends ActorTest {
+class OwnershipTest extends ActorTest {
ServiceManager.boot(system)
"VehicleService" should {
"pass Awareness" in {
val service = system.actorOf(Props[VehicleService], "v-service")
service ! Service.Join("test")
- service ! VehicleServiceMessage("test", VehicleAction.Awareness(PlanetSideGUID(10), PlanetSideGUID(11)))
- expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.Awareness(PlanetSideGUID(11))))
+ service ! VehicleServiceMessage("test", VehicleAction.Ownership(PlanetSideGUID(10), PlanetSideGUID(11)))
+ expectMsg(VehicleServiceResponse("/test/Vehicle", PlanetSideGUID(10), VehicleResponse.Ownership(PlanetSideGUID(11))))
}
}
}