From 5d54dc8929e86c7ba236ceaf94a41fdb9d76d701 Mon Sep 17 00:00:00 2001 From: Anthony Birkett Date: Mon, 31 May 2021 18:52:56 +0100 Subject: [PATCH] Move the response array logic into classes. --- Examples/Example.php | 2 +- Examples/RconExample.php | 2 +- Examples/View.php | 2 +- SourceQuery/Buffer.php | 16 ++ .../GoldSourceInfoQueryResponse.php | 65 ++++++ .../QueryResponse/PlayersQueryResponse.php | 44 ++++ .../QueryResponse/RulesQueryResponse.php | 42 ++++ .../QueryResponse/SourceInfoQueryResponse.php | 113 ++++++++++ SourceQuery/Rcon/RconInterface.php | 3 - SourceQuery/Rcon/TestableRcon.php | 48 +++++ SourceQuery/Socket/TestableSocket.php | 2 +- SourceQuery/SourceQuery.php | 204 ++---------------- SourceQuery/SourceQueryFactory.php | 12 +- Tests/Tests.php | 35 +-- 14 files changed, 383 insertions(+), 207 deletions(-) create mode 100644 SourceQuery/QueryResponse/GoldSourceInfoQueryResponse.php create mode 100644 SourceQuery/QueryResponse/PlayersQueryResponse.php create mode 100644 SourceQuery/QueryResponse/RulesQueryResponse.php create mode 100644 SourceQuery/QueryResponse/SourceInfoQueryResponse.php create mode 100644 SourceQuery/Rcon/TestableRcon.php diff --git a/Examples/Example.php b/Examples/Example.php index abbbdd3..edb8273 100644 --- a/Examples/Example.php +++ b/Examples/Example.php @@ -6,7 +6,7 @@ require_once __DIR__ . '/../vendor/autoload.php'; use xPaw\SourceQuery\SourceQueryFactory; -// For the sake of this example +// For the sake of this example. header('Content-Type: text/plain'); header('X-Content-Type-Options: nosniff'); diff --git a/Examples/RconExample.php b/Examples/RconExample.php index 2304a4b..a53da4e 100644 --- a/Examples/RconExample.php +++ b/Examples/RconExample.php @@ -6,7 +6,7 @@ require_once __DIR__ . '/../vendor/autoload.php'; use xPaw\SourceQuery\SourceQueryFactory; -// For the sake of this example +// For the sake of this example. header('Content-Type: text/plain'); header('X-Content-Type-Options: nosniff'); diff --git a/Examples/View.php b/Examples/View.php index 3afb7f3..db6f001 100644 --- a/Examples/View.php +++ b/Examples/View.php @@ -17,7 +17,7 @@ $exception = null; try { $query->connect('localhost', 27015); - //$query->setUseOldGetChallengeMethod( true ); // Use this when players/rules retrieval fails on games like Starbound + //$query->setUseOldGetChallengeMethod(true); // Use this when players/rules retrieval fails on games like Starbound. $info = $query->getInfo(); $players = $query->getPlayers(); diff --git a/SourceQuery/Buffer.php b/SourceQuery/Buffer.php index d4a038b..e6dbf51 100644 --- a/SourceQuery/Buffer.php +++ b/SourceQuery/Buffer.php @@ -93,6 +93,22 @@ final class Buffer return ord($this->get(1)); } + /** + * Get byte (boolean) from buffer. + */ + public function getBool(): bool + { + return 1 === $this->getByte(); + } + + /** + * Get byte (character) from buffer. + */ + public function getChar(): string + { + return chr($this->getByte()); + } + /** * Get short from buffer. * diff --git a/SourceQuery/QueryResponse/GoldSourceInfoQueryResponse.php b/SourceQuery/QueryResponse/GoldSourceInfoQueryResponse.php new file mode 100644 index 0000000..d22598f --- /dev/null +++ b/SourceQuery/QueryResponse/GoldSourceInfoQueryResponse.php @@ -0,0 +1,65 @@ +getString(); + $server['HostName'] = $buffer->getString(); + $server['Map'] = $buffer->getString(); + $server['ModDir'] = $buffer->getString(); + $server['ModDesc'] = $buffer->getString(); + $server['Players'] = $buffer->getByte(); + $server['MaxPlayers'] = $buffer->getByte(); + $server['Protocol'] = $buffer->getByte(); + $server['Dedicated'] = $buffer->getChar(); + $server['Os'] = $buffer->getChar(); + $server['Password'] = $buffer->getBool(); + $server['IsMod'] = $buffer->getBool(); + + if ($server['IsMod']) { + $mod = []; + $mod['Url'] = $buffer->getString(); + $mod['Download'] = $buffer->getString(); + $buffer->get(1); // NULL byte + $mod['Version'] = $buffer->getLong(); + $mod['Size'] = $buffer->getLong(); + $mod['ServerSide'] = $buffer->getBool(); + $mod['CustomDLL'] = $buffer->getBool(); + + $server['Mod'] = $mod; + } + + $server['Secure'] = $buffer->getBool(); + $server['Bots'] = $buffer->getByte(); + + return $server; + } +} diff --git a/SourceQuery/QueryResponse/PlayersQueryResponse.php b/SourceQuery/QueryResponse/PlayersQueryResponse.php new file mode 100644 index 0000000..fdae7c1 --- /dev/null +++ b/SourceQuery/QueryResponse/PlayersQueryResponse.php @@ -0,0 +1,44 @@ +getByte(); + + while ($count-- > 0 && !$buffer->isEmpty()) { + $player = []; + $player['Id'] = $buffer->getByte(); // PlayerID, is it just always 0? + $player['Name'] = $buffer->getString(); + $player['Frags'] = $buffer->getLong(); + $player['Time'] = (int) $buffer->getFloat(); + $player['TimeF'] = gmdate(($player['Time'] > 3600 ? 'H:i:s' : 'i:s'), $player['Time']); + + $players[] = $player; + } + + return $players; + } +} diff --git a/SourceQuery/QueryResponse/RulesQueryResponse.php b/SourceQuery/QueryResponse/RulesQueryResponse.php new file mode 100644 index 0000000..c2f6b0e --- /dev/null +++ b/SourceQuery/QueryResponse/RulesQueryResponse.php @@ -0,0 +1,42 @@ +getShort(); + + while ($count-- > 0 && !$buffer->isEmpty()) { + $rule = $buffer->getString(); + $value = $buffer->getString(); + + if (!empty($rule)) { + $rules[$rule] = $value; + } + } + + return $rules; + } +} diff --git a/SourceQuery/QueryResponse/SourceInfoQueryResponse.php b/SourceQuery/QueryResponse/SourceInfoQueryResponse.php new file mode 100644 index 0000000..95ee2ee --- /dev/null +++ b/SourceQuery/QueryResponse/SourceInfoQueryResponse.php @@ -0,0 +1,113 @@ +getByte(); + $server['HostName'] = $buffer->getString(); + $server['Map'] = $buffer->getString(); + $server['ModDir'] = $buffer->getString(); + $server['ModDesc'] = $buffer->getString(); + $server['AppID'] = $buffer->getShort(); + $server['Players'] = $buffer->getByte(); + $server['MaxPlayers'] = $buffer->getByte(); + $server['Bots'] = $buffer->getByte(); + $server['Dedicated'] = $buffer->getChar(); + $server['Os'] = $buffer->getChar(); + $server['Password'] = $buffer->getBool(); + $server['Secure'] = $buffer->getBool(); + + // The Ship (they violate query protocol spec by modifying the response) + if (2400 === $server['AppID']) { + $server['GameMode'] = $buffer->getByte(); + $server['WitnessCount'] = $buffer->getByte(); + $server['WitnessTime'] = $buffer->getByte(); + } + + $server['Version'] = $buffer->getString(); + + if ($buffer->isEmpty()) { + return $server; + } + + $flags = $buffer->getByte(); + + $server['ExtraDataFlags'] = $flags; + + // S2A_EXTRA_DATA_HAS_GAME_PORT - Next 2 bytes include the game port. + if ($flags & 0x80) { + $server['GamePort'] = $buffer->getShort(); + } + + // S2A_EXTRA_DATA_HAS_STEAMID - Next 8 bytes are the steamID. + // Want to play around with this? + // You can use https://github.com/xPaw/SteamID.php + if ($flags & 0x10) { + $steamIdLower = $buffer->getUnsignedLong(); + $steamIdInstance = $buffer->getUnsignedLong(); // This gets shifted by 32 bits, which should be steamid instance. + + if (PHP_INT_SIZE === 4) { + if (extension_loaded('gmp')) { + $steamIdLower = gmp_abs($steamIdLower); + $steamIdInstance = gmp_abs($steamIdInstance); + $steamId = gmp_strval(gmp_or($steamIdLower, gmp_mul($steamIdInstance, gmp_pow(2, 32)))); + } else { + throw new RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.'); + } + } else { + $steamId = $steamIdLower | ($steamIdInstance << 32); + } + + $server['SteamID'] = $steamId; + + unset($steamIdLower, $steamIdInstance, $steamId); + } + + // S2A_EXTRA_DATA_HAS_SPECTATOR_DATA - Next 2 bytes include the spectator port, then the spectator server name. + if ($flags & 0x40) { + $server['SpecPort'] = $buffer->getShort(); + $server['SpecName'] = $buffer->getString(); + } + + // S2A_EXTRA_DATA_HAS_GAMETAG_DATA - Next bytes are the game tag string. + if ($flags & 0x20) { + $server['GameTags'] = $buffer->getString(); + } + + // S2A_EXTRA_DATA_GAMEID - Next 8 bytes are the gameID of the server. + if ($flags & 0x01) { + $server['GameID'] = $buffer->getUnsignedLong() | ($buffer->getUnsignedLong() << 32); + } + + if (!$buffer->isEmpty()) { + throw new InvalidPacketException('GetInfo: unread data? ' . $buffer->remaining() . ' bytes remaining in the buffer. Please report it to the library developer.', InvalidPacketException::BUFFER_NOT_EMPTY); + } + + return $server; + } +} diff --git a/SourceQuery/Rcon/RconInterface.php b/SourceQuery/Rcon/RconInterface.php index b1ccc9f..c7de4f3 100644 --- a/SourceQuery/Rcon/RconInterface.php +++ b/SourceQuery/Rcon/RconInterface.php @@ -17,12 +17,9 @@ namespace xPaw\SourceQuery\Rcon; use xPaw\SourceQuery\Exception\AuthenticationException; use xPaw\SourceQuery\Exception\InvalidPacketException; -use xPaw\SourceQuery\Socket\SocketInterface; interface RconInterface { - public function __construct(SocketInterface $socket); - /** * Open. */ diff --git a/SourceQuery/Rcon/TestableRcon.php b/SourceQuery/Rcon/TestableRcon.php new file mode 100644 index 0000000..a0e9d31 --- /dev/null +++ b/SourceQuery/Rcon/TestableRcon.php @@ -0,0 +1,48 @@ +packetQueue = []; $this->type = $type; diff --git a/SourceQuery/SourceQuery.php b/SourceQuery/SourceQuery.php index 7ab1d69..4bcc911 100644 --- a/SourceQuery/SourceQuery.php +++ b/SourceQuery/SourceQuery.php @@ -15,14 +15,15 @@ declare(strict_types=1); namespace xPaw\SourceQuery; -use RuntimeException; use xPaw\SourceQuery\Exception\AuthenticationException; use xPaw\SourceQuery\Exception\InvalidArgumentException; use xPaw\SourceQuery\Exception\InvalidPacketException; use xPaw\SourceQuery\Exception\SocketException; -use xPaw\SourceQuery\Rcon\GoldSourceRcon; +use xPaw\SourceQuery\QueryResponse\GoldSourceInfoQueryResponse; +use xPaw\SourceQuery\QueryResponse\PlayersQueryResponse; +use xPaw\SourceQuery\QueryResponse\RulesQueryResponse; +use xPaw\SourceQuery\QueryResponse\SourceInfoQueryResponse; use xPaw\SourceQuery\Rcon\RconInterface; -use xPaw\SourceQuery\Rcon\SourceRcon; use xPaw\SourceQuery\Socket\SocketInterface; use xPaw\SourceQuery\Socket\SocketType; @@ -64,7 +65,7 @@ final class SourceQuery /** * Points to rcon class. */ - private ?RconInterface $rcon; + private RconInterface $rcon; /** * Points to socket class. @@ -76,6 +77,11 @@ final class SourceQuery */ private bool $connected = false; + /** + * True if we have opened an Rcon connection, false if not. + */ + private bool $rconConnected = false; + /** * Contains challenge. */ @@ -86,10 +92,10 @@ final class SourceQuery */ private bool $useOldGetChallengeMethod = false; - public function __construct(SocketInterface $socket) + public function __construct(SocketInterface $socket, RconInterface $rcon) { $this->socket = $socket; - $this->rcon = null; + $this->rcon = $rcon; } /** @@ -128,31 +134,19 @@ final class SourceQuery public function disconnect(): void { $this->connected = false; + $this->rconConnected = false; $this->challenge = ''; $this->socket->close(); - - if ($this->rcon) { - $this->rcon->close(); - - $this->rcon = null; - } + $this->rcon->close(); } /** * Forces GetChallenge to use old method for challenge retrieval because some games use outdated protocol (e.g Starbound). - * - * @param bool $value Set to true to force old method - * - * @return bool Previous value */ - public function setUseOldGetChallengeMethod(bool $value): bool + public function setUseOldGetChallengeMethod(bool $value): void { - $previous = $this->useOldGetChallengeMethod; - - $this->useOldGetChallengeMethod = true === $value; - - return $previous; + $this->useOldGetChallengeMethod = $value; } /** @@ -197,7 +191,6 @@ final class SourceQuery $buffer = $this->socket->read(); $type = $buffer->getByte(); - $server = []; if (self::S2C_CHALLENGE === $type) { $this->challenge = $buffer->get(4); @@ -209,125 +202,14 @@ final class SourceQuery // Old GoldSource protocol, HLTV still uses it. if (self::S2A_INFO_OLD === $type && SocketType::GOLDSOURCE === $this->socket->getType()) { - /* - * If we try to read data again, and we get the result with type S2A_INFO (0x49) - * That means this server is running dproto, - * Because it sends answer for both protocols - */ - - $server['Address'] = $buffer->getString(); - $server['HostName'] = $buffer->getString(); - $server['Map'] = $buffer->getString(); - $server['ModDir'] = $buffer->getString(); - $server['ModDesc'] = $buffer->getString(); - $server['Players'] = $buffer->getByte(); - $server['MaxPlayers'] = $buffer->getByte(); - $server['Protocol'] = $buffer->getByte(); - $server['Dedicated'] = chr($buffer->getByte()); - $server['Os'] = chr($buffer->getByte()); - $server['Password'] = 1 === $buffer->getByte(); - $server['IsMod'] = 1 === $buffer->getByte(); - - if ($server['IsMod']) { - $Mod = []; - $Mod['Url'] = $buffer->getString(); - $Mod['Download'] = $buffer->getString(); - $buffer->get(1); // NULL byte - $Mod['Version'] = $buffer->getLong(); - $Mod['Size'] = $buffer->getLong(); - $Mod['ServerSide'] = 1 === $buffer->getByte(); - $Mod['CustomDLL'] = 1 === $buffer->getByte(); - $server['Mod'] = $Mod; - } - - $server['Secure'] = 1 === $buffer->getByte(); - $server['Bots'] = $buffer->getByte(); - - return $server; + return GoldSourceInfoQueryResponse::fromBuffer($buffer); } if (self::S2A_INFO_SRC !== $type) { throw new InvalidPacketException('GetInfo: Packet header mismatch. (0x' . dechex($type) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH); } - $server['Protocol'] = $buffer->getByte(); - $server['HostName'] = $buffer->getString(); - $server['Map'] = $buffer->getString(); - $server['ModDir'] = $buffer->getString(); - $server['ModDesc'] = $buffer->getString(); - $server['AppID'] = $buffer->getShort(); - $server['Players'] = $buffer->getByte(); - $server['MaxPlayers'] = $buffer->getByte(); - $server['Bots'] = $buffer->getByte(); - $server['Dedicated'] = chr($buffer->getByte()); - $server['Os'] = chr($buffer->getByte()); - $server['Password'] = 1 === $buffer->getByte(); - $server['Secure'] = 1 === $buffer->getByte(); - - // The Ship (they violate query protocol spec by modifying the response) - if (2400 === $server['AppID']) { - $server['GameMode'] = $buffer->getByte(); - $server['WitnessCount'] = $buffer->getByte(); - $server['WitnessTime'] = $buffer->getByte(); - } - - $server['Version'] = $buffer->getString(); - - // Extra Data Flags. - if ($buffer->remaining() > 0) { - $server['ExtraDataFlags'] = $Flags = $buffer->getByte(); - - // S2A_EXTRA_DATA_HAS_GAME_PORT - Next 2 bytes include the game port. - if ($Flags & 0x80) { - $server['GamePort'] = $buffer->getShort(); - } - - // S2A_EXTRA_DATA_HAS_STEAMID - Next 8 bytes are the steamID. - // Want to play around with this? - // You can use https://github.com/xPaw/SteamID.php - if ($Flags & 0x10) { - $steamIdLower = $buffer->getUnsignedLong(); - $steamIdInstance = $buffer->getUnsignedLong(); // This gets shifted by 32 bits, which should be steamid instance. - - if (PHP_INT_SIZE === 4) { - if (extension_loaded('gmp')) { - $steamIdLower = gmp_abs($steamIdLower); - $steamIdInstance = gmp_abs($steamIdInstance); - $steamId = gmp_strval(gmp_or($steamIdLower, gmp_mul($steamIdInstance, gmp_pow(2, 32)))); - } else { - throw new RuntimeException('Either 64-bit PHP installation or "gmp" module is required to correctly parse server\'s steamid.'); - } - } else { - $steamId = $steamIdLower | ($steamIdInstance << 32); - } - - $server['SteamID'] = $steamId; - - unset($steamIdLower, $steamIdInstance, $steamId); - } - - // S2A_EXTRA_DATA_HAS_SPECTATOR_DATA - Next 2 bytes include the spectator port, then the spectator server name. - if ($Flags & 0x40) { - $server['SpecPort'] = $buffer->getShort(); - $server['SpecName'] = $buffer->getString(); - } - - // S2A_EXTRA_DATA_HAS_GAMETAG_DATA - Next bytes are the game tag string. - if ($Flags & 0x20) { - $server['GameTags'] = $buffer->getString(); - } - - // S2A_EXTRA_DATA_GAMEID - Next 8 bytes are the gameID of the server. - if ($Flags & 0x01) { - $server['GameID'] = $buffer->getUnsignedLong() | ($buffer->getUnsignedLong() << 32); - } - - if (!$buffer->isEmpty()) { - throw new InvalidPacketException('GetInfo: unread data? ' . $buffer->remaining() . ' bytes remaining in the buffer. Please report it to the library developer.', InvalidPacketException::BUFFER_NOT_EMPTY); - } - } - - return $server; + return SourceInfoQueryResponse::fromBuffer($buffer); } /** @@ -356,21 +238,7 @@ final class SourceQuery throw new InvalidPacketException('GetPlayers: Packet header mismatch. (0x' . dechex($type) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH); } - $players = []; - $count = $buffer->getByte(); - - while ($count-- > 0 && !$buffer->isEmpty()) { - $player = []; - $player['Id'] = $buffer->getByte(); // PlayerID, is it just always 0? - $player['Name'] = $buffer->getString(); - $player['Frags'] = $buffer->getLong(); - $player['Time'] = (int) $buffer->getFloat(); - $player['TimeF'] = gmdate(($player['Time'] > 3600 ? 'H:i:s' : 'i:s'), $player['Time']); - - $players[] = $player; - } - - return $players; + return PlayersQueryResponse::fromBuffer($buffer); } /** @@ -398,19 +266,7 @@ final class SourceQuery throw new InvalidPacketException('GetRules: Packet header mismatch. (0x' . dechex($type) . ')', InvalidPacketException::PACKET_HEADER_MISMATCH); } - $rules = []; - $count = $buffer->getShort(); - - while ($count-- > 0 && !$buffer->isEmpty()) { - $rule = $buffer->getString(); - $value = $buffer->getString(); - - if (!empty($rule)) { - $rules[$rule] = $value; - } - } - - return $rules; + return RulesQueryResponse::fromBuffer($buffer); } /** @@ -419,7 +275,6 @@ final class SourceQuery * @param string $password Rcon Password * * @throws AuthenticationException - * @throws InvalidPacketException * @throws SocketException */ public function setRconPassword(string $password): void @@ -428,23 +283,10 @@ final class SourceQuery throw new SocketException('Not connected.', SocketException::NOT_CONNECTED); } - switch ($this->socket->getType()) { - case SocketType::GOLDSOURCE: - $this->rcon = new GoldSourceRcon($this->socket); - - break; - - case SocketType::SOURCE: - $this->rcon = new SourceRcon($this->socket); - - break; - - default: - throw new SocketException('Unknown engine.', SocketException::INVALID_ENGINE); - } - $this->rcon->open(); $this->rcon->authorize($password); + + $this->rconConnected = true; } /** @@ -464,7 +306,7 @@ final class SourceQuery throw new SocketException('Not connected.', SocketException::NOT_CONNECTED); } - if (null === $this->rcon) { + if (!$this->rconConnected) { throw new SocketException('You must set a RCON password before trying to execute a RCON command.', SocketException::NOT_CONNECTED); } diff --git a/SourceQuery/SourceQueryFactory.php b/SourceQuery/SourceQueryFactory.php index c8c8e6b..e7c9c15 100644 --- a/SourceQuery/SourceQueryFactory.php +++ b/SourceQuery/SourceQueryFactory.php @@ -4,6 +4,8 @@ declare(strict_types=1); namespace xPaw\SourceQuery; +use xPaw\SourceQuery\Rcon\GoldSourceRcon; +use xPaw\SourceQuery\Rcon\SourceRcon; use xPaw\SourceQuery\Socket\GoldSourceSocket; use xPaw\SourceQuery\Socket\SourceSocket; @@ -11,11 +13,17 @@ final class SourceQueryFactory { public static function createGoldSourceQuery(): SourceQuery { - return new SourceQuery(new SourceSocket()); + $socket = new SourceSocket(); + $rcon = new SourceRcon($socket); + + return new SourceQuery($socket, $rcon); } public static function createSourceQuery(): SourceQuery { - return new SourceQuery(new GoldSourceSocket()); + $socket = new GoldSourceSocket(); + $rcon = new GoldSourceRcon($socket); + + return new SourceQuery($socket, $rcon); } } diff --git a/Tests/Tests.php b/Tests/Tests.php index c4d8af3..61ea988 100644 --- a/Tests/Tests.php +++ b/Tests/Tests.php @@ -7,6 +7,7 @@ use xPaw\SourceQuery\Exception\AuthenticationException; use xPaw\SourceQuery\Exception\InvalidArgumentException; use xPaw\SourceQuery\Exception\InvalidPacketException; use xPaw\SourceQuery\Exception\SocketException; +use xPaw\SourceQuery\Rcon\TestableRcon; use xPaw\SourceQuery\Socket\SocketType; use xPaw\SourceQuery\Socket\TestableSocket; use xPaw\SourceQuery\SourceQuery; @@ -25,7 +26,7 @@ final class Tests extends TestCase public function testInvalidTimeout(): void { $this->expectException(InvalidArgumentException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->disconnect(); $sourceQuery->connect('', 2, -1); @@ -39,7 +40,7 @@ final class Tests extends TestCase public function testNotConnectedGetInfo(): void { $this->expectException(SocketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->disconnect(); $sourceQuery->getInfo(); @@ -52,7 +53,7 @@ final class Tests extends TestCase public function testNotConnectedPing(): void { $this->expectException(SocketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->disconnect(); $sourceQuery->ping(); @@ -66,7 +67,7 @@ final class Tests extends TestCase public function testNotConnectedGetPlayers(): void { $this->expectException(SocketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->disconnect(); $sourceQuery->getPlayers(); @@ -80,7 +81,7 @@ final class Tests extends TestCase public function testNotConnectedGetRules(): void { $this->expectException(SocketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->disconnect(); $sourceQuery->getRules(); @@ -90,12 +91,11 @@ final class Tests extends TestCase * @throws InvalidArgumentException * @throws SocketException * @throws AuthenticationException - * @throws InvalidPacketException */ public function testNotConnectedSetRconPassword(): void { $this->expectException(SocketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->disconnect(); $sourceQuery->setRconPassword('a'); @@ -110,7 +110,7 @@ final class Tests extends TestCase public function testNotConnectedRcon(): void { $this->expectException(SocketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->disconnect(); $sourceQuery->rcon('a'); @@ -125,7 +125,7 @@ final class Tests extends TestCase public function testRconWithoutPassword(): void { $this->expectException(SocketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $sourceQuery->rcon('a'); } @@ -171,7 +171,7 @@ final class Tests extends TestCase public function testBadGetInfo(string $data): void { $this->expectException(InvalidPacketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $socket->queue($data); @@ -188,7 +188,7 @@ final class Tests extends TestCase public function testBadGetChallengeViaPlayers(string $data): void { $this->expectException(InvalidPacketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $socket->queue($data); @@ -205,7 +205,7 @@ final class Tests extends TestCase public function testBadGetPlayersAfterCorrectChallenge(string $data): void { $this->expectException(InvalidPacketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $socket->queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11"); $socket->queue($data); @@ -223,7 +223,7 @@ final class Tests extends TestCase public function testBadGetRulesAfterCorrectChallenge(string $data): void { $this->expectException(InvalidPacketException::class); - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $socket->queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11"); $socket->queue($data); @@ -255,7 +255,7 @@ final class Tests extends TestCase */ public function testGetChallengeTwice(): void { - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $socket->queue("\xFF\xFF\xFF\xFF\x41\x11\x11\x11\x11"); $socket->queue("\xFF\xFF\xFF\xFF\x45\x01\x00ayy\x00lmao\x00"); @@ -323,7 +323,7 @@ final class Tests extends TestCase */ public function testPing(): void { - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $socket->queue("\xFF\xFF\xFF\xFF\x6A\x00"); @@ -338,7 +338,8 @@ final class Tests extends TestCase */ private function create(TestableSocket $socket): SourceQuery { - $sourceQuery = new SourceQuery($socket); + $rcon = new TestableRcon(); + $sourceQuery = new SourceQuery($socket, $rcon); $sourceQuery->connect('', 2); return $sourceQuery; @@ -407,7 +408,7 @@ final class Tests extends TestCase throw new InvalidPacketException('Bad packet data'); } - $socket = new TestableSocket(SocketType::SOURCE); + $socket = new TestableSocket(); $sourceQuery = $this->create($socket); $socket->queue($data); // Challenge.