Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fully implement the VoiceHostRequest packet #1159

Merged
merged 2 commits into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 23 additions & 11 deletions src/main/scala/net/psforever/packet/game/VoiceHostRequest.scala
Original file line number Diff line number Diff line change
@@ -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._
Expand All @@ -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]
}
85 changes: 75 additions & 10 deletions src/test/scala/game/VoiceHostRequestTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
Loading