Re: gameserver


Code PHP :
Pour copier le contenu exact du code,
Veuillez citer le message
  1. <?php
  2.  
  3. /*
  4.  *  gsQuery - Querys GameServer protocol compatible Gameservers (and more)
  5.  *  Copyright (c) 2003 Jeremias Reith <email anti-spam>
  6.  *  http://gsquery.terragate.net
  7.  *
  8.  *  This file is part of the gsQuery library.
  9.  *
  10.  *  The gsQuery library is free software; you can redistribute it and/or
  11.  *  modify it under the terms of the GNU Lesser General Public
  12.  *  License as published by the Free Software Foundation; either
  13.  *  version 2.1 of the License, or (at your option) any later version.
  14.  *
  15.  *  The gsQuery library is distributed in the hope that it will be useful,
  16.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18.  *  Lesser General Public License for more details.
  19.  *
  20.  *  You should have received a copy of the GNU Lesser General Public
  21.  *  License along with the gsQuery library; if not, write to the
  22.  *  Free Software Foundation, Inc.,
  23.  *  59 Temple Place, Suite 330, Boston,
  24.  *  MA  02111-1307  USA
  25.  *
  26.  */
  27.  
  28. global $GSQUERYDEFINED;
  29.  
  30. // to be sure that it is only included once (does this really help?)
  31. if(!$GSQUERYDEFINED) {
  32.   $GSQUERYDEFINED=TRUE;
  33.  
  34.   class gsQuery
  35.   {
  36.     // version
  37.     var $version;
  38.     
  39.     // this must be known
  40.     var $address;
  41.     var $queryport;
  42.     
  43.     // status info
  44.     var $gamename;
  45.     var $hostport;
  46.     var $gameversion;
  47.     var $servertitle;
  48.     var $hostport;
  49.     var $mapname;
  50.     var $maptitle;
  51.     var $gametype;
  52.     var $numplayers;
  53.     var $maxplayers;
  54.     var $password;
  55.     var $nextmap;
  56.     
  57.     // players
  58.     var $players;
  59.     
  60.     // list of available playerinfos
  61.     // name=1, score=1, ping=1 in most cases
  62.     var $playerkeys;
  63.  
  64.     // contains the names of the teams (if available)
  65.     var $playerteams;
  66.  
  67.     // serverrules
  68.     var $rules;
  69.     
  70.     // Holds an errormessage if something goes wrong (not implemented yet)
  71.     var $errstr;
  72.     
  73.     // Holds debug infos 
  74.     var $debug;
  75.     
  76.     // constructor
  77.     function gsQuery($address, $queryport)
  78.     {
  79.       $this->version = "0.0.5";
  80.       
  81.       $this->address = $address;
  82.       $this->queryport = $queryport;
  83.       
  84.       $this->gamename = "";
  85.       $this->hostport = 0;
  86.       $this->gameversion = "";
  87.       $this->servertitle = "";
  88.       $this->hostport = "";
  89.       $this->mapname = "";
  90.       $this->maptitle = "";
  91.       $this->gametype = "";
  92.       $this->numplayers = 0;
  93.       $this->maxplayers = 0;
  94.       $this->password = -1; // -1 stands for unknown
  95.                             //  0 for no password
  96.                             //  1 for password
  97.       $this->nextmap="";
  98.  
  99.       $this->players = array();
  100.       $this->playerkeys = array();
  101.       $this->playerteams = array();
  102.       $this->rules = array();
  103.       $this->debug = array();
  104.       
  105.       $this->errstr="";
  106.     }
  107.   
  108.   
  109.     // use this function to query the server
  110.     // returns FALSE on failure
  111.     function query_server($protocol="gsqp",$getPlayers=TRUE,$getRules=TRUE)
  112.     { 
  113.       
  114.       $this->playerkeys=array();
  115.       $this->debug=array();
  116.       $this->password=-1;
  117.       
  118.       switch($protocol) {
  119.     
  120.       case "gsqp":
  121.     return $this->_query_gsqp_server($getPlayers,$getRules);
  122.       case "hlife":
  123.     return $this->_query_hlife_server($getPlayers,$getRules);
  124.       case "q3a":
  125.     return $this->_query_q3a_server($getPlayers);
  126.       default:
  127.     return FALSE;
  128.       }
  129.     }
  130.     
  131.     // sorts the players
  132.     function sortPlayers($players, $sortkey="name") 
  133.     {
  134.       switch($sortkey) {
  135.       default:
  136.       case "name":
  137.     uasort($players, array("gsQuery", "_sortbyName"));
  138.     break;
  139.       case "score":
  140.     uasort($players, array("gsQuery", "_sortbyScore"));
  141.     break;
  142.       case "frags":
  143.     uasort($players, array("gsQuery", "_sortbyFrags"));
  144.     break;
  145.       case "deaths":
  146.     uasort($players, array("gsQuery", "_sortbyDeaths"));
  147.     break;
  148.       case "honor":
  149.     uasort($players, array("gsQuery", "_sortbyHonor"));
  150.     break;
  151.       case "time":
  152.     uasort($players, array("gsQuery", "_sortbyTime"));
  153.     break;    
  154.       }
  155.       return ($players);
  156.     }
  157.  
  158.     // private member functions
  159.     
  160.     // this works for most games 
  161.     function _query_gsqp_server($getPlayers=TRUE,$getRules=TRUE)
  162.     {
  163.       $command="basicinfo";
  164.       if(!($result=$this->_sendCommand($this->address,$this->queryport,$command, "final"))) {
  165.     // trying it more generic (America's Army)
  166.     if(!($result=$this->_sendCommand($this->address,$this->queryport,"status"))) {
  167.       return FALSE;
  168.     }
  169.       }
  170.       
  171.       $temp=explode("",$result);
  172.       for($i=1;$i <count($temp);$i++) {
  173.     $rawdata[$temp[$i]]=$temp[++$i];
  174.       }
  175.       
  176.       // Whatever we got it is not useful for us
  177.       if(!$rawdata["gamename"]) {
  178.     return FALSE;
  179.       }
  180.  
  181.       $this->gamename = $rawdata["gamename"];
  182.       $this->hostport = $rawdata["hostport"];
  183.       $this->gameversion = $rawdata["gamever"];
  184.       $this->servertitle = $rawdata["hostname"];
  185.       $this->maptitle = $rawdata["maptitle"];
  186.       $this->mapname = $rawdata["mapname"];
  187.       $this->gametype = $rawdata["gametype"];
  188.       $this->numplayers = $rawdata["numplayers"];
  189.       $this->maxplayers = $rawdata["maxplayers"];
  190.       
  191.       if($rawdata["password"]==0 || $rawdata["password"]==1) {
  192.     $this->password=$rawdata["password"];
  193.       }
  194.       
  195.       // get players
  196.       
  197.       if($this->numplayers && $getPlayers) {
  198.     $cmd="players";
  199.     if(!($response=$this->_sendCommand($this->address,$this->queryport,$cmd))) {
  200.       return FALSE;
  201.     }
  202.     
  203.     $temp=explode("", $this->_sortByQueryId($response));
  204.     $this->playerkeys["name"]=TRUE;
  205.     for($i=1;$i<count($temp);$i++) {
  206.       list($var, $playerid)=explode("_", $temp[$i]);
  207.       switch($var) {
  208.       case "player":
  209.         $players[$playerid]["name"]=$temp[++$i];        
  210.         break;
  211.       case "teamname":
  212.         $this->playerteams[$playerid]=$temp[++$i];        
  213.         break;
  214.       default:
  215.         $players[$playerid][$var]=$temp[++$i];
  216.         $this->playerkeys[$var]=TRUE;
  217.       }
  218.     }
  219.     $this->players=$players;
  220.       }
  221.       
  222.  
  223.       // get rules
  224.       if($getRules) {
  225.     $cmd="rules";
  226.     if(!($response=$this->_sendCommand($this->address,$this->queryport,$cmd))) {
  227.       return FALSE;
  228.     }
  229.     
  230.     $temp=explode("",$response);
  231.     for($i=1;$i<count($temp);$i++) { 
  232.       if($temp[$i]!="queryid" && $temp[$i]!="final" && $temp[$i]!="password") {
  233.         $this->rules[$temp[$i]]=$temp[++$i]; 
  234.       } else {
  235.         if($temp[$i++]=="password") {
  236.           $this->password=$temp[$i];      
  237.         }
  238.       }
  239.     } 
  240.       }
  241.       return TRUE;
  242.     }
  243.       
  244.     // sorts gsqp data
  245.     // sometimes a packet get lost but we do not have the time to rerequest it
  246.     function _sortByQueryId($data)
  247.     {
  248.       $data=preg_replace("/final/", "", $data);
  249.       $exploded_data=explode("queryid", $data);
  250.       for($i=0;$i<count($exploded_data)-1;$i++) { 
  251.     preg_match("/^d+.(d+)/", $exploded_data[$i+1], $id);
  252.     $sorted_data[$id[1]]=$exploded_data[$i];
  253.     $exploded_data[$i+1]=substr($exploded_data[$i+1],strlen($id[0]-1),strlen($exploded_data[$i+1]));
  254.       }
  255.       ksort($sorted_data);
  256.       foreach($sorted_data as $key => $value) {
  257.     $result.=$value;
  258.       }
  259.       return($result);
  260.     }  
  261.       
  262.     // code is very ugly (does anyone have the protocol specs?)
  263.     // There are a lot of bugs in it
  264.     function _query_hlife_server($getPlayers=TRUE,$getRules=TRUE) 
  265.     {
  266.       $command="xFFxFFxFFxFFx54x53x6Fx75x72x63x65x20x45x6Ex67x69x6Ex65x20x51x75x65x72x79x00";
  267.       if(!($result=$this->_sendCommand($this->address,$this->queryport,$command))) {
  268.     return FALSE;
  269.       }
  270.       
  271.       $exploded_data = explode("x00", $result);
  272.       list($ip, $this->hostport) = explode(":", $exploded_data[0]);
  273.       $this->gamename = "hlife_" . $exploded_data[3];
  274.       $this->gametype = $exploded_data[3];
  275.       $this->servertitle = $exploded_data[1];
  276.       $this->mapname = $exploded_data[2];
  277.       $this->numplayers = ord(substr($exploded_data[5], 0, 1));
  278.       if($this->numplayers) {
  279.     $this->maxplayers = ord(substr($exploded_data[5], 1, 1));
  280.       }
  281.       else {
  282.     $this->maxplayers = ord(substr($exploded_data[6], 0, 1));
  283.       }
  284.       $this->gameversion = "";
  285.       $this->maptitle = "";
  286.       
  287.       // get players
  288.       if($this->numplayers && $getPlayers) {
  289.     $command="xFFxFFxFFxFFx57";
  290.     if(!($result=$this->_sendCommand($this->address,$this->queryport,$command))) {
  291.       return FALSE;
  292.     }
  293.     
  294.     $exploded_data = explode("x00", substr($result, 4, strlen($result)));
  295.     $players[0]["name"]=substr($exploded_data[0], 3, strlen($exploded_data[0]));
  296.     $players[0]["score"]=hexdec(bin2hex(substr($exploded_data[1],0,1))); 
  297.     // correction to signed short (is there a better way in PHP to do that?)
  298.     if($players[0]["score"]>128) {
  299.       $players[0]["score"]-=256;
  300.     }
  301.     
  302.     for($i=1;$i<count($exploded_data);$i++) {
  303.       if(strlen($exploded_data[$i])>4) {
  304.         $players[$i]["name"]=substr($exploded_data[$i], 5, strlen($exploded_data[$i]));
  305.         $players[$i]["score"]=hexdec(bin2hex(substr($exploded_data[$i+1],0,1)));
  306.       }
  307.     }
  308.     $this->playerkeys["name"]=TRUE;
  309.     $this->playerkeys["score"]=TRUE;
  310.     $this->players=$players;
  311.       }
  312.       
  313.       // get rules
  314.       $command="xFFxFFxFFxFFx57";
  315.       if(!($result=$this->_sendCommand($this->address,$this->queryport,$command))) {
  316.     return FALSE;
  317.       }
  318.       
  319.       $exploded_data = explode("x00", $result);
  320.       $this->password = -1;
  321.       
  322.       for($i=1;$i<count($exploded_data);$i++) { 
  323.     if($exploded_data[$i]!="sv_password" && $exploded_data[$i]!="") {
  324.       $this->rules[$exploded_data[$i]]=$exploded_data[++$i]; 
  325.     } else {
  326.       if($exploded_data[$i++]=="sv_password") {
  327.         $this->password=$exploded_data[$i];      
  328.       }
  329.     }
  330.       } 
  331.       return TRUE;
  332.     }
  333.     
  334.     function _query_q3a_server($getPlayers=TRUE)
  335.     {
  336.       $command="xFFxFFxFFxFFx02getstatusx0ax00";
  337.       if(!($result=$this->_sendCommand($this->address,$this->queryport,$command))) {
  338.     return FALSE;
  339.       }
  340.       
  341.       $temp=explode("x0a",$result);
  342.       $rawdata=explode("",substr($temp[1],1,strlen($temp[1])));
  343.  
  344.       // get rules and basic infos
  345.       for($i=0;$i< count($rawdata);$i++) {
  346.     switch ($rawdata[$i++]) {
  347.     case "g_gametypestring":
  348.       $this->gametype=$rawdata[$i];
  349.       break;
  350.     case "gamename":
  351.       $this->gametype=$rawdata[$i];
  352.       $this->gamename="q3a_" . $rawdata[$i];
  353.       break;
  354.     case "version":
  355.       $this->gameversion=$rawdata[$i];
  356.       break;
  357.     case "sv_hostname":
  358.       $this->servertitle=$rawdata[$i];
  359.       break;
  360.     case "mapname":
  361.       $this->mapname=$rawdata[$i];
  362.       break;
  363.     case "g_needpass":
  364.       $this->password=$rawdata[$i];
  365.       break;
  366.     case "sv_maplist":
  367.       $maps=explode($rawdata[$i], " ");
  368.       break;
  369.     default:
  370.       $this->rules[$rawdata[$i-1]] = $rawdata[$i];
  371.     }
  372.       }
  373.  
  374.       // for MoHAA
  375.       if(!$this->gamename && eregi("Medal of Honor", $this->gameversion)) {
  376.     $this->gamename="mohaa";
  377.       }
  378.  
  379.       if($maps) {
  380.     $i=0;
  381.     while($this->mapname!=$maps[$i++] && $i<count($maps));      
  382.     if($i==count($maps)-1) {
  383.       $this->nextmap=$maps[0];
  384.     }
  385.     else {
  386.       $this->nextmap=$maps[$i];
  387.     }
  388.       }
  389.  
  390.       //for MoHAA
  391.       $this->mapname=preg_replace("/.*//", "", $this->mapname);
  392.  
  393.       $this->hostport = $this->queryport;
  394.       $this->maxplayers = $this->rules["sv_maxclients"]-$this->rules["sv_privateClients"];
  395.  
  396.       //get playerdata and strip colortags away
  397.       $temp=substr($result,strlen($temp[0])+strlen($temp[1])+1,strlen($result));
  398.       $temp=preg_replace("/^[^"]/","",$temp);
  399.       $allplayers=explode("n", $temp);
  400.       $this->numplayers=count($allplayers)-2;
  401.  
  402.       // get players
  403.       if(count($allplayers)-2 && $getPlayers) {
  404.     for($i=1;$i< count($allplayers)-1;$i++) {
  405.       if(preg_match("/(d+)[^0-9](d+)[^0-9]"(.*)"/", $allplayers[$i], $curplayer)) {
  406.         $players[$i-1]["name"]=$curplayer[3];
  407.         $players[$i-1]["score"]=$curplayer[1];
  408.         $players[$i-1]["ping"]=$curplayer[2];        
  409.       }
  410.       else {
  411.         if(preg_match("/(d+)."(.*)"/", $allplayers[$i], $curplayer)) {
  412.           $players[$i-1]["name"]=$curplayer[2];
  413.           $players[$i-1]["ping"]=$curplayer[1];
  414.           $pingOnly=TRUE; // for MoHAA
  415.         }
  416.         else {
  417.           $this->errstr="Could not extract player infos!";
  418.           echo "Unmatched Player: " . $allplayers[$i] . "<br>";
  419.           return FALSE;
  420.         }
  421.       }
  422.     }
  423.     if(!$pingOnly) {
  424.       $this->playerkeys["name"]=TRUE;
  425.       $this->playerkeys["score"]=TRUE;
  426.       $this->playerkeys["ping"]=TRUE;
  427.     }
  428.     else {
  429.       $this->playerkeys["name"]=TRUE;
  430.       $this->playerkeys["ping"]=TRUE;
  431.     }
  432.     $this->players=$players;
  433.       }
  434.     
  435.       return TRUE;
  436.     }
  437.  
  438.  
  439.     // better idea?
  440.     function _sortbyName($a, $b) 
  441.     {
  442.       return(strcasecmp($a["name"], $b["name"]));
  443.     }  
  444.  
  445.     function _sortbyScore($a, $b) 
  446.     {
  447.       if($a["score"]==$b["score"]) { return 0; } 
  448.       elseif($a["score"]<$b["score"]) { return 1; }
  449.       else { return -1; }
  450.     }  
  451.  
  452.     function _sortbyFrags($a, $b) 
  453.     {
  454.       if($a["frags"]==$b["frags"]) { return 0; } 
  455.       elseif($a["frags"]<$b["frags"]) { return 1; }
  456.       else { return -1; }
  457.     }  
  458.  
  459.     function _sortbyDeaths($a, $b) 
  460.     {
  461.       if($a["deaths"]==$b["deaths"]) { return 0; } 
  462.       elseif($a["deaths"]<$b["deaths"]) { return 1; }
  463.       else { return -1; }
  464.     }  
  465.  
  466.     function _sortbyHonor($a, $b) 
  467.     {
  468.       if($a["honor"]==$b["honor"]) { return 0; } 
  469.       elseif($a["honor"]<$b["honor"]) { return 1; }
  470.       else { return -1; }
  471.     }  
  472.  
  473.     function _sortbyTime($a, $b) 
  474.     {
  475.       if($a["time"]==$b["time"]) { return 0; } 
  476.       elseif($a["time"]<$b["time"]) { return 1; }
  477.       else { return -1; }
  478.     }  
  479.     
  480.     // this function is far away from being finished
  481.     // TODO: Make sure that packets are recieved in the correct order 
  482.     function _sendCommand($address,$port,$command)
  483.     {
  484.       if (!$socket=@fsockopen("udp://".$address,$port)) {
  485.     $this->debug[$command]="Couldn't reach server";
  486.     return FALSE;
  487.       } else {
  488.     socket_set_blocking($socket,true);
  489.     //waiting half a second max
  490.     socket_set_timeout($socket,0,500000);
  491.     
  492.     // send command
  493.     if(fwrite($socket,$command,strlen($command))==-1) {
  494.       fclose($socket);
  495.       $this->debug[$command]="Unable to write on open socket!";
  496.       return FALSE;
  497.     }
  498.  
  499.     $result="";
  500.     do {
  501.       $result .= fread($socket,128);
  502.       $socketstatus = socket_get_status($socket);
  503.     } while ($socketstatus["unread_bytes"]);
  504.   
  505.     fclose($socket);
  506.     if(empty($result)) {
  507.       $this->debug[$command]="Empty reply recieved!";
  508.       return FALSE;
  509.     }
  510.     $this->debug[$command]=$result;
  511.     return $result;
  512.       }
  513.     }
  514.   }
  515. }
  516. ?>
  517.  


Sujet écrit par Ancien membre le dimanche 27 janvier 2008 à 13:48

[ Imprimer ] - [ Fermer la fenêtre ]