From e68c912ecbfea0d557463836ca69d4f184938219 Mon Sep 17 00:00:00 2001 From: Resaec Date: Sun, 24 Dec 2023 05:14:27 +0100 Subject: [PATCH 1/2] Implement the VoiceHostRequest message --- .../packet/game/VoiceHostRequest.scala | 35 +++++--- .../scala/game/VoiceHostRequestTest.scala | 81 ++++++++++++++++--- 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala b/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala index 363cd124..2e143231 100644 --- a/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala +++ b/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala @@ -1,31 +1,40 @@ // 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._ /** * 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 +) 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) :: - ("data" | bytes) - ).as[VoiceHostRequest] + ("remote_host" | bool) :: + ("port" | uint16L) :: + ("bandwidth" | uint8L) :: + ("remote_ip" | PacketHelpers.encodedStringAligned(7)) + ).as[VoiceHostRequest] } diff --git a/src/test/scala/game/VoiceHostRequestTest.scala b/src/test/scala/game/VoiceHostRequestTest.scala index 82ef72a2..51cae071 100644 --- a/src/test/scala/game/VoiceHostRequestTest.scala +++ b/src/test/scala/game/VoiceHostRequestTest.scala @@ -4,26 +4,87 @@ 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 25 80 01c000" + val string_request_local_1111_mid = hex"b0 2b 82 64c000" + val string_request_local_1112_mid = hex"b0 2c 02 64c000" + val string_request_remote_12345_high = hex"b0 9c 98 01c780 3131312e3232322e3132332e323334" - "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, data) => + remote_host mustEqual false + port mustEqual 75 + bandwidth mustEqual 3 + data mustEqual "" 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, "") 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, data) => + remote_host mustEqual false + port mustEqual 1111 + bandwidth mustEqual 201 + data mustEqual "" + case _ => + ko + } + } + + "encode local 1111 mid" in { + val msg = VoiceHostRequest(remote_host = false, 1111, 201, "") + 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, data) => + remote_host mustEqual false + port mustEqual 1112 + bandwidth mustEqual 201 + data mustEqual "" + case _ => + ko + } + } + + "encode local 1112 mid" in { + val msg = VoiceHostRequest(remote_host = false, 1112, 201, "") + 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) => + remote mustEqual true + port mustEqual 12345 + codec mustEqual 3 + server_ip mustEqual "111.222.123.234" + case _ => + ko + } + } + + "encode remote 12345 high" in { + val msg = VoiceHostRequest(remote_host = true, port = 12345, bandwidth = 3, remote_ip = "111.222.123.234") + val pkt = PacketCoding.encodePacket(msg).require.toByteVector + + pkt mustEqual string_request_remote_12345_high } } From 88ac2f35f744f1087e88f5b5bf9a2045aeed07bf Mon Sep 17 00:00:00 2001 From: Resaec Date: Wed, 27 Dec 2023 01:47:25 +0100 Subject: [PATCH 2/2] Append opportunistic overhang data consumer --- .../packet/game/VoiceHostRequest.scala | 7 ++-- .../scala/game/VoiceHostRequestTest.scala | 34 +++++++++++-------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala b/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala index 2e143231..a5902c1b 100644 --- a/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala +++ b/src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala @@ -3,6 +3,7 @@ package net.psforever.packet.game import net.psforever.packet.{GamePacketOpcode, Marshallable, PacketHelpers, PlanetSideGamePacket} import scodec.Codec +import scodec.bits.ByteVector import scodec.codecs._ /** @@ -19,7 +20,8 @@ final case class VoiceHostRequest( remote_host: Boolean, port: Int, bandwidth: Int, - remote_ip: String + remote_ip: String, + data: ByteVector ) extends PlanetSideGamePacket { require(port > 0) require(port <= 65535) @@ -35,6 +37,7 @@ object VoiceHostRequest extends Marshallable[VoiceHostRequest] { ("remote_host" | bool) :: ("port" | uint16L) :: ("bandwidth" | uint8L) :: - ("remote_ip" | PacketHelpers.encodedStringAligned(7)) + ("remote_ip" | PacketHelpers.encodedStringAligned(7)) :: + ("data" | bytes) ).as[VoiceHostRequest] } diff --git a/src/test/scala/game/VoiceHostRequestTest.scala b/src/test/scala/game/VoiceHostRequestTest.scala index 51cae071..d1bf096c 100644 --- a/src/test/scala/game/VoiceHostRequestTest.scala +++ b/src/test/scala/game/VoiceHostRequestTest.scala @@ -7,25 +7,26 @@ import net.psforever.packet.game._ import scodec.bits._ class VoiceHostRequestTest extends Specification { - val string_request_local_75_high = hex"b0 25 80 01c000" - val string_request_local_1111_mid = hex"b0 2b 82 64c000" - val string_request_local_1112_mid = hex"b0 2c 02 64c000" - val string_request_remote_12345_high = hex"b0 9c 98 01c780 3131312e3232322e3132332e323334" + 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 local 75 high" in { PacketCoding.decodePacket(string_request_local_75_high).require match { - case VoiceHostRequest(remote_host, port, bandwidth, data) => + case VoiceHostRequest(remote_host, port, bandwidth, server_ip, data) => remote_host mustEqual false port mustEqual 75 bandwidth mustEqual 3 - data mustEqual "" + server_ip mustEqual "" + data mustEqual ByteVector.empty case _ => ko } } "encode local 75 high" in { - val msg = VoiceHostRequest(remote_host = false, 75, 3, "") + val msg = VoiceHostRequest(remote_host = false, 75, 3, "", ByteVector.empty) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual string_request_local_75_high @@ -33,18 +34,19 @@ class VoiceHostRequestTest extends Specification { "decode local 1111 mid" in { PacketCoding.decodePacket(string_request_local_1111_mid).require match { - case VoiceHostRequest(remote_host, port, bandwidth, data) => + case VoiceHostRequest(remote_host, port, bandwidth, server_ip, data) => remote_host mustEqual false port mustEqual 1111 bandwidth mustEqual 201 - data mustEqual "" + server_ip mustEqual "" + data mustEqual ByteVector.empty case _ => ko } } "encode local 1111 mid" in { - val msg = VoiceHostRequest(remote_host = false, 1111, 201, "") + val msg = VoiceHostRequest(remote_host = false, 1111, 201, "", ByteVector.empty) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual string_request_local_1111_mid @@ -52,18 +54,19 @@ class VoiceHostRequestTest extends Specification { "decode local 1112 mid" in { PacketCoding.decodePacket(string_request_local_1112_mid).require match { - case VoiceHostRequest(remote_host, port, bandwidth, data) => + case VoiceHostRequest(remote_host, port, bandwidth, server_ip, data) => remote_host mustEqual false port mustEqual 1112 bandwidth mustEqual 201 - data mustEqual "" + server_ip mustEqual "" + data mustEqual ByteVector.empty case _ => ko } } "encode local 1112 mid" in { - val msg = VoiceHostRequest(remote_host = false, 1112, 201, "") + val msg = VoiceHostRequest(remote_host = false, 1112, 201, "", ByteVector.empty) val pkt = PacketCoding.encodePacket(msg).require.toByteVector pkt mustEqual string_request_local_1112_mid @@ -71,18 +74,19 @@ class VoiceHostRequestTest extends Specification { "decode remote 12345 high" in { PacketCoding.decodePacket(string_request_remote_12345_high).require match { - case VoiceHostRequest(remote, port, codec, server_ip) => + 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") + 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