cvs: pear /Net_GameServerQuery GameServerQuery.php Games.php Games.xml Protocols.php Socket.php example1.php
| From: | Aidan Lister | Date: | Wed, 30 Jun 2004 11:38:05 +0000 |
| Subject: | cvs: pear /Net_GameServerQuery GameServerQuery.php Games.php Games.xml Protocols.php Socket.php example1.php | ||
| Groups: | php.pear.cvs | ||
| Request: | Send a blank email to pear-cvs+get-21306@lists.php.net to get a copy of this message | ||
aidan Wed Jun 30 07:38:05 2004 EDT
Added files:
/pear/Net_GameServerQuery Games.php Games.xml Protocols.php
Socket.php example1.php
Modified files:
/pear/Net_GameServerQuery GameServerQuery.php
Log:
Initial Commit
- Adding some ugly ugly code in so we can play with it
http://cvs.php.net/diff.php/pear/Net_GameServerQuery/GameServerQuery.php?r1=1.3&r2=1.4&ty=u Index: pear/Net_GameServerQuery/GameServerQuery.php diff -u /dev/null pear/Net_GameServerQuery/GameServerQuery.php:1.4 --- /dev/null Wed Jun 30 07:38:05 2004 +++ pear/Net_GameServerQuery/GameServerQuery.php Wed Jun 30 07:38:05 2004 @@ -0,0 +1,158 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ +// +----------------------------------------------------------------------+ +// | PHP version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2004 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 3.0 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available through the world-wide-web at the following url: | +// | http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Aidan Lister <aidan@php.net> | +// +----------------------------------------------------------------------+ +// +// $Id: GameServerQuery.php,v 1.4 2004/06/30 11:38:05 aidan Exp $ + + +/** + * A class to query and retrieve information from game servers + * + * @category Net + * @package Net_GameServerQuery + * @author Aidan Lister <aidan@php.net> + * @version $Revision: 1.4 $ + */ +class Net_GameServerQuery +{ + /** + * Hold the counter + * + * @var int + */ + private $_counter; + + /** + * The array of servers to query + * + * @var array + */ + private $_servers; + + /** + * A list of all protocol information + * + * @var array + */ + private $_protocol; + + /** + * A list of all game information + * + * @var array + */ + private $_game; + + + /** + * Constructor + */ + public function __construct () + { + // Initialise counter + $this->_counter = -1; + + // Load the protocol config + require 'Protocols.php'; + $this->_protocol = $protocol; + + // Load the game config + require 'Games.php'; + $this->_game = $game; + } + + + /** + * Add a server + * + * @param string $game The type of game + * @param string $ip The IP to query + * @param int $port The port to query + * @param string $status A pipe delimited string of query types + * @return int The counter + */ + public function addServer ($game, $ip, $port = null, $query = 'status') + { + // Incriment the counter + ++$this->_counter; + + // Build the list of packets to be sent + $querylist = explode('|', $query); + foreach ($querylist as $query) { + $querypackets[$query] = $this->_getpacket($game, $query); + } + + // Default port + if (is_null($port)) { + $port = $this->_protocol[$this->_game[$game]]['queryport']; + } + + // Add information to our servers array + $this->_servers[$this->_counter] = array( + 'game' => $game, + 'ip' => $ip, + 'port' => $port, + 'query' => $querypackets, + ); + + // Return the counter for identifying the server later + return $this->_counter; + } + + + /** + * Execute the query + * + * @param int $timeout The timeout in milliseconds + * @return array An array of server information + */ + public function execute ($timeout = 300) + { + // Timeout in millseconds + $timeout = $timeout * 1000; + + require_once 'Socket.php'; + $socket = new Net_GameServerQuery_Socket; + $result = $socket->go($this->_servers, $timeout); + + return $result; + } + + + /** + * Get the packet to be sent to server + * + * This should probably be moved somewhere else, I don't know where. + * + * @return string The packet + * @param string $game The game + * @param string $query The type of query + */ + private function _getpacket ($game, $query) + { + $protocol = $this->_game[$game]; + $packetformat = $this->_protocol[$protocol]['packet']; + $querystring = $this->_protocol[$protocol]['send'][$query]; + + $packet = sprintf($packetformat, $querystring); + + return $packet; + } + +} + +?> \ No newline at end of file http://cvs.php.net/co.php/pear/Net_GameServerQuery/Games.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/Games.php +++ pear/Net_GameServerQuery/Games.php <?php $game['halflife'] = 'halflife'; ?> http://cvs.php.net/co.php/pear/Net_GameServerQuery/Games.xml?r=1.1&p=1 Index: pear/Net_GameServerQuery/Games.xml +++ pear/Net_GameServerQuery/Games.xml <games> <game key="aarmy"> <name>America's Army: Operations</name> <queryport>1717</queryport> <protocol>gamespy</protocol> </game> <game key="avp2"> <name>Alien vs Predator 2</name> <queryport>27888</queryport> <protocol>gamespy</protocol> </game> <game key="bf1942"> <name>Battlefield 1942</name> <queryport>23000</queryport> <protocol>gamespy</protocol> </game> <game key="callofduty"> <name>Call of Duty</name> <queryport>28960</queryport> <protocol>quake3</protocol> </game> <game key="freelancer"> <name>Freelancer</name> <queryport>2302</queryport> <protocol>freelancer</protocol> </game> <game key="halflife"> <name>HalfLife</name> <queryport>27015</queryport> <gameport>27015</gameport> <protocol>halflife</protocol> </game> <game key="moh"> <name>Medal of Honor</name> <queryport>12300</queryport> <protocol>gamespy</protocol> </game> <game key="nwn"> <name>Neverwinter Nights</name> <queryport>5121</queryport> <protocol>gamespy</protocol> </game> <game key="quakeworld"> <name>QuakeWorld</name> <queryport>27500</queryport> <protocol>quakeworld</protocol> </game> <game key="quake2"> <name>Quake 2</name> <queryport>27910</queryport> <protocol>quakeworld</protocol> </game> <game key="quake3"> <name>Quake 3 Arena</name> <queryport>27960</queryport> <protocol>quake3</protocol> </game> <game key="rtcw"> <name>Return to Castle Wolfenstein</name> <queryport>27960</queryport> <protocol>quake3</protocol> </game> <game key="savage"> <name>Savage: The Battle For Newerth</name> <queryport>11235</queryport> <protocol>savage</protocol> </game> <game key="sof"> <name>Soldier of Fortune</name> <queryport>28910</queryport> <protocol>quake3</protocol> </game> <game key="sof2"> <name>Soldier of Fortune 2: Double Helix</name> <queryport>20100</queryport> <protocol>quake3</protocol> </game> <game key="ut2003"> <name>Unreal Tournament 2003</name> <queryport>7778</queryport> <protocol>ut2003</protocol> </game> <game key="ut2004"> <name>Unreal Tournament 2004</name> <queryport>7778</queryport> <protocol>ut2004</protocol> </game> <game key="vietcong"> <name>Vietcong</name> <queryport>15425</queryport> <protocol>gamespy</protocol> </game> </games> http://cvs.php.net/co.php/pear/Net_GameServerQuery/Protocols.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/Protocols.php +++ pear/Net_GameServerQuery/Protocols.php <?php $protocol['halflife']['name'] = 'Half-Life'; $protocol['halflife']['packet'] = "\xFF\xFF\xFF\xFF%s\x00"; $protocol['halflife']['queryport'] = '27015'; $protocol['halflife']['send']['status'] = 'infostring'; $protocol['halflife']['send']['players'] = 'players'; $protocol['halflife']['send']['rules'] = 'rules'; $protocol['halflife']['send']['ping'] = 'ping'; $protocol['gamespy']['name'] = 'GameSpy'; $protocol['gamespy']['packet'] = '%s'; ?> http://cvs.php.net/co.php/pear/Net_GameServerQuery/Socket.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/Socket.php +++ pear/Net_GameServerQuery/Socket.php <?php /** * The socket class */ class Net_GameServerQuery_Socket { /** * The sockets / list of sockets */ private $_sockets; private $_sockets_list; /** * Do the whole lot */ public function go ($servers, $timeout) { $this->_servers = $servers; $this->open($this->_servers); $result = $this->listen($timeout); $this->close(); return $result; } /** * Open */ public function open ($servers) { foreach ($servers as $key => $server) { // Open each socket $socket = @fsockopen("udp://" . $server['ip'], $server['port'], $errno, $errstr, 1); if ($socket !== false) { stream_set_blocking($socket, false); $sockets[$key] = $socket; $sockets_list[(int)$socket] = $key; foreach ($server['query'] as $packet) { $this->write($socket, $packet); } } } $this->_sockets = $sockets; $this->_sockets_list = $sockets_list; return true; } /** * Write */ public function write ($socket, $packet) { fwrite($socket, $packet); } /** * Listen */ public function listen ($timeout) { // Listen to sockets $result = array (); $starttime = microtime(true); $r = $this->_sockets; while (stream_select($r, $w = null, $e = null, 0, $timeout - ((microtime(true) - $starttime) * 1000000)) !== 0) { foreach ($r as $socket) { $response = fread($socket, 2048); $result[$this->_sockets_list[$socket]][] = $response; } $r = $this->_sockets; } return $result; } /** * Close */ public function close () { foreach ($this->_sockets as $socket) { fclose($socket); } } } ?> http://cvs.php.net/co.php/pear/Net_GameServerQuery/example1.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/example1.php +++ pear/Net_GameServerQuery/example1.php <pre> <?php include 'GameServerQuery.php'; include 'Benchmark.php'; include 'function.hexdump.php'; // load class $gsq = new Net_GameServerQuery; $bm = new Benchmark; $bm->start(); // add servers $serv1 = $gsq->addServer('halflife', '202.173.159.7', null, 'players'); $serv2 = $gsq->addServer('halflife', '202.173.159.8', null, 'status'); $serv3 = $gsq->addServer('halflife', '203.26.94.152', null, 'rules|status|players'); // fire up $result = $gsq->execute(); $bm->stop(); ksort($result); // results foreach ($result as $server => $reply) { echo "Server $server\n"; $i = 0; foreach ($reply as $packet) { ++$i; echo "Packet #$i (" . strlen($packet) . "bytes)\n"; } echo "\n"; } // benchmark echo 'Took ... ' . $bm->timems() . 'ms'; ?> </pre>
http://cvs.php.net/diff.php/pear/Net_GameServerQuery/GameServerQuery.php?r1=1.3&r2=1.4&ty=u Index: pear/Net_GameServerQuery/GameServerQuery.php diff -u /dev/null pear/Net_GameServerQuery/GameServerQuery.php:1.4 --- /dev/null Wed Jun 30 07:38:05 2004 +++ pear/Net_GameServerQuery/GameServerQuery.php Wed Jun 30 07:38:05 2004 @@ -0,0 +1,158 @@ +<?php +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ +// +----------------------------------------------------------------------+ +// | PHP version 4 | +// +----------------------------------------------------------------------+ +// | Copyright (c) 1997-2004 The PHP Group | +// +----------------------------------------------------------------------+ +// | This source file is subject to version 3.0 of the PHP license, | +// | that is bundled with this package in the file LICENSE, and is | +// | available through the world-wide-web at the following url: | +// | http://www.php.net/license/3_0.txt. | +// | If you did not receive a copy of the PHP license and are unable to | +// | obtain it through the world-wide-web, please send a note to | +// | license@php.net so we can mail you a copy immediately. | +// +----------------------------------------------------------------------+ +// | Authors: Aidan Lister <aidan@php.net> | +// +----------------------------------------------------------------------+ +// +// $Id: GameServerQuery.php,v 1.4 2004/06/30 11:38:05 aidan Exp $ + + +/** + * A class to query and retrieve information from game servers + * + * @category Net + * @package Net_GameServerQuery + * @author Aidan Lister <aidan@php.net> + * @version $Revision: 1.4 $ + */ +class Net_GameServerQuery +{ + /** + * Hold the counter + * + * @var int + */ + private $_counter; + + /** + * The array of servers to query + * + * @var array + */ + private $_servers; + + /** + * A list of all protocol information + * + * @var array + */ + private $_protocol; + + /** + * A list of all game information + * + * @var array + */ + private $_game; + + + /** + * Constructor + */ + public function __construct () + { + // Initialise counter + $this->_counter = -1; + + // Load the protocol config + require 'Protocols.php'; + $this->_protocol = $protocol; + + // Load the game config + require 'Games.php'; + $this->_game = $game; + } + + + /** + * Add a server + * + * @param string $game The type of game + * @param string $ip The IP to query + * @param int $port The port to query + * @param string $status A pipe delimited string of query types + * @return int The counter + */ + public function addServer ($game, $ip, $port = null, $query = 'status') + { + // Incriment the counter + ++$this->_counter; + + // Build the list of packets to be sent + $querylist = explode('|', $query); + foreach ($querylist as $query) { + $querypackets[$query] = $this->_getpacket($game, $query); + } + + // Default port + if (is_null($port)) { + $port = $this->_protocol[$this->_game[$game]]['queryport']; + } + + // Add information to our servers array + $this->_servers[$this->_counter] = array( + 'game' => $game, + 'ip' => $ip, + 'port' => $port, + 'query' => $querypackets, + ); + + // Return the counter for identifying the server later + return $this->_counter; + } + + + /** + * Execute the query + * + * @param int $timeout The timeout in milliseconds + * @return array An array of server information + */ + public function execute ($timeout = 300) + { + // Timeout in millseconds + $timeout = $timeout * 1000; + + require_once 'Socket.php'; + $socket = new Net_GameServerQuery_Socket; + $result = $socket->go($this->_servers, $timeout); + + return $result; + } + + + /** + * Get the packet to be sent to server + * + * This should probably be moved somewhere else, I don't know where. + * + * @return string The packet + * @param string $game The game + * @param string $query The type of query + */ + private function _getpacket ($game, $query) + { + $protocol = $this->_game[$game]; + $packetformat = $this->_protocol[$protocol]['packet']; + $querystring = $this->_protocol[$protocol]['send'][$query]; + + $packet = sprintf($packetformat, $querystring); + + return $packet; + } + +} + +?> \ No newline at end of file http://cvs.php.net/co.php/pear/Net_GameServerQuery/Games.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/Games.php +++ pear/Net_GameServerQuery/Games.php <?php $game['halflife'] = 'halflife'; ?> http://cvs.php.net/co.php/pear/Net_GameServerQuery/Games.xml?r=1.1&p=1 Index: pear/Net_GameServerQuery/Games.xml +++ pear/Net_GameServerQuery/Games.xml <games> <game key="aarmy"> <name>America's Army: Operations</name> <queryport>1717</queryport> <protocol>gamespy</protocol> </game> <game key="avp2"> <name>Alien vs Predator 2</name> <queryport>27888</queryport> <protocol>gamespy</protocol> </game> <game key="bf1942"> <name>Battlefield 1942</name> <queryport>23000</queryport> <protocol>gamespy</protocol> </game> <game key="callofduty"> <name>Call of Duty</name> <queryport>28960</queryport> <protocol>quake3</protocol> </game> <game key="freelancer"> <name>Freelancer</name> <queryport>2302</queryport> <protocol>freelancer</protocol> </game> <game key="halflife"> <name>HalfLife</name> <queryport>27015</queryport> <gameport>27015</gameport> <protocol>halflife</protocol> </game> <game key="moh"> <name>Medal of Honor</name> <queryport>12300</queryport> <protocol>gamespy</protocol> </game> <game key="nwn"> <name>Neverwinter Nights</name> <queryport>5121</queryport> <protocol>gamespy</protocol> </game> <game key="quakeworld"> <name>QuakeWorld</name> <queryport>27500</queryport> <protocol>quakeworld</protocol> </game> <game key="quake2"> <name>Quake 2</name> <queryport>27910</queryport> <protocol>quakeworld</protocol> </game> <game key="quake3"> <name>Quake 3 Arena</name> <queryport>27960</queryport> <protocol>quake3</protocol> </game> <game key="rtcw"> <name>Return to Castle Wolfenstein</name> <queryport>27960</queryport> <protocol>quake3</protocol> </game> <game key="savage"> <name>Savage: The Battle For Newerth</name> <queryport>11235</queryport> <protocol>savage</protocol> </game> <game key="sof"> <name>Soldier of Fortune</name> <queryport>28910</queryport> <protocol>quake3</protocol> </game> <game key="sof2"> <name>Soldier of Fortune 2: Double Helix</name> <queryport>20100</queryport> <protocol>quake3</protocol> </game> <game key="ut2003"> <name>Unreal Tournament 2003</name> <queryport>7778</queryport> <protocol>ut2003</protocol> </game> <game key="ut2004"> <name>Unreal Tournament 2004</name> <queryport>7778</queryport> <protocol>ut2004</protocol> </game> <game key="vietcong"> <name>Vietcong</name> <queryport>15425</queryport> <protocol>gamespy</protocol> </game> </games> http://cvs.php.net/co.php/pear/Net_GameServerQuery/Protocols.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/Protocols.php +++ pear/Net_GameServerQuery/Protocols.php <?php $protocol['halflife']['name'] = 'Half-Life'; $protocol['halflife']['packet'] = "\xFF\xFF\xFF\xFF%s\x00"; $protocol['halflife']['queryport'] = '27015'; $protocol['halflife']['send']['status'] = 'infostring'; $protocol['halflife']['send']['players'] = 'players'; $protocol['halflife']['send']['rules'] = 'rules'; $protocol['halflife']['send']['ping'] = 'ping'; $protocol['gamespy']['name'] = 'GameSpy'; $protocol['gamespy']['packet'] = '%s'; ?> http://cvs.php.net/co.php/pear/Net_GameServerQuery/Socket.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/Socket.php +++ pear/Net_GameServerQuery/Socket.php <?php /** * The socket class */ class Net_GameServerQuery_Socket { /** * The sockets / list of sockets */ private $_sockets; private $_sockets_list; /** * Do the whole lot */ public function go ($servers, $timeout) { $this->_servers = $servers; $this->open($this->_servers); $result = $this->listen($timeout); $this->close(); return $result; } /** * Open */ public function open ($servers) { foreach ($servers as $key => $server) { // Open each socket $socket = @fsockopen("udp://" . $server['ip'], $server['port'], $errno, $errstr, 1); if ($socket !== false) { stream_set_blocking($socket, false); $sockets[$key] = $socket; $sockets_list[(int)$socket] = $key; foreach ($server['query'] as $packet) { $this->write($socket, $packet); } } } $this->_sockets = $sockets; $this->_sockets_list = $sockets_list; return true; } /** * Write */ public function write ($socket, $packet) { fwrite($socket, $packet); } /** * Listen */ public function listen ($timeout) { // Listen to sockets $result = array (); $starttime = microtime(true); $r = $this->_sockets; while (stream_select($r, $w = null, $e = null, 0, $timeout - ((microtime(true) - $starttime) * 1000000)) !== 0) { foreach ($r as $socket) { $response = fread($socket, 2048); $result[$this->_sockets_list[$socket]][] = $response; } $r = $this->_sockets; } return $result; } /** * Close */ public function close () { foreach ($this->_sockets as $socket) { fclose($socket); } } } ?> http://cvs.php.net/co.php/pear/Net_GameServerQuery/example1.php?r=1.1&p=1 Index: pear/Net_GameServerQuery/example1.php +++ pear/Net_GameServerQuery/example1.php <pre> <?php include 'GameServerQuery.php'; include 'Benchmark.php'; include 'function.hexdump.php'; // load class $gsq = new Net_GameServerQuery; $bm = new Benchmark; $bm->start(); // add servers $serv1 = $gsq->addServer('halflife', '202.173.159.7', null, 'players'); $serv2 = $gsq->addServer('halflife', '202.173.159.8', null, 'status'); $serv3 = $gsq->addServer('halflife', '203.26.94.152', null, 'rules|status|players'); // fire up $result = $gsq->execute(); $bm->stop(); ksort($result); // results foreach ($result as $server => $reply) { echo "Server $server\n"; $i = 0; foreach ($reply as $packet) { ++$i; echo "Packet #$i (" . strlen($packet) . "bytes)\n"; } echo "\n"; } // benchmark echo 'Took ... ' . $bm->timems() . 'ms'; ?> </pre>