*/ if(!defined('DOKU_INC')) define('DOKU_INC',realpath(dirname(__FILE__).'/../../').'/'); if(!defined('DOKU_PLUGIN')) define('DOKU_PLUGIN',DOKU_INC.'lib/plugins/'); require_once(DOKU_PLUGIN.'syntax.php'); /** * All DokuWiki plugins to extend the parser/rendering mechanism * need to inherit from this class */ class syntax_plugin_dwqstat extends DokuWiki_Syntax_Plugin { /** * Get an associative array with plugin info. * *

* The returned array holds the following fields: *

*
author
Author of the plugin
*
email
Email address to contact the author
*
date
Last modified date of the plugin in * YYYY-MM-DD format
*
name
Name of the plugin
*
desc
Short description of the plugin (Text only)
*
url
Website with more information on the plugin * (eg. syntax description)
*
* @param none * @return Array Information about this plugin class. * @public * @static */ function getInfo(){ return array( 'author' => 'Mathieu', 'email' => 'mathieu@guim.info', 'date' => rtrim(io_readFile(DOKU_PLUGIN.'dwqstat/VERSION.txt')), 'name' => 'DWQstat Plugin mostly for Openarena. You can use a proxy server if your PHP installation can\'t use \'stream_socket_*\' functions.', 'desc' => 'Provide informations about a Quake3 (or compatible) server', 'url' => 'http://www.guim.info/dokuwiki/dev/qstat', ); } /** * Get the type of syntax this plugin defines. * * @param none * @return String 'substition' (i.e. 'substitution'). * @public * @static */ function getType(){ return 'substition'; } /** * Where to sort in? * * @param none * @return Integer 6. * @public * @static */ function getSort() { return 100; } /** * Connect lookup pattern to lexer. * * @param $aMode String The desired rendermode. * @return none * @public * @see render() */ function connectTo($mode) { $this->Lexer->addSpecialPattern('{{qstat}}', $mode, 'plugin_dwqstat'); $this->Lexer->addSpecialPattern('{{qstat.+?}}', $mode, 'plugin_dwqstat'); } /** * Handler to prepare matched data for the rendering process. * *

* The $aState parameter gives the type of pattern * which triggered the call to this method: *

*
*
DOKU_LEXER_ENTER
*
a pattern set by addEntryPattern()
*
DOKU_LEXER_MATCHED
*
a pattern set by addPattern()
*
DOKU_LEXER_EXIT
*
a pattern set by addExitPattern()
*
DOKU_LEXER_SPECIAL
*
a pattern set by addSpecialPattern()
*
DOKU_LEXER_UNMATCHED
*
ordinary text encountered within the plugin's syntax mode * which doesn't match any pattern.
*
* @param $aMatch String The text matched by the patterns. * @param $aState Integer The lexer state for the match. * @param $aPos Integer The character position of the matched text. * @param $aHandler Object Reference to the Doku_Handler object. * @return Integer The current lexer state for the match. * @public * @see render() * @static */ function handle($match, $state, $pos, &$handler){ $match = substr($match,7,-2); $match = explode(" ", trim($match)); if (count($match) != 2) { return array(); } $status = $this->_getStatus($match[0], $match[1]); return ($status === FALSE) ? array() : $status; } /** * Handle the actual output creation. * *

* The method checks for the given $aFormat and returns * FALSE when a format isn't supported. $aRenderer * contains a reference to the renderer object which is currently * handling the rendering. The contents of $aData is the * return value of the handle() method. *

* @param $aFormat String The output format to generate. * @param $aRenderer Object A reference to the renderer object. * @param $aData Array The data created by the handle() * method. * @return Boolean TRUE if rendered successfully, or * FALSE otherwise. * @public * @see handle() */ function render($mode, &$renderer, $data) { $this->setupLocale(); $renderer->info['cache'] = false; if($mode == 'xhtml') { if (empty($data)) { //$renderer->doc .= "No informations available."; $renderer->doc .= $this->getLang('no_info'); } else { $infotodisplay = array('mapname'); if (array_key_exists('defrag_vers', $data)) { //defrag server array_push($infotodisplay, 'df_promode'); } else { // baseoa server if (array_key_exists('g_gametype', $data)) { switch($data['g_gametype']) { case 0: case 3: // ffa, tdm array_push($infotodisplay, 'g_gametype', 'fraglimit', 'timelimit'); break; case 4: // ctf array_push($infotodisplay, 'g_gametype', 'capturelimit', 'timelimit'); break; } } } $buf = '
'; // hostname $buf .= "

".$this->_colorize($data['sv_hostname'], 'server')."

"; // informations /* $buf .= "

". 'Serveur '.(($data['g_needpass'] == 0) ? 'public' : 'privé').''. ''.$this->_renderInformation('protocol', $data['protocol'])."

"; */ $buf .= '

'. (($data['g_needpass'] == 0) ? $this->getLang('public_server') : $this->getLang('private_server')). '

'; $buf .= '
_renderInformation($key, $data[$key]); } // flagbar $buf .= "
"; $buf .= $this->_flagbar($data); // players $maxclient = $data['sv_maxclients'] - $data['sv_privateClients']; $buf .= "

{$this->getLang('players')} ".count($data['players'])."/{$maxclient}

"; $buf .= '
"; $buf .= '
'; $renderer->doc .= $buf; } return true; } return false; } // display formatted information function _renderInformation($key, $value) { $str = ''; switch ($key) { case 'mapname': $str = '

'.$this->getLang('map').': '.$value.'

'; break; case 'capturelimit': $str = '

'.$this->getLang('flags').": $value

"; break; case 'fraglimit': $str = '

'.$this->getLang('frags').": $value

"; break; case 'timelimit': $str = '

'.$this->getLang('time').": $value

"; break; case 'protocol': if ($value == '68') $str = '0.7.1'; elseif ($value == '69') $str = '0.7.6'; elseif ($value == '70') $str = '0.7.7'; elseif ($value == '71') $str = '0.8.1'; break; case 'df_promode': $str = '

'.$this->getLang('physic').': '.(($value == '0') ? 'VQ3' : 'CPM').'

'; break; case 'g_gametype': $str .= '

'; if ($value == 0) $str = 'Type : FFA'; elseif ($value == 3) $str = 'Type : TDM'; elseif ($value == 4) $str = 'Type : CTF'; $str .= '

'; break; default: $str = "

$key: $value

"; break; } return $str; } // show flag option (on/off) for the server function _flagbar($data) { $flag = array( 'g_delagHitscan' => array('desc' => 'unlagged', 'img' => 'lag.png'), 'g_delaghitscan' => array('desc' => 'unlagged', 'img' => 'lag.png'), 'g_instantgib' => array('desc' => 'instantgib', 'img' => 'ammo_rg.png'), 'g_rockets' => array('desc' => 'all rocket', 'img' => 'ammo_rl.png'), ); $mod = array( 'baseoa' => array('desc' => 'OpenArena', img => 'baseoa.png'), 'unfrag-ifs' => array('desc' => 'unfrag-ifs', img => 'unfrag-ifs.png'), 'z3r0x' => array('desc' => 'z3r0x', img => 'z3r0x.png'), ); $imgpath = DOKU_BASE.'/lib/plugins/qstat_oatforg/images/'; $str = '
'; // mod iteration foreach ($mod as $key => $value) { $keytotest = ((isset($data['game'])) ? 'game' : 'gamename'); if ($data[$keytotest] == $key) { $str .= ''; } } // flag iteration foreach ($flag as $key => $value) { if ($data[$key] == 1) { $str .= ''; } } $str .= '
'; return $str; } // retrieve status using the appropriate method function _getStatus($host, $port) { if ($this->getConf('use_proxy')) return $this->_proxy($host, $port); else return array_merge($this->_infos($host, $port), $this->_status($host, $port)); } // use the proxy to retrieve information function _proxy($host, $port) { $proxy = $this->getConf('proxy_url'); $str = file_get_contents("$proxy?host=$host&port=$port"); $serverstatus = unserialize($str); if (is_string($serverstatus) and $serverstatus == "Bad host or port") { $serverstatus = FALSE; } return $serverstatus; } // ask server for "getinfo" function _infos($host, $port) { $serverinfos = array(); $packet = "\xFF\xFF\xFF\xFFgetinfo\x00"; $sock = @stream_socket_client("udp://$host:$port"); if ($sock === FALSE) return FALSE; @stream_set_timeout($sock, 3); $r = @fwrite($sock, $packet, strlen($packet)); if ($r === FALSE) return FALSE; $r = @fread($sock, 1500); if ($r === FALSE) return FALSE; // "\0xFF\0xFF\0xFF\0xFFinfoResponse " => 17 $str = trim(substr($r, 17)); $split = preg_split("/\\\/", $str); $key = null; foreach ($split as $item) { if ($key == null) { $key = $item; } else { $serverinfos[$key] = $item; $key = null; } } return $serverinfos; } // ask server for "getstatus" function _status($host, $port) { $serverstatus = array(); $packet = "\xFF\xFF\xFF\xFFgetstatus\x00"; $sock = @stream_socket_client("udp://$host:$port"); if ($sock === FALSE) return FALSE; @stream_set_timeout($sock, 3); $r = @fwrite($sock, $packet, strlen($packet)); if ($r === FALSE) return FALSE; $r = @fread($sock, 1500); if ($r === FALSE) return FALSE; // "\0xFF\0xFF\0xFF\0xFFstatusResponse " => 19 $str = trim(substr($r, 19)); $split = preg_split("/\n/", $str); $status = array_shift($split); // player parsing $players = array(); foreach ($split as $p) { $s = preg_split("/\s/", $p); $tmp_name = ''; for ($i=2; $i $tmp_name, 'ping' => $s[1], 'score' => $s[0])); } $serverstatus['players'] = $players; // status parsing $split = preg_split("/\\\/", $status); $key = null; foreach ($split as $item) { if ($key == null) { $key = $item; } else { $serverstatus[$key] = $item; $key = null; } } return $serverstatus; } // colorize a player name with Quake style function _colorize($str,$type='player') { $COLOR = array( 0 => 'black', 1 => 'red', 2 => 'green', 3 => 'yellow', 4 => 'blue', 5 => 'cyan', 6 => 'magenta', 7 => 'white'); $len = strlen($str); $tmp = ''; $span = false; for ($i=0; $i<$len; $i++) { if ($str[$i] == '^' && $str[$i+1] == '^') { if ($type == 'server') { if ($i+2 < $len && is_numeric($str[$i+2])) { if ($span) $tmp .= ''; $tmp .= ''; $span = true; $i+=3; } } else { $tmp .= $str[$i]; } } else if ($str[$i] == '^' && $i+1 < $len && is_numeric($str[$i+1])) { if ($span) $tmp .= ''; $tmp .= ''; $span = true; $i++; } else if ($str[$i] == '^' && $i+1 < $len && is_string($str[$i+1])) { if ($span) $tmp .= ''; $ascii = ord($str[$i+1]); #$color = (($ascii > 96) ? $ascii - 22 : $ascii) - 65; $color = (($ascii > 96) ? $ascii - 22 : $ascii) - 66; $tmp .= ''; $span = true; $i++; } else { $tmp .= $str[$i]; } } if ($span) $tmp .= ''; return $tmp; } } ?>