Most of you don't know (don't care), but there is something called 'advanced status' (very usefull to detect servers that spoof info about number if players). You can get from port 7171 of any server status in XML format (with number of players online, record, server name etc.), but you can get also list of online players names and their levels. Example how to get it is in this script:
Server generates that information in status.cpp and sends in 'binary' (0010110..) format. You don't have to understand binary format. You can use my class ServerPlayersList to get players names and levels
Example result:
PHP:
<?php
class ServerPlayersList
{
public $players = array();
public $playersCount = 0;
public $playersBinaryData = '';
/*
basic binary decoder from ItemAttributes of gesior acc. maker 2012
START
*/
public function __construct($playersBinaryData)
{
$this->loadPlayers($playersBinaryData);
}
private function getByte()
{
$ret = ord($this->playersBinaryData[0]);
$this->playersBinaryData = substr($this->playersBinaryData, 1);
return $ret;
}
private function getU16()
{
$ret = ord($this->playersBinaryData[0]) + ord($this->playersBinaryData[1]) * 256;
$this->playersBinaryData = substr($this->playersBinaryData, 2);
return $ret;
}
private function getU32()
{
$ret = ord($this->playersBinaryData[0]) + ord($this->playersBinaryData[1]) * 256 + ord($this->playersBinaryData[2]) * 65536 + ord($this->playersBinaryData[3]) * 16777216;
$this->playersBinaryData = substr($this->playersBinaryData, 4);
return $ret;
}
private function getString($length)
{
$ret = substr($this->playersBinaryData, 0, $length);
$this->playersBinaryData = substr($this->playersBinaryData, $length);
return $ret;
}
/*
basic binary decoder from ItemAttributes of gesior acc. maker 2012
END
*/
public function loadPlayers($playersBinaryData)
{
/*
short info:
byte (U8) is 1 byte length number
short (U16) is 2 byte length number
int (U32) is 4 byte length number
string is chain of letters [bytes] (OTS always send U16 before that chain to let us know how many letters we must read)
*/
$this->playersBinaryData = $playersBinaryData;
if(!empty($this->playersBinaryData))
{
$packetLength = $this->getU16(); // useless for us
$firstByte = $this->getByte(); // first byte of players list is 0x21
if($firstByte == 33) // if first byte is 0x21 (2 * 16 + 1 = 33)
{
$this->playersCount = $this->getU32(); // then players count in U32
while(!empty($this->playersBinaryData)) // now read all players
{
$playerName = $this->getString($this->getU16()); // get string, string 'length' is in U16 before chain of letters [tfs format]
$level = $this->getU32(); // get level of player, its in U32
// add player to list
$this->players[] = array('name' => $playerName, 'level' => $level);
}
}
}
}
public function getPlayers()
{
return $this->players;
}
}
// OUR PACKET:
$toSend = chr(6).chr(0).chr(255).chr(1).chr(32).chr(0).chr(0).chr(0);
// 6,0,255 = we want status
// 1 = we want some special 'binary' status, not 'XML' basic info (XML info = 255 [0xFF])
// 32 (0x20) = we want players list
// 0,0,0 = idk why must be x3, not x1 [server reads U32 in place of U16?]
/*
available binary status list (more info in source file 'status.cpp'):
REQUEST_BASIC_SERVER_INFO = 0x01 // 1
REQUEST_SERVER_OWNER_INFO = 0x02 // 2
REQUEST_MISC_SERVER_INFO = 0x04 // 4
REQUEST_PLAYERS_INFO = 0x08 // 8
REQUEST_SERVER_MAP_INFO = 0x10 // 16
REQUEST_EXT_PLAYERS_INFO = 0x20 // 32
REQUEST_PLAYER_STATUS_INFO = 0x40 // 64
REQUEST_SERVER_SOFTWARE_INFO = 0x80 // 128
*/
/*
---------
S T A R T
O F
C O D E
---------
*/
$ip = 'gamescraft.net';
$port = 7171;
$sock = @fsockopen($ip, $port, $errno, $errstr, 1);
if($sock)
{
fwrite($sock, $toSend); // send our 8 bytes that tells server: 'please send me players list'
$answer = '';
while (!feof($sock)) // read text from server as long as there is anything to read
{
$answer .= fgets($sock, 1024);
}
fclose($sock);
// this script demonstrates how to parse REQUEST_EXT_PLAYERS_INFO [list of players online and their levels] ONLY!
$spl = new ServerPlayersList($answer);
foreach($spl->getPlayers() as $player)
{
echo 'Name: ' . htmlspecialchars($player['name']) . ', level: ' . htmlspecialchars($player['level']) . '<br />';
}
}
else
echo 'Server blocked script. Probably you must wait 5 minutes [config.lua: statusTimeout = 5 * 60 * 1000]';
Example result:
Name: Kshadowe, level: 90
Name: Geeme, level: 86
Name: Master Kellir, level: 80
Name: Home Simpson, level: 97
Name: Tomurka, level: 117
Name: Rei Leao, level: 84
Name: Paola Druidinha, level: 112
Name: Zeck Lester, level: 118
Name: Cadeirante Vitor, level: 117
Name: Bitche, level: 134
Name: Leaao Niice, level: 142
Name: Pally Pistao, level: 131
Name: Fryzon, level: 129
Name: Target Down, level: 146
Name: Vinagrete, level: 141
Name: Rapaz, level: 147
Name: Ned Stark, level: 119
Name: Lemysk Suisem, level: 142
Name: Taz Mania, level: 128
Name: Mancha Verde, level: 150
Name: Volna Dream, level: 147
Name: Castiel, level: 149
Name: Sir Druidizinho, level: 128
Name: Paladin Of Holy, level: 138
Name: Devil Oo Barbaro, level: 147
Name: Matheus De Mage, level: 150