<?
// **********************************************************************************************
// Class Quake3
// Author : Henrik Schack Jensen (henrik@schack.dk)
//
// Changelog:
// Version 1.00 03/13/2001 Initial release
// A utilityclass (PHP4 only) to do serverstatus-queries against Quake3Arena servers
//
// Syntax:
//
// Function getServerStatus(serveraddress,serverport,timeout)
// Get player/servervar info from server
//
// All results are returned in membervariables:
//
//
// Demosource is available at http://www.gameserver.dk/
// **********************************************************************************************
//
// Function used to sort players by frags
// Needs to be defined globally in order for usort to call it
//
function fragsort ($a, $b) {
if ($a["frags"] == $b["frags"]) return 0;
if ($a["frags"] > $b["frags"]) {
return -1;
} else {
return 1;
}
}
Class Quake3 {
var $m_playerinfo =""; // Info about players
var $m_servervars =""; // Info about the server
//
// Get exact time, used for timeout counting
//
function timenow() {
return doubleval(ereg_replace('^0\.([0-9]*) ([0-9]*)$','\\2.\\1',microtime()));
}
//
// Function to remove funny characters from playernames
//
function removefunchars($data) {
$result="";
$skipnextchar=false;
for ($i=0;$i<strlen($data);$i++) {
if (!$skipnextchar) {
$currentchar=ord(substr($data,$i,1));
if (($currentchar==27) || ($currentchar==94)) {
$skipnextchar=true;
} else {
if (($currentchar>=32) && ($currentchar<=127)) $result=$result.chr($currentchar);
if (($currentchar>=160) && ($currentchar<=255)) $result=$result.chr($currentchar-128);
}
} else {
$skipnextchar=false;
}
}
return $result;
}
//
// Read raw data from server
//
function getServerData($command,$serveraddress,$portnumber,$waittime) {
$serverdata ="";
$serverdatalen=0;
if ($waittime< 500) $waittime= 500;
if ($waittime>2000) $waittime=2000;
$waittime=doubleval($waittime/1000.0);
if (!$cssocket=fsockopen("udp://".$serveraddress,$portnumber,$errnr)) {
$this->errmsg="No connection";
return "";
}
socket_set_blocking($cssocket,true);
socket_set_timeout($cssocket,0,500000);
fwrite($cssocket,$command,strlen($command));
// Mark
$starttime=$this->timenow();
do {
$serverdata.=fgetc($cssocket);
$serverdatalen++;
$socketstatus=socket_get_status($cssocket);
if ($this->timenow()>($starttime+$waittime)) {
$this->errmsg="Connection timed out";
fclose($cssocket);
return "";
}
} while ($socketstatus["unread_bytes"] );
fclose($cssocket);
return $serverdata;
}
// **********************************************************************
// getServerStatus
// Read rules/setup from the gameserver into m_servervars
// Return true if successful
// **********************************************************************
function getServerStatus($serveraddress,$portnumber,$timeout) {
$cmd="\xFF\xFF\xFF\xFFgetstatus\n";
$serverdata=$this->getServerData($cmd,$serveraddress,$portnumber,$timeout);
if (strlen($serverdata)>20) {
$serverdata=substr($serverdata,20);
} else {
return false;
}
$srvvars=substr($serverdata,0,strpos($serverdata,"\n"))."\\";
$players=substr($serverdata,strpos($serverdata,"\n")+1);
// Skip the last linefeed
$players=substr($players,0,strlen($players)-1);
// Split playerinfo and fill into array
$playercount=0;
if (strlen($players)) {
$playercollection=explode("\n",$players);
while (list($key,$data) = each ($playercollection)) {
eregi("^([-0-9]+) ([-0-9]+) \"(.*)\"",$data,$player);
$this->m_playerinfo[$key]=array("frags"=>$player[1],"ping"=>$player[2],"name"=>$this->removefunchars($player[3]));
$playercount++;
}
}
// Fake servervar containing number of current players
$this->m_servervars["sv_currentclients"]=$playercount;
if ($playercount>0) usort($this->m_playerinfo,"fragsort");
// Split servervars and fill into array
$name_tok = strtok ($srvvars,"\\");
$val_tok = strtok ("\\");
while (strlen($name_tok)) {
$this->m_servervars[$name_tok]=$val_tok;
$name_tok = strtok ("\\");
$val_tok = strtok ("\\");
}
return true;
}
}
?>
|