Scripts

Call of Duty Server Stats versie 2

Ik had een aantal jaren geleden ooit een versie gemaakt (http://www.phphulp.nl/php/scripts/7/146/). Vandaag in een opwelling even een nieuwe, beter gecodeerde (in my opinion) geschreven. Getest op Call of Duty 2 en 4, mogelijk werkt deze (aangepast) ook met andere games zoals MoH etc. Geeft naast alle cvars (instellingen) van de server ook de naam, score en ping van de spelers (gesorteerd) weer. Zie ook http://img248.imageshack.us/img248/6327/version2classim0.gif . Geen werkend voorbeeld omdat de enige PHP-host die ik momenteel heb geen sockets ondersteund. Layout is niet prachtig (heb er overal even simpel php doorheen gevlochten (zoals de "die;")), maar daar ging het mij niet om. Als mensen dit gaan gebruiken is het aan te raden om het even netjes in templates of wat dan ook te zetten, maar dat is persoonlijke voorkeur. Beargumenteerde kritiek welkom. EDIT: Heb 'm in een class gezet, code is aangepast. Bij de bugs nog het probleem dat Rick aangaf. Tijdens het maken had ik deze melding ook nog een keer, echt geen idee waar dat door kan komen.

call-of-duty-server-stats-versie-2
[code]<?php

/**
*
* Serverstatus class
*
* Tested and working in PHP5, PHP6
* Only tested with Call of Duty serie.
* Connects to a server an retrieves the data.
*
* @throws ServerException
*
* Known bugs:
*  - Sometimes (random) the server returns 'disconnect' as data.
*    Then the script just dies for unknown reasons (???)*
*
* Version 2.0
*   Class implementation
*
*   CHANGELOG
*     1.0      - 5 May 2004
*                Made by =(.T.T.B.)= Spikey (http://www.phphulp.nl/php/scripts/7/145/)
*     1.1, 1.2 - 13 May 2004
*                http://www.phphulp.nl/php/scripts/7/146/
*     2.0      - 1 March 2008
*                Class implementation. Totally rewritten 1.2 version.
*                http://www.phphulp.nl/php/scripts/7/1293/
*
*                       Mark van Seventer
*
*/
class ServerException extends Exception { }

class ServerStatus {

	/* Server address */
	private $ip;
	private $port;

	/* Server data */
	private $cvar   = array();
	private $player = array();
	private $score  = array();
	private $ping   = array();

	/**
	* Constructor, saves IP and port
	* Note that the IP does not has to be syntaxed as
	* XXX.XXX.XXX.XXX. A host can also be entered.
	*
	* @param String $ip
	* @param String $port
	* @param boolean $autoConnect
	*/
	public function __construct($ip, $port = '28960', $autoConnect = true) {
		if(!isset($ip)) {
			throw new ServerException('IP cannot be left empty!');
		}
		$this->ip   = $ip;
		$this->port = $port;

		if($autoConnect) {
			$this->connect();
		}
	}

	/**
	* Connects to server
	*/
	public function connect() {
		if(!empty($this->player)) {
			throw new ServerException('No need to connect to the same server twice!');
		}

		$con = fsockopen('udp://' . $this->ip, $this->port);
		if(!$con) {
			throw new ServerException('Failed connecting to the server!');
		}

		fwrite($con, chr(255) . chr(255) . chr(255) . chr(255) . chr(0x02) . 'getstatus' . chr(0x00));
		fread($con, 4);

		$status = socket_get_status($con);
		if($status['unread_bytes'] == 0) {
			throw new ServerException('Failed retrieving data from the server!');
		}

		$data = fread($con, $status['unread_bytes']);
		//do {
		//	$data .= fread($con, 1); 
		//	$status = socket_get_status($con);
		//} 
		//while($status['unread_bytes'] != 0);

		fclose($con);

		$this->_handle($data);
	}

	/**
	* Handles retrieved data
	* @param String $data
	*/
	private function _handle($data) {
		if($data == 'disconnect') {
			throw new ServerException('Unknown error retrieving data!');
		}

		$playerData = explode("\n", $data);

		/* Remove unnecessary items */
		array_shift($playerData);//statusResponse
		array_pop($playerData);//empty

		$cvars = array_shift($playerData);
		$cvars = explode('\\', $cvars);
		array_shift($cvars);//empty

		$this->_parseCvar($cvars);
		$this->_parsePlayer($playerData);
	}

	/**
	* Parses cvars
	* @param Array $cvar
	*/
	private function _parseCvar($cvar) {
		/**
		* We want to achieve an array with:
		* $cvar => $cvar-value
		*/
		$cvarCount = count($cvar);
		for($i = 0; $i < $cvarCount; $i++) {
			$cvarValueIndex = $i + 1;
			$this->cvar[$cvar[$i]] = $this->_colorize($cvar[$cvarValueIndex]);
			$i += 1;//skip cvarvalue
		}
	}

	/**
	* Parses player information
	* @param Array $player
	*/
	private function _parsePlayer($players) {
		$regex = '#([0-9]+) ([0-9]+) "(.*)"#';
		foreach($players as $player) {
			preg_match($regex, $player, $info);
			$this->score[]  = $info[1];
			$this->ping[]   = $info[2];
			$this->player[] = $info[3];
		}

		/* Sort players */
		array_multisort($this->score, SORT_DESC, SORT_NUMERIC,
						$this->ping,  SORT_ASC,  SORT_NUMERIC,
						$this->player);

		/* Colorize after sort to avoid sorting on <span> */
		$this->player = array_map(array($this, '_colorize'), $this->player);
	}

	/**
	* Colorizes according to Call of Duty format
	* @param String $string
	* @return String $string
	*/
	private function _colorize($string) {
		$string = htmlentities($string);

		$colorcodes = array(
			'^1' => '</span><span style="color: red">',
			'^2' => '</span><span style="color: green">',
			'^3' => '</span><span style="color: yellow">',
			'^4' => '</span><span style="color: blue">',
			'^5' => '</span><span style="color: cyan">',
			'^6' => '</span><span style="color: purple">',
			'^7' => '</span><span style="color: #CCC">',//white is unreadable
			'^8' => '</span><span style="color: black">',//team color
			'^9' => '</span><span style="color: gray">',
			'^0' => '</span><span style="color: black">',
		);
		$string = str_replace(array_keys($colorcodes), $colorcodes, $string);

		/* Fix the </span> in the beginning and add one at the end */
		$pos = strpos($string, '</span>');
		if($pos !== false) {
			$length = strlen('</span>');
			$string = substr($string, 0, $pos) . substr($string, $pos + $length);//remove first </span>
			$string .= '</span>';//add trailing </span>
		}
		
		return $string;
	}

	/**
	* Allow access to private variables
	* @param String $var
	* @return String private $var
	*/
	public function __get($var) {
		return isset($this->$var) ? $this->$var : false;
	}

}
?>[/code]
[code]<?php

try {
	$status = new ServerStatus('85.131.237.222', '28960', false);
	$status->connect();//optional

	/**
	* The above is the same as
	* $status = new ServerStatus('85.131.237.222');
	*/

	/* EXAMPLE */
	echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">' . "\n" .
         '<html xmlns="http://www.w3.org/1999/xhtml">' . "\n" .
         '<head>' . "\n" .
         '<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />' . "\n" .
         '<title>Agirre ServerStatus</title>' . "\n" .
         '</head>' . "\n" .
         '<body>' . "\n";

	/* EXAMPLE: printing example header */
	echo '<p style="font-weight: bold">Server status: ' . $status->ip . ':' . $status->port . '</p>' . "\n";

	/* EXAMPLE: printing cvars */
	echo '<table>' . "\n" .
	     '  <tr>' . "\n" .
	     '    <td style="font-style: italic">Cvar</td>' . "\n" .
	     '    <td style="font-style: italic">Value</td>' . "\n" .
	     '  </tr>' . "\n";

	foreach($status->cvar as $cvar => $value) {
		echo '  <tr>' . "\n" .
		     '    <td>' . $cvar . '</td>' . "\n" .
		     '    <td>' . $value . '</td>' . "\n" .
		     '  </tr>' . "\n";
	}
	echo '</table>' . "\n";

	/* EXAMPLE: printing player table */
	echo '<table>' . "\n" .
	     '  <tr>' . "\n" .
	     '    <td style="font-style: italic">Player</td>' . "\n" .
	     '    <td style="font-style: italic">Score</td>' . "\n" .
	     '    <td style="font-style: italic">Ping</td>' . "\n" .
	     '  </tr>' .  "\n";

	$playerCount = count($status->player);
	for($i = 0; $i < $playerCount; $i++) {
		echo '  <tr>' . "\n" .
		     '    <td>' . $status->player[$i] . '</td>' . "\n" .
		     '    <td>' . $status->score[$i] . '</td>' . "\n" .
		     '    <td>' . $status->ping[$i] . '</td>' . "\n" .
		     '  </tr>' .  "\n";
	}
	echo '</table>' . "\n";

	echo '</body>' . "\n" . '</html>';

}
catch(ServerException $e) {
	echo 'Error: ' . $e->getMessage();
}

?>[/code]

Reacties

0
Nog geen reacties.