diff --git a/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala b/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala index 363cd124f..a5902c1b5 100644 --- a/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala +++ b/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala @@ -1,8 +1,7 @@ // Copyright (c) 2017 PSForever package net.psforever.packet.game -import net.psforever.packet.{GamePacketOpcode, Marshallable, PlanetSideGamePacket} -import net.psforever.types.PlanetSideGUID +import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} import scodec.Codec import scodec.bits.ByteVector import scodec.codecs._ @@ -11,21 +10,34 @@ import scodec.codecs._ * Used by PlanetSide in conjunction with wiredred/pscs.exe to establish local platoon/squad voice chat. * We are not focusing on implementation of this feature. * At the most, we will merely record data about who requested it. - * @param unk na - * @param player_guid the player who sent this request - * @param data everything else + * + * @param remote_host true if the player provides info for a remote host (remote_ip) + * @param port the port to connect to + * @param bandwidth the bandwidth set by the player (valid values are 3, 201, 203) + * @param remote_ip the IP of the remote voice server, only set if remote_host == true */ -final case class VoiceHostRequest(unk: Boolean, player_guid: PlanetSideGUID, data: ByteVector) - extends PlanetSideGamePacket { - type Packet = VoiceHostRequest +final case class VoiceHostRequest( + remote_host: Boolean, + port: Int, + bandwidth: Int, + remote_ip: String, + data: ByteVector +) extends PlanetSideGamePacket { + require(port > 0) + require(port <= 65535) + require(bandwidth == 3 || bandwidth == 201 || bandwidth == 203) + require(remote_host == (remote_ip != "")) + def opcode = GamePacketOpcode.VoiceHostRequest def encode = VoiceHostRequest.encode(this) } object VoiceHostRequest extends Marshallable[VoiceHostRequest] { implicit val codec: Codec[VoiceHostRequest] = ( - ("unk" | bool) :: - ("player_guid" | PlanetSideGUID.codec) :: + ("remote_host" | bool) :: + ("port" | uint16L) :: + ("bandwidth" | uint8L) :: + ("remote_ip" | PacketHelpers.encodedStringAligned(7)) :: ("data" | bytes) - ).as[VoiceHostRequest] + ).as[VoiceHostRequest] } diff --git a/src/test/scala/game/VoiceHostRequestTest.scala b/src/test/scala/game/VoiceHostRequestTest.scala index 82ef72a26..d1bf096cf 100644 --- a/src/test/scala/game/VoiceHostRequestTest.scala +++ b/src/test/scala/game/VoiceHostRequestTest.scala @@ -4,26 +4,91 @@ package game import org.specs2.mutable._ import net.psforever.packet._ import net.psforever.packet.game._ -import net.psforever.types.PlanetSideGUID import scodec.bits._ class VoiceHostRequestTest extends Specification { - val string_request = hex"b0 2580 00" + val string_request_local_75_high = hex"b0 2580 01 c0 00" + val string_request_local_1111_mid = hex"b0 2b82 64 c0 00" + val string_request_local_1112_mid = hex"b0 2c02 64 c0 00" + val string_request_remote_12345_high = hex"b0 9c98 01 c7 803131312e3232322e3132332e323334" - "decode" in { - PacketCoding.decodePacket(string_request).require match { - case VoiceHostRequest(unk, player, _) => - unk mustEqual false - player mustEqual PlanetSideGUID(75) + "decode local 75 high" in { + PacketCoding.decodePacket(string_request_local_75_high).require match { + case VoiceHostRequest(remote_host, port, bandwidth, server_ip, data) => + remote_host mustEqual false + port mustEqual 75 + bandwidth mustEqual 3 + server_ip mustEqual "" + data mustEqual ByteVector.empty case _ => ko } } - "encode" in { - val msg = VoiceHostRequest(false, PlanetSideGUID(75), ByteVector.empty) + "encode local 75 high" in { + val msg = VoiceHostRequest(remote_host = false, 75, 3, "", ByteVector.empty) val pkt = PacketCoding.encodePacket(msg).require.toByteVector - pkt mustEqual string_request + pkt mustEqual string_request_local_75_high + } + + "decode local 1111 mid" in { + PacketCoding.decodePacket(string_request_local_1111_mid).require match { + case VoiceHostRequest(remote_host, port, bandwidth, server_ip, data) => + remote_host mustEqual false + port mustEqual 1111 + bandwidth mustEqual 201 + server_ip mustEqual "" + data mustEqual ByteVector.empty + case _ => + ko + } + } + + "encode local 1111 mid" in { + val msg = VoiceHostRequest(remote_host = false, 1111, 201, "", ByteVector.empty) + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual string_request_local_1111_mid + } + + "decode local 1112 mid" in { + PacketCoding.decodePacket(string_request_local_1112_mid).require match { + case VoiceHostRequest(remote_host, port, bandwidth, server_ip, data) => + remote_host mustEqual false + port mustEqual 1112 + bandwidth mustEqual 201 + server_ip mustEqual "" + data mustEqual ByteVector.empty + case _ => + ko + } + } + + "encode local 1112 mid" in { + val msg = VoiceHostRequest(remote_host = false, 1112, 201, "", ByteVector.empty) + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual string_request_local_1112_mid + } + + "decode remote 12345 high" in { + PacketCoding.decodePacket(string_request_remote_12345_high).require match { + case VoiceHostRequest(remote, port, codec, server_ip, data) => + remote mustEqual true + port mustEqual 12345 + codec mustEqual 3 + server_ip mustEqual "111.222.123.234" + data mustEqual ByteVector.empty + case _ => + ko + } + } + + "encode remote 12345 high" in { + val msg = VoiceHostRequest(remote_host = true, port = 12345, bandwidth = 3, remote_ip = "111.222.123.234", ByteVector.empty) + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual string_request_remote_12345_high } }