diff --git a/src/main/scala/net/psforever/actors/net/LoginActor.scala b/src/main/scala/net/psforever/actors/net/LoginActor.scala index 6fd5d7bd5..f58fce6d1 100644 --- a/src/main/scala/net/psforever/actors/net/LoginActor.scala +++ b/src/main/scala/net/psforever/actors/net/LoginActor.scala @@ -106,7 +106,7 @@ class LoginActor(middlewareActor: typed.ActorRef[MiddlewareActor.Command], conne accountLogin(username, password.getOrElse("")) - case ConnectToWorldRequestMessage(name, _, _, _, _, _, _) => + case ConnectToWorldRequestMessage(name, _, _, _, _, _, _, _) => log.info(s"Connect to world request for '$name'") val response = ConnectToWorldMessage(serverName, publicAddress.getAddress.getHostAddress, publicAddress.getPort) middlewareActor ! MiddlewareActor.Send(response) diff --git a/src/main/scala/net/psforever/actors/session/support/SessionData.scala b/src/main/scala/net/psforever/actors/session/support/SessionData.scala index 74243d913..196bb8a15 100644 --- a/src/main/scala/net/psforever/actors/session/support/SessionData.scala +++ b/src/main/scala/net/psforever/actors/session/support/SessionData.scala @@ -156,7 +156,7 @@ class SessionData( /* packets */ def handleConnectToWorldRequest(pkt: ConnectToWorldRequestMessage)(implicit context: ActorContext): Unit = { - val ConnectToWorldRequestMessage(_, token, majorVersion, minorVersion, revision, buildDate, _) = pkt + val ConnectToWorldRequestMessage(_, token, majorVersion, minorVersion, revision, buildDate, _, _) = pkt log.trace( s"ConnectToWorldRequestMessage: client with versioning $majorVersion.$minorVersion.$revision, $buildDate has sent a token to the server" ) @@ -217,9 +217,9 @@ class SessionData( } } fallHeightTracker(pos.z) - // if (isCrouching && !player.Crouching) { - // //dev stuff goes here - // } +// if (isCrouching && !player.Crouching) { +// //dev stuff goes here +// } player.Position = pos player.Velocity = vel player.Orientation = Vector3(player.Orientation.x, pitch, yaw) diff --git a/src/main/scala/net/psforever/objects/definition/converter/BattleFrameFlightConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/BattleFrameFlightConverter.scala index 49fcd57c7..0d652db9e 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/BattleFrameFlightConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/BattleFrameFlightConverter.scala @@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.vehicles.VehicleSubsystemEntry import net.psforever.objects.{PlanetSideGameObject, Vehicle} -import net.psforever.types.PlanetSideGUID +import net.psforever.types.{PlanetSideGUID, VehicleFormat} import net.psforever.packet.game.objectcreate._ import scala.util.{Failure, Success, Try} diff --git a/src/main/scala/net/psforever/objects/definition/converter/BattleFrameRoboticsConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/BattleFrameRoboticsConverter.scala index 0f94dfc9c..1c51b1afb 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/BattleFrameRoboticsConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/BattleFrameRoboticsConverter.scala @@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.vehicles.VehicleSubsystemEntry import net.psforever.objects.{PlanetSideGameObject, Vehicle} -import net.psforever.types.PlanetSideGUID +import net.psforever.types.{PlanetSideGUID, VehicleFormat} import net.psforever.packet.game.objectcreate._ import scala.util.{Failure, Success, Try} diff --git a/src/main/scala/net/psforever/objects/definition/converter/SeatConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/SeatConverter.scala index dfa7d5b20..2ccc8788c 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/SeatConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/SeatConverter.scala @@ -11,7 +11,7 @@ object SeatConverter { AvatarConverter.MakeAppearanceData(player), AvatarConverter.MakeCharacterData(player), AvatarConverter.MakeInventoryData(player), - AvatarConverter.GetDrawnSlot(player), + DrawnSlot.None, offset ) } diff --git a/src/main/scala/net/psforever/objects/definition/converter/UtilityVehicleConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/UtilityVehicleConverter.scala index d3ddd5ea9..61812407c 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/UtilityVehicleConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/UtilityVehicleConverter.scala @@ -2,10 +2,11 @@ package net.psforever.objects.definition.converter import net.psforever.objects.Vehicle -import net.psforever.packet.game.objectcreate.{UtilityVehicleData, VehicleFormat} +import net.psforever.packet.game.objectcreate.UtilityVehicleData +import net.psforever.types.VehicleFormat class UtilityVehicleConverter extends VehicleConverter { - override protected def SpecificFormatModifier: VehicleFormat.Value = VehicleFormat.Utility + override protected def SpecificFormatModifier: VehicleFormat = VehicleFormat.Utility - override protected def SpecificFormatData(obj: Vehicle) = Some(UtilityVehicleData(0)) + override protected def SpecificFormatData(obj: Vehicle): Some[UtilityVehicleData] = Some(UtilityVehicleData(0)) } diff --git a/src/main/scala/net/psforever/objects/definition/converter/VariantVehicleConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/VariantVehicleConverter.scala index ed972465f..9b07c88c8 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/VariantVehicleConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/VariantVehicleConverter.scala @@ -2,12 +2,13 @@ package net.psforever.objects.definition.converter import net.psforever.objects.Vehicle -import net.psforever.packet.game.objectcreate.{VariantVehicleData, VehicleFormat} +import net.psforever.packet.game.objectcreate.VariantVehicleData +import net.psforever.types.VehicleFormat class VariantVehicleConverter extends VehicleConverter { - override protected def SpecificFormatModifier: VehicleFormat.Value = VehicleFormat.Variant + override protected def SpecificFormatModifier: VehicleFormat = VehicleFormat.Variant - override protected def SpecificFormatData(obj: Vehicle) = { + override protected def SpecificFormatData(obj: Vehicle): Some[VariantVehicleData] = { /* landed is 0 flying is 7 diff --git a/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala b/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala index 2e76d7314..6ce558c2e 100644 --- a/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala +++ b/src/main/scala/net/psforever/objects/definition/converter/VehicleConverter.scala @@ -4,7 +4,7 @@ package net.psforever.objects.definition.converter import net.psforever.objects.equipment.{Equipment, EquipmentSlot} import net.psforever.objects.{PlanetSideGameObject, Vehicle} import net.psforever.packet.game.objectcreate._ -import net.psforever.types.{DriveState, PlanetSideGUID} +import net.psforever.types.{DriveState, PlanetSideGUID, VehicleFormat} import scala.util.{Failure, Success, Try} @@ -75,9 +75,9 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { } private def MakeDriverSeat(obj: Vehicle): List[InventoryItemData.InventoryItem] = { - val offset: Long = MountableInventory.InitialStreamLengthToSeatEntries(obj.Velocity.nonEmpty, SpecificFormatModifier) obj.Seats(0).occupant match { case Some(player) => + val offset: Long = MountableInventory.InitialStreamLengthToSeatEntries(obj.Velocity.nonEmpty, SpecificFormatModifier) List(InventoryItemData(ObjectClass.avatar, player.GUID, 0, SeatConverter.MakeSeat(player, offset))) case None => Nil @@ -112,7 +112,7 @@ class VehicleConverter extends ObjectCreateConverter[Vehicle]() { } } - protected def SpecificFormatModifier: VehicleFormat.Value = VehicleFormat.Normal + protected def SpecificFormatModifier: VehicleFormat = VehicleFormat.Normal protected def SpecificFormatData(obj: Vehicle): Option[SpecificVehicleData] = None } diff --git a/src/main/scala/net/psforever/packet/game/ConnectToWorldRequestMessage.scala b/src/main/scala/net/psforever/packet/game/ConnectToWorldRequestMessage.scala index 63b0aadd5..36193896b 100644 --- a/src/main/scala/net/psforever/packet/game/ConnectToWorldRequestMessage.scala +++ b/src/main/scala/net/psforever/packet/game/ConnectToWorldRequestMessage.scala @@ -14,7 +14,8 @@ final case class ConnectToWorldRequestMessage( minorVersion: Long, revision: Long, buildDate: String, - unknown: Int + unk1: Int, + unk2: Int ) extends PlanetSideGamePacket { type Packet = ConnectToWorldRequestMessage def opcode = GamePacketOpcode.ConnectToWorldRequestMessage @@ -29,6 +30,7 @@ object ConnectToWorldRequestMessage extends Marshallable[ConnectToWorldRequestMe ("minor_version" | uint32L) :: ("revision" | uint32L) :: ("build_date" | PacketHelpers.encodedString) :: - ("unknown_short" | uint16L) + ("unk1" | uint8) :: + ("unk2" | uint8) ).as[ConnectToWorldRequestMessage] } diff --git a/src/main/scala/net/psforever/packet/game/objectcreate/BattleFrameRoboticsData.scala b/src/main/scala/net/psforever/packet/game/objectcreate/BattleFrameRoboticsData.scala index 03c4692b5..a0e63db6d 100644 --- a/src/main/scala/net/psforever/packet/game/objectcreate/BattleFrameRoboticsData.scala +++ b/src/main/scala/net/psforever/packet/game/objectcreate/BattleFrameRoboticsData.scala @@ -2,6 +2,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.Marshallable +import net.psforever.types.VehicleFormat import scodec.{Attempt, Codec, Err} import shapeless.HNil import scodec.codecs._ diff --git a/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala b/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala index 08018cf7a..3e8b820e1 100644 --- a/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala +++ b/src/main/scala/net/psforever/packet/game/objectcreate/CharacterAppearanceData.scala @@ -171,9 +171,9 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { app.faction, black_ops, altModel, - false, + v1 = false, None, - false, + jammered=false, None, if (jammered) { Some(0) @@ -194,20 +194,20 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { outfit_name.length, outfit_name: String, outfit_logo: Int, - false, + unk1 = false, backpack, - false, - false, - false, + unk2 = false, + unk3 = false, + unk4 = false, facingPitch: Float, facingYawUpper: Float, lfs: Boolean, grenade_state: GrenadeState.Value, is_cloaking: Boolean, - false, - false, + unk5 = false, + unk6 = false, charging_pose: Boolean, - false, + unk7 = false, on_zipline )(altModel, name_padding) new CharacterAppearanceData( @@ -283,11 +283,6 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { 6 } - private val extra_codec: Codec[ExtraData] = ( - ("unk1" | bool) :: - ("unk2" | bool) - ).as[ExtraData] - private val zipline_codec: Codec[ZiplineData] = ( ("unk1" | uint32L) :: ("unk2" | bool) @@ -303,7 +298,7 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { ("data" | CommonFieldData.codec) >>:~ { data => ("name" | PacketHelpers.encodedWideStringAligned(namePadding(name_padding, data.v2))) :: ("exosuit" | ExoSuitType.codec) :: - ("unk5" | uint2) :: //unknown + ("unk5" | uint2) :: ("sex" | CharacterSex.codec) :: ("head" | uint8L) :: ("voice" | CharacterVoice.codec) :: @@ -398,14 +393,14 @@ object CharacterAppearanceData extends Marshallable[CharacterAppearanceData] { ("outfit_name" | PacketHelpers.encodedWideStringAligned(outfitNamePadding)) :: ("outfit_logo" | uint8L) :: ("unk1" | bool) :: //unknown - conditional(alt_model, "backpack" | bool) :: //alt_model flag adds this bit; see ps.c:line#1069587 + ("backpack" | conditional(alt_model, bool)) :: //alt_model flag adds this bit; see ps.c:line#1069587 ("unk2" | bool) :: //requires alt_model flag (does NOT require health == 0) ("unk3" | bool) :: //stream misalignment when set ("unk4" | bool) :: //unknown ("facingPitch" | Angular.codec_zero_centered) :: ("facingYawUpper" | Angular.codec_zero_centered) :: ("lfs" | uint2) :: - ("grenade_state" | GrenadeState.codec_2u) :: //note: bin10 and bin11 are neutral (bin00 is not defined) + ("grenade_state" | GrenadeState.codec_2u) :: ("is_cloaking" | bool) :: ("unk5" | bool) :: //unknown ("unk6" | bool) :: //stream misalignment when set diff --git a/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala b/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala index 014c46bd9..d224f62d5 100644 --- a/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala +++ b/src/main/scala/net/psforever/packet/game/objectcreate/CharacterData.scala @@ -119,7 +119,7 @@ object CharacterData extends Marshallable[CharacterData] { ("health" | uint8L) :: //dead state when health == 0 ("armor" | uint8L) :: (("uniform_upgrade" | UniformStyle.codec) >>:~ { style => - uint(3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded + uint(bits = 3) :: //uniform_upgrade is actually interpreted as a 6u field, but the lower 3u seems to be discarded ("command_rank" | uintL(3)) :: listOfN(uint2, "implant_effects" | ImplantEffects.codec) :: ("cosmetics" | conditional(BattleRank.showCosmetics(style), Cosmetic.codec)) diff --git a/src/main/scala/net/psforever/packet/game/objectcreate/MountableInventory.scala b/src/main/scala/net/psforever/packet/game/objectcreate/MountableInventory.scala index 8e883c7ba..76d2c50a3 100644 --- a/src/main/scala/net/psforever/packet/game/objectcreate/MountableInventory.scala +++ b/src/main/scala/net/psforever/packet/game/objectcreate/MountableInventory.scala @@ -2,7 +2,7 @@ package net.psforever.packet.game.objectcreate import net.psforever.packet.PacketHelpers -import net.psforever.types.PlanetSideGUID +import net.psforever.types.{PlanetSideGUID, VehicleFormat} import scodec.Attempt.{Failure, Successful} import scodec.{Codec, Err} import scodec.codecs._ @@ -23,7 +23,7 @@ object MountableInventory { * @param format the subtype for this vehicle * @return a `Codec` that translates `InventoryData` */ - def custom_inventory_codec(hasVelocity: Boolean, format: VehicleFormat.Type): Codec[InventoryData] = + def custom_inventory_codec(hasVelocity: Boolean, format: VehicleFormat): Codec[InventoryData] = custom_inventory_codec(InitialStreamLengthToSeatEntries(hasVelocity, format)) /** @@ -96,7 +96,7 @@ object MountableInventory { accumulative: Long ): Player_Data = { val appearance = basic_appearance(CumulativeSeatedPlayerNamePadding(accumulative)) - Player_Data(None, appearance, character_data(appearance.b.backpack, true), Some(inventory), drawn_slot)(false) + Player_Data(None, appearance, character_data(false, true), Some(inventory), drawn_slot)(position_defined = false) } /** @@ -118,7 +118,7 @@ object MountableInventory { accumulative: Long ): Player_Data = { val appearance = basic_appearance(CumulativeSeatedPlayerNamePadding(accumulative)) - Player_Data.apply(None, appearance, character_data(appearance.b.backpack, true), None, drawn_slot)(false) + Player_Data.apply(None, appearance, character_data(false, true), None, drawn_slot)(position_defined = false) } /** @@ -136,16 +136,8 @@ object MountableInventory { * @param format the subtype for this vehicle * @return the length of the bitstream */ - def InitialStreamLengthToSeatEntries(hasVelocity: Boolean, format: VehicleFormat.Type): Long = { - 198 + - (if (hasVelocity) 42 else 0) + - (format match { - case VehicleFormat.Utility => 6 - case VehicleFormat.Variant => 8 - case VehicleFormat.Battleframe => 1 - case VehicleFormat.BattleframeFlight => 2 - case _ => 0 - }) + def InitialStreamLengthToSeatEntries(hasVelocity: Boolean, format: VehicleFormat): Long = { + 198 + (if (hasVelocity) 42 else 0) + format.value } /** @@ -156,10 +148,7 @@ object MountableInventory { * @return the padding value, 0-7 bits */ def CumulativeSeatedPlayerNamePadding(base: Long, next: Option[StreamBitSize]): Int = { - CumulativeSeatedPlayerNamePadding(base + (next match { - case Some(o) => o.bitsize - case None => 0 - })) + CumulativeSeatedPlayerNamePadding(base + next.map { _.bitsize }.getOrElse(0L)) } /** @@ -199,7 +188,7 @@ object MountableInventory { private def inventory_seat_codec(length: Long, offset: Int): Codec[Option[InventorySeat]] = { import shapeless.:: ( - PacketHelpers.peek(uintL(11)) >>:~ { objClass => + PacketHelpers.peek(uintL(bits = 11)) >>:~ { objClass => conditional(objClass == ObjectClass.avatar, seat_codec(offset)) >>:~ { seat => conditional( objClass == ObjectClass.avatar, @@ -240,7 +229,7 @@ object MountableInventory { } /** - * Translate data the is verified to involve a player who is seated (mounted) to the parent object at a given slot. + * Translate data that is verified to involve a player who is seated (mounted) to the parent object at a given slot. * The operation performed by this `Codec` is very similar to `InternalSlot.codec`. * @param pad the padding offset for the player's name; * 0-7 bits; @@ -253,7 +242,7 @@ object MountableInventory { private def seat_codec(pad: Int): Codec[InternalSlot] = { import shapeless.:: ( - ("objectClass" | uintL(11)) :: + ("objectClass" | uintL(bits = 11)) :: ("guid" | PlanetSideGUID.codec) :: ("parentSlot" | PacketHelpers.encodedStringSize) :: ("obj" | Player_Data.codec(pad)) diff --git a/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala b/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala index 25a20a14d..224e1e896 100644 --- a/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala +++ b/src/main/scala/net/psforever/packet/game/objectcreate/ObjectClass.scala @@ -1,6 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.packet.game.objectcreate +import net.psforever.types.VehicleFormat import scodec.{Attempt, Codec, Err} import scodec.codecs._ diff --git a/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala b/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala index 6e912423a..c4f2921c3 100644 --- a/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala +++ b/src/main/scala/net/psforever/packet/game/objectcreate/VehicleData.scala @@ -6,21 +6,12 @@ import scodec.Attempt.{Failure, Successful} import scodec.{Attempt, Codec, Err} import shapeless.HNil import scodec.codecs._ -import net.psforever.types.DriveState - -/** - * An `Enumeration` of the various formats that known structures that the stream of bits for `VehicleData` can assume. - */ -object VehicleFormat extends Enumeration { - type Type = Value - - val Battleframe, BattleframeFlight, Normal, Utility, Variant = Value -} +import net.psforever.types.{DriveState, VehicleFormat} /** * A basic `Trait` connecting all of the vehicle data formats (excepting `Normal`/`None`). */ -sealed abstract class SpecificVehicleData(val format: VehicleFormat.Value) extends StreamBitSize +sealed abstract class SpecificVehicleData(val format: VehicleFormat) extends StreamBitSize /** * The format of vehicle data for the type of vehicles that are considered "utility." @@ -84,7 +75,7 @@ final case class VehicleData( cloak: Boolean, vehicle_format_data: Option[SpecificVehicleData], inventory: Option[InventoryData] = None -)(val vehicle_type: VehicleFormat.Value = VehicleFormat.Normal) +)(val vehicle_type: VehicleFormat = VehicleFormat.Normal) extends ConstructorData { override def bitsize: Long = { //factor guard bool values into the base size, not its corresponding optional field @@ -174,7 +165,7 @@ object VehicleData extends Marshallable[VehicleData] { */ private val utility_data_codec: Codec[SpecificVehicleData] = { import shapeless.:: - uintL(6).hlist.exmap[SpecificVehicleData]( + uintL(VehicleFormat.Utility.value).hlist.exmap[SpecificVehicleData]( { case n :: HNil => Successful(UtilityVehicleData(n).asInstanceOf[SpecificVehicleData]) @@ -193,7 +184,7 @@ object VehicleData extends Marshallable[VehicleData] { */ private val variant_data_codec: Codec[SpecificVehicleData] = { import shapeless.:: - uint8L.hlist.exmap[SpecificVehicleData]( + uintL(VehicleFormat.Variant.value).hlist.exmap[SpecificVehicleData]( { case n :: HNil => Successful(VariantVehicleData(n).asInstanceOf[SpecificVehicleData]) @@ -212,7 +203,7 @@ object VehicleData extends Marshallable[VehicleData] { * @param vehicleFormat the requested format * @return the appropriate `Codec` for parsing that format */ - private def selectFormatReader(vehicleFormat: VehicleFormat.Value): Codec[SpecificVehicleData] = + private def selectFormatReader(vehicleFormat: VehicleFormat): Codec[SpecificVehicleData] = vehicleFormat match { case VehicleFormat.Utility => utility_data_codec @@ -223,7 +214,7 @@ object VehicleData extends Marshallable[VehicleData] { .asInstanceOf[Codec[SpecificVehicleData]] } - def codec(vehicle_type: VehicleFormat.Value): Codec[VehicleData] = { + def codec(vehicle_type: VehicleFormat): Codec[VehicleData] = { import shapeless.:: ( ("pos" | PlacementData.codec) >>:~ { pos => @@ -237,7 +228,7 @@ object VehicleData extends Marshallable[VehicleData] { ("unk6" | bool) :: ("cloak" | bool) :: //cloak as wraith, phantasm conditional(vehicle_type != VehicleFormat.Normal,"vehicle_format_data" | selectFormatReader(vehicle_type)) :: - optional(bool, target = "inventory" | MountableInventory.custom_inventory_codec(pos.vel.isDefined, VehicleFormat.Normal)) + optional(bool, target = "inventory" | MountableInventory.custom_inventory_codec(pos.vel.isDefined, vehicle_type)) } ).exmap[VehicleData]( { diff --git a/src/main/scala/net/psforever/types/CharacterVoice.scala b/src/main/scala/net/psforever/types/CharacterVoice.scala index a6e287d44..eefc6baa2 100644 --- a/src/main/scala/net/psforever/types/CharacterVoice.scala +++ b/src/main/scala/net/psforever/types/CharacterVoice.scala @@ -22,5 +22,5 @@ object CharacterVoice extends Enumeration { Voice5 //daredevil, calculating = Value - implicit val codec = PacketHelpers.createEnumerationCodec(this, uint(3)) + implicit val codec = PacketHelpers.createEnumerationCodec(this, uint(bits = 3)) } diff --git a/src/main/scala/net/psforever/types/ExoSuitType.scala b/src/main/scala/net/psforever/types/ExoSuitType.scala index fee36b081..439d1e023 100644 --- a/src/main/scala/net/psforever/types/ExoSuitType.scala +++ b/src/main/scala/net/psforever/types/ExoSuitType.scala @@ -12,5 +12,5 @@ object ExoSuitType extends Enumeration { type Type = Value val Agile, Reinforced, MAX, Infiltration, Standard = Value - implicit val codec: Codec[ExoSuitType.Value] = PacketHelpers.createEnumerationCodec(this, uint(3)) + implicit val codec: Codec[ExoSuitType.Value] = PacketHelpers.createEnumerationCodec(this, uint(bits = 3)) } diff --git a/src/main/scala/net/psforever/types/GrenadeState.scala b/src/main/scala/net/psforever/types/GrenadeState.scala index a75e0c9e5..6242cbd4d 100644 --- a/src/main/scala/net/psforever/types/GrenadeState.scala +++ b/src/main/scala/net/psforever/types/GrenadeState.scala @@ -7,12 +7,14 @@ import scodec.codecs._ /** * An `Enumeration` of the kinds of states applicable to the grenade animation. */ -object GrenadeState extends Enumeration(1) { +object GrenadeState extends Enumeration { type Type = Value - val Primed, //avatars and other depicted player characters - Thrown, //avatars only - None //non-actionable state of rest + val + Non, //non-actionable state of rest + Primed, //avatars and other depicted player characters + Thrown, //avatars only + None //non-actionable state of rest = Value implicit val codec = PacketHelpers.createEnumerationCodec(this, uint8L) diff --git a/src/main/scala/net/psforever/types/VehicleFormat.scala b/src/main/scala/net/psforever/types/VehicleFormat.scala new file mode 100644 index 000000000..30cf9b099 --- /dev/null +++ b/src/main/scala/net/psforever/types/VehicleFormat.scala @@ -0,0 +1,19 @@ +// Copyright (c) 2023 PSForever +package net.psforever.types + +import enumeratum.values.{IntEnum, IntEnumEntry} + +/** + * An enumeration of the various formats that known structures that the stream of bits for `VehicleData` can assume. + */ +sealed abstract class VehicleFormat(val value: Int) extends IntEnumEntry + +object VehicleFormat extends IntEnum[VehicleFormat] { + val values: IndexedSeq[VehicleFormat] = findValues + + case object Normal extends VehicleFormat(value = 0) + case object Battleframe extends VehicleFormat(value = 1) + case object BattleframeFlight extends VehicleFormat(value = 2) + case object Utility extends VehicleFormat(value = 6) + case object Variant extends VehicleFormat(value = 8) +} diff --git a/src/test/scala/game/ConnectToWorldRequestMessageTest.scala b/src/test/scala/game/ConnectToWorldRequestMessageTest.scala index 770bb3aca..05f1dba0e 100644 --- a/src/test/scala/game/ConnectToWorldRequestMessageTest.scala +++ b/src/test/scala/game/ConnectToWorldRequestMessageTest.scala @@ -12,21 +12,22 @@ class ConnectToWorldRequestMessageTest extends Specification { "decode" in { PacketCoding.decodePacket(string).require match { - case ConnectToWorldRequestMessage(serverName, token, majorVersion, minorVersion, revision, buildDate, unk) => + case ConnectToWorldRequestMessage(serverName, token, majorVersion, minorVersion, revision, buildDate, unk1, unk2) => serverName mustEqual "gemini" token mustEqual "" majorVersion mustEqual 0 minorVersion mustEqual 0 revision mustEqual 0 buildDate mustEqual "" - unk mustEqual 0 + unk1 mustEqual 0 + unk2 mustEqual 0 case _ => ko } } "encode" in { - val msg = ConnectToWorldRequestMessage("gemini", "", 0, 0, 0, "", 0) + val msg = ConnectToWorldRequestMessage("gemini", "", 0, 0, 0, "", 0, 0) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual string diff --git a/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala b/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala index b6bec222d..57dedbdb0 100644 --- a/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala +++ b/src/test/scala/game/objectcreatevehicle/UtilityVehiclesTest.scala @@ -2,7 +2,7 @@ package game.objectcreatevehicle import net.psforever.packet._ -import net.psforever.packet.game.objectcreate._ +import net.psforever.packet.game.objectcreate.{CharacterAppearanceA, _} import net.psforever.packet.game.ObjectCreateMessage import net.psforever.types._ import org.specs2.mutable._ @@ -12,8 +12,8 @@ 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"17 ec060000 970 fe0f 6C2D765535CA16000013 f9c1f2f80c000 1e18ff0000 105 1e4078640000000 8c50004c0041006d0069006e00670079007500650054005200 04217c859e808000000000000000250342002 2c02a002a002a002a0050004c0041002a002a002a002a00 010027e3007c000003940000016c0400023c040002285a086c2f00c80000000000300210288740800000004046f17423018000002c4d6190400000001010704a86406000002bc770842000000004041c5f21d01800000e0 75821902000000 623e8420800000 1950588c1800000 332ea0f840000000" "Utility vehicles" should { "decode (ant)" in { @@ -95,6 +95,152 @@ class UtilityVehiclesTest extends Specification { } } + "decode (ams, seated)" in { + PacketCoding.decodePacket(string_ams_seated).require match { + case ObjectCreateMessage(len, cls, guid, None, data) => + len mustEqual 1772 + cls mustEqual ObjectClass.ams + guid mustEqual PlanetSideGUID(4094) + data match { + case ams: VehicleData => + ams.pos.coord mustEqual Vector3(3674.8438f, 2726.789f, 91.15625f) + ams.pos.orient mustEqual Vector3(0f, 0f, 36.5625f) + ams.pos.vel.contains(Vector3(27.3375f, -0.78749996f, 0.1125f)) mustEqual true //contains does not work + ams.data match { + case data: CommonFieldData => + data.faction mustEqual PlanetSideEmpire.TR + data.bops mustEqual false + data.alternate mustEqual false + data.v1 mustEqual false + data.v2.isEmpty mustEqual true + data.jammered mustEqual false + data.v4.contains(false) mustEqual true + data.v5.isEmpty mustEqual true + data.guid mustEqual ValidPlanetSideGUID(3087) + case _ => + ko + } + ams.unk3 mustEqual false + ams.health mustEqual 255 + ams.unk4 mustEqual false + ams.no_mount_points mustEqual false + ams.driveState mustEqual DriveState.Mobile + ams.unk5 mustEqual false + ams.unk6 mustEqual false + ams.cloak mustEqual false + ams.vehicle_format_data.contains(UtilityVehicleData(0)) mustEqual true + val inv = ams.inventory match { + case Some(inv: InventoryData) => inv.contents + case _ => Nil + } + //0 + val inv0 = inv.head + inv0.objectClass mustEqual ObjectClass.avatar + inv0.guid mustEqual PlanetSideGUID(3087) + inv0.parentSlot mustEqual 0 + inv0.obj match { + case PlayerData(None, CharacterAppearanceData(a, b, r), char, Some(InventoryData(pinv)), DrawnSlot.None) => + a.app.name mustEqual "PLAmingyueTR" + a.app.faction mustEqual PlanetSideEmpire.TR + a.app.sex mustEqual CharacterSex.Female + a.app.voice mustEqual CharacterVoice.Voice5 + a.app.head mustEqual 16 + a.data match { + case data: CommonFieldData => + data.faction mustEqual PlanetSideEmpire.TR + data.bops mustEqual false + data.alternate mustEqual false + data.v1 mustEqual false + data.v2.isEmpty mustEqual true + data.jammered mustEqual false + data.v4.isEmpty mustEqual true + data.v5.isEmpty mustEqual true + data.guid mustEqual ValidPlanetSideGUID(0) + case _ => + ko + } + a.char_id mustEqual 41555698L + a.exosuit mustEqual ExoSuitType.Agile + a.unk5 mustEqual 0 + a.unk7 mustEqual 0 + a.unk8 mustEqual 0 + a.unk9 mustEqual 0 + a.unkA mustEqual 0 + b.outfit_id mustEqual 527764 + b.outfit_name mustEqual "****PLA****" + b.outfit_logo mustEqual 1 + b.lfs mustEqual false + b.backpack mustEqual false + b.charging_pose mustEqual false + b.grenade_state mustEqual GrenadeState.None + b.on_zipline.isEmpty mustEqual true + b.facingPitch mustEqual -5.625f + b.facingYawUpper mustEqual 5.625f + b.unk1 mustEqual false + b.unk2 mustEqual false + b.unk3 mustEqual false + b.unk4 mustEqual false + b.unk5 mustEqual false + b.unk6 mustEqual false + b.unk7 mustEqual false + r mustEqual RibbonBars( + MeritCommendation.AMSSupport2, + MeritCommendation.HeavyAssault1, + MeritCommendation.ScavengerTR1, + MeritCommendation.ThreeYearTR + ) + char.health mustEqual 100 + char.armor mustEqual 0 + char.uniform_upgrade mustEqual UniformStyle.ThirdUpgrade + char.command_rank mustEqual 4 + char.implant_effects mustEqual Nil + char.unk mustEqual 2 + char.cosmetics.contains(Set(Cosmetic.Earpiece, Cosmetic.Sunglasses, Cosmetic.NoHelmet)) mustEqual true + pinv mustEqual List( + InternalSlot(728, ValidPlanetSideGUID(3312), 0, REKData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)),3,0)), + InternalSlot(132, ValidPlanetSideGUID(3665), 1, WeaponData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,None,None,ValidPlanetSideGUID(0)),0,List( + InternalSlot(111,ValidPlanetSideGUID(4538),0,CommonFieldData(PlanetSideEmpire.NEUTRAL,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)))),false) + ), + InternalSlot(556, ValidPlanetSideGUID(3179), 2, WeaponData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,None,None,ValidPlanetSideGUID(0)),0,List( + InternalSlot(28,ValidPlanetSideGUID(3221),0,CommonFieldData(PlanetSideEmpire.NEUTRAL,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)))),false) + ), + InternalSlot(175,ValidPlanetSideGUID(4334),4,WeaponData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,None,None,ValidPlanetSideGUID(0)),0,List(InternalSlot(540,ValidPlanetSideGUID(3833),0,CommonFieldData(PlanetSideEmpire.NEUTRAL,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)))),false)) + ) + case _ => + ko + } + //1 + val inv1 = inv(1) + inv1.objectClass mustEqual ObjectClass.matrix_terminalc + inv1.guid mustEqual PlanetSideGUID(3265) + inv1.parentSlot mustEqual 1 + inv1.obj.isInstanceOf[CommonFieldData] mustEqual true + //2 + val inv2 = inv(2) + inv2.objectClass mustEqual ObjectClass.ams_respawn_tube + inv2.guid mustEqual PlanetSideGUID(4346) + inv2.parentSlot mustEqual 2 + inv2.obj.isInstanceOf[CommonFieldData] mustEqual true + //3 + val inv3 = inv(3) + inv3.objectClass mustEqual ObjectClass.order_terminala + inv3.guid mustEqual PlanetSideGUID(4363) + inv3.parentSlot mustEqual 3 + inv3.obj.isInstanceOf[CommonFieldData] mustEqual true + //4 + val inv4 = inv(4) + inv4.objectClass mustEqual ObjectClass.order_terminalb + inv4.guid mustEqual PlanetSideGUID(4074) + inv4.parentSlot mustEqual 4 + inv4.obj.isInstanceOf[CommonFieldData] mustEqual true + case _ => + ko + } + case _ => + ko + } + } + "encode (ant)" in { val obj = VehicleData( PlacementData(3674.8438f, 2726.789f, 91.15625f, 0f, 0f, 90.0f), @@ -165,5 +311,124 @@ class UtilityVehiclesTest extends Specification { pkt mustEqual string_ams } + + "encode (ams, seated)" in { + val obj = VehicleData( + PlacementData( + Vector3(3674.8438f, 2726.789f, 91.15625f), + Vector3(0f, 0f, 36.5625f), + Some(Vector3(27.3375f, -0.78749996f, 0.1125f)) + ), + CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, Some(false), None, PlanetSideGUID(3087)), + unk3 = false, + health = 255, + unk4 = false, + no_mount_points = false, + DriveState.Mobile, + unk5 = false, + unk6 = false, + cloak = false, + Some(UtilityVehicleData(0)), + Some(InventoryData( + List( + InternalSlot( + ObjectClass.avatar, PlanetSideGUID(3087), 0, { + val a: Int => CharacterAppearanceA = CharacterAppearanceA( + BasicCharacterData( + "PLAmingyueTR", + PlanetSideEmpire.TR, + CharacterSex.Female, + head = 16, + CharacterVoice.Voice5 + ), + CommonFieldData(PlanetSideEmpire.TR, false, false, false, None, false, None, None, PlanetSideGUID(0)), + ExoSuitType.Agile, + unk5 = 0, + char_id = 41555698L, + unk7 = 0, + unk8 = 0, + unk9 = 0, + unkA = 0 + ) + val b: (Boolean, Int) => CharacterAppearanceB = CharacterAppearanceB( + outfit_id = 527764L, + outfit_name = "****PLA****", + outfit_logo = 1, + unk1 = false, + backpack = false, + unk2 = false, + unk3 = false, + unk4 = false, + facingPitch = -5.625f, + facingYawUpper = 5.625f, + lfs = false, + GrenadeState.None, + is_cloaking = false, + unk5 = false, + unk6 = false, + charging_pose = false, + unk7 = false, + on_zipline = None + ) + val app: Int => CharacterAppearanceData = CharacterAppearanceData( + a, + b, + RibbonBars( + MeritCommendation.AMSSupport2, + MeritCommendation.HeavyAssault1, + MeritCommendation.ScavengerTR1, + MeritCommendation.ThreeYearTR + ) + ) + val char: (Boolean, Boolean) => CharacterData = CharacterData( + health = 100, + armor = 0, + UniformStyle.ThirdUpgrade, + unk = 2, + command_rank = 4, + implant_effects = List(), + Some(Set(Cosmetic.Earpiece, Cosmetic.Sunglasses, Cosmetic.NoHelmet)) + ) + val inv = InventoryData( + List( + InternalSlot(728, ValidPlanetSideGUID(3312), 0, REKData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)),3,0)), + InternalSlot(132, ValidPlanetSideGUID(3665), 1, WeaponData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,None,None,ValidPlanetSideGUID(0)),0,List( + InternalSlot(111, ValidPlanetSideGUID(4538), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)))),false) + ), + InternalSlot(556, ValidPlanetSideGUID(3179), 2, WeaponData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,None,None,ValidPlanetSideGUID(0)),0,List( + InternalSlot(28, ValidPlanetSideGUID(3221), 0, CommonFieldData(PlanetSideEmpire.NEUTRAL,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)))),false) + ), + InternalSlot(175, ValidPlanetSideGUID(4334), 4, WeaponData(CommonFieldData(PlanetSideEmpire.TR,false,false,false,None,false,None,None,ValidPlanetSideGUID(0)),0,List(InternalSlot(540,ValidPlanetSideGUID(3833),0,CommonFieldData(PlanetSideEmpire.NEUTRAL,false,false,false,None,false,Some(false),None,ValidPlanetSideGUID(0)))),false)) + ) + ) + MountableInventory.PlayerData( + app, + char, + inv, + DrawnSlot.None, + MountableInventory.InitialStreamLengthToSeatEntries(hasVelocity=true, VehicleFormat.Utility) + ) + } + ), + InternalSlot( + ObjectClass.matrix_terminalc, PlanetSideGUID(3265), 1, CommonFieldData(PlanetSideEmpire.TR)(flag = false) + ), + InternalSlot( + ObjectClass.ams_respawn_tube, PlanetSideGUID(4346), 2, CommonFieldData(PlanetSideEmpire.TR)(flag = false) + ), + InternalSlot( + ObjectClass.order_terminala, PlanetSideGUID(4363), 3, CommonFieldData(PlanetSideEmpire.TR)(flag = false) + ), + InternalSlot( + ObjectClass.order_terminalb, PlanetSideGUID(4074), 4, CommonFieldData(PlanetSideEmpire.TR)(flag = false) + ) + ) + )) + )(VehicleFormat.Utility) + val msg = ObjectCreateMessage(ObjectClass.ams, PlanetSideGUID(4094), obj) + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual string_ams_seated + } } } diff --git a/tools/client/src/main/scala/net/psforever/tools/client/Client.scala b/tools/client/src/main/scala/net/psforever/tools/client/Client.scala index a8f44128d..d7f231efe 100644 --- a/tools/client/src/main/scala/net/psforever/tools/client/Client.scala +++ b/tools/client/src/main/scala/net/psforever/tools/client/Client.scala @@ -209,7 +209,7 @@ class Client(username: String, password: String) { case _ => ??? } setupConnection() - send(ConnectToWorldRequestMessage("", state.token.get, 0, 0, 0, "", 0)).require + send(ConnectToWorldRequestMessage("", state.token.get, 0, 0, 0, "", 0, 0)).require while (true) { val r = waitFor[CharacterInfoMessage]().require if (r.finished) {