<?
//    **********************************************************************************************
//    Class Unreal
//    Author : Henrik Schack Jensen (henrik@schack.dk)
// 
//    Changelog:
//     Version 1.00        03/16/2001 Initial release
//    A utilityclass (PHP4 only) to do serverstatus-queries against UnrealTournament 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 
Unreal {
    var 
$m_playerinfo        ="";        // Info about players
    
var $m_servervars        ="";        // Info about the server 
    
var $errmsg                    ="";

    
//
    // Get exact time, used for timeout counting
    //
    
function timenow() {
        return 
doubleval(ereg_replace('^0\.([0-9]*) ([0-9]*)$','\\2.\\1',microtime()));
    }    

    
//
    // Read raw data from server
    //
    
function getServerData($command,$serveraddress,$portnumber,$waittime) {
        
$serverdata        ="";
        
$serverdatalen=0;
        
        if (
$waittime500$waittime500;
        if (
$waittime>2000$waittime=2000;
        
$waittime=doubleval($waittime/1000.0);

        if (!
$cssocket=fsockopen("udp://".$serveraddress,$portnumber+1,$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 (
substr($serverdata,strlen($serverdata)-7)!="\\final\\");
        
fclose($cssocket);
        return 
$serverdata;        
    }    


    
// **********************************************************************
    // getServerStatus
    // Read rules/setup from the gameserver into m_servervars
    // Return true if successful
    // **********************************************************************    
    
function getServerStatus($serveraddress,$portnumber,$timeout) {
        
        
$cmd="\\status\\";        
        
$serverdata=$this->getServerData($cmd,$serveraddress,$portnumber,$timeout);

        
// Is data complete ?
        // This strange doublecheck is needed since UT serverdata sometimes arrives out of order
        
if ((substr($serverdata,strlen($serverdata)-7)!="\\final\\") || (substr($serverdata,1,8)!="gamename")) {
            
$this->errmsg="Data incomplete";
            return 
false;
        }
        
        
// Remove \\final\\ text at end of data
        
$serverdata=substr($serverdata,1,strlen($serverdata)-7);

        
// Split data and fill into array
        
$name_tok strtok ($serverdata,"\\");
        
$val_tok  strtok ("\\");
        while (
strlen($name_tok)) {
            if (
$name_tok!="queryid") {
                
$vars[$name_tok]=$val_tok;
            }    
            
$name_tok strtok ("\\");
            
$val_tok  strtok ("\\");
        }

        while (list(
$key,$data) = each ($vars)) {
            if (!
strncmp($key,"player_",7)) {
                
$player[substr($key,7)]["name"]=$data;
            } elseif (!
strncmp($key,"ping_",5)) {         
                
$player[substr($key,5)]["ping"]=$data;
            } elseif (!
strncmp($key,"frags_",6)) {
                
$player[substr($key,6)]["frags"]=$data;     
            } elseif (!
strncmp($key,"team_",5)) {
                
$player[substr($key,5)]["team"]=$data;                             
            } elseif (!
strncmp($key,"skin_",5)) {
                
$player[substr($key,5)]["skin"]=$data;                             
            } elseif (!
strncmp($key,"mesh_",5)) {
                
$player[substr($key,5)]["mesh"]=$data;                             
            } elseif (!
strncmp($key,"face_",5)) {
                
$player[substr($key,5)]["face"]=$data;                             
            } elseif (!
strncmp($key,"ngsecret_",9)) {
                
$player[substr($key,9)]["ngsecret"]=$data;                             
            } else {
                
$this->m_servervars[$key]=$data;
            }
        }

        
// Move playerinfo to membervariable
        
for ($i=0;$i<$this->m_servervars["numplayers"];$i++) {
            
$this->m_playerinfo[$i]=array("name"=>$player[$i]["name"],"ping"=>$player[$i]["ping"],"frags"=>$player[$i]["frags"]);
        }        

        
// If there are players on the server we sort them by frags        
        
if ($this->m_servervars["numplayers"]>0usort($this->m_playerinfo,"fragsort");
        
        
// Make maptitle lowercase 
        
$this->m_servervars["mapname"]=strtolower($this->m_servervars["mapname"]);

        return 
true;
    }    
}
?>