mirror of
https://github.com/YGGverse/hl-php.git
synced 2025-03-13 05:41:13 +00:00
initial release
This commit is contained in:
parent
f343894229
commit
c91e69fc73
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/vendor/
|
21
README.md
21
README.md
@ -1,2 +1,21 @@
|
||||
# hl-php
|
||||
PHP library for Half-Life API
|
||||
|
||||
PHP 8 library for Half-Life API with native IPv6 / Yggdrasil support
|
||||
|
||||
## Install
|
||||
|
||||
`composer require yggverse/hl`
|
||||
|
||||
## Usage
|
||||
|
||||
### Xash3d
|
||||
|
||||
#### Master
|
||||
|
||||
```
|
||||
$master = new Yggverse\Hl\Xash3d\Master('hl.ygg', 27010);
|
||||
|
||||
var_dump(
|
||||
$master->getServersIPv6()
|
||||
);
|
||||
```
|
17
composer.json
Normal file
17
composer.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "yggverse/hl",
|
||||
"description": "PHP 8 library for Half-Life API with native IPv6 / Yggdrasil support ",
|
||||
"type": "library",
|
||||
"license": "MIT",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Yggverse\\Hl\\": "src/"
|
||||
}
|
||||
},
|
||||
"authors": [
|
||||
{
|
||||
"name": "YGGverse"
|
||||
}
|
||||
],
|
||||
"require": {}
|
||||
}
|
125
src/Xash3D/Master.php
Normal file
125
src/Xash3D/Master.php
Normal file
@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Yggverse\Hl\Xash3d;
|
||||
|
||||
class Master
|
||||
{
|
||||
private $_socket;
|
||||
|
||||
public function __construct(
|
||||
string $host,
|
||||
int $port,
|
||||
int $timeout = 5
|
||||
)
|
||||
{
|
||||
$this->_socket = fsockopen(
|
||||
"udp://{$host}",
|
||||
$port
|
||||
);
|
||||
|
||||
stream_set_timeout(
|
||||
$this->_socket,
|
||||
$timeout
|
||||
);
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->_socket)
|
||||
{
|
||||
fclose(
|
||||
$this->_socket
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public static function getServersIPv6(
|
||||
int $limit = 100,
|
||||
string $region = "\xFF",
|
||||
string $host = "0.0.0.0:0",
|
||||
int $port = 0,
|
||||
string $gamedir = "valve"
|
||||
): ?array
|
||||
{
|
||||
// Is connected
|
||||
if (!$this->_socket)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Filter query
|
||||
if (!fwrite($this->_socket, "1{$region}{$host}:{$port}\0\gamedir\t{$gamedir}\0"))
|
||||
{
|
||||
fclose(
|
||||
$this->_socket
|
||||
);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Skip header
|
||||
if (!fread($this->_socket, 6))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get servers
|
||||
$servers = [];
|
||||
|
||||
for ($i = 0; $i < $limit; $i++)
|
||||
{
|
||||
// Get host
|
||||
if (false === $host = fread($this->_socket, 16))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Is end of packet
|
||||
if (true === str_starts_with($host, 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip invalid host
|
||||
if (false === $host = inet_ntop($host))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Decode first byte for port
|
||||
if (false === $byte1 = fread($this->_socket, 1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Decode second byte for port
|
||||
if (false === $byte2 = fread($this->_socket, 1))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Calculate port value
|
||||
$port = ord($byte1) * 256 + ord($byte2);
|
||||
|
||||
// Validate IPv6 result
|
||||
if (
|
||||
false !== strpos($host, '.') || // filter_var not always works with mixed IPv6
|
||||
false === filter_var($host, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) ||
|
||||
false === filter_var($port, FILTER_VALIDATE_INT)
|
||||
)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$servers["[{$host}]:{$port}"] = // keep unique
|
||||
[
|
||||
'host' => $host,
|
||||
'port' => $port
|
||||
];
|
||||
}
|
||||
|
||||
return $servers;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user