Gameserver - Query - "4 byte challenge number"

SwissError

Grünschnabel
Guten Morgen!

Ich bin auf dem weg ein Serverqueryscript für HL2 Basierte games zu schreiben (HL1 hatte isch schon, war nicht schwer).

Bevor ich das höre wie: Das wurde schon xxx mal gepostet. Jein! Über das Thema schon, hab ich auch alles schön gelesen, aber nie wurde das wort challenge nr. in die Tastatur getippt.

Nun bei HL2 bin ich soweit dass ich einfache Informationen auslesen kann. Jedoch hänge ich bei den Rules und den Playerlisten. Und das nicht wegen des auswerten der daten, sondern eher am senden der "<4 byte challenge number>" (wie es im sdk beschrieben ist).

Die Challengenummer zo holen (auch per empfangen vom server). hab ich auch geschaft (ist sogar 4 byte :))

Nun aber wenn ich diese direkt an den nächsten string hänge gibt es probleme...

Hier der Code um die Challange nr. zu empfangen und der code den ich versuche um die challange nr. mit zu schicken.

Code:
// String welche man dem Server schickt
	$so_qry = "\xFF\xFF\xFF\xFF\x57";
	
	// Senden des Strings
	if(!fwrite($fp, $so_qry)) {
		echo "<br><br>ERROR: Could NOT write data to server!<br><br>";
	}
	
	// Daten abholen und speichern
	unset($data);
	while ($buffer = fgets($fp,4096)) {
		$data.= $buffer;
	}
	
	$i = 5;
	$server['challenge']['type'] = ord($data{$i++});
	$server['challenge']['number'] = ord($data{$i++}).ord($data{$i++}).ord($data{$i++}).ord($data{$i++});
	
	/*
	for($p=0;$p<8;$p=$p+2) {
		$chalnr .= dechex(substr($server['challenge']['number'],$p,2));
	}
	*/
	$chalnr = $server['challenge']['number'];
	
	echo "test: ".$chalnr."<br>";
	
	// String welche man dem Server schickt
	$so_qry = "\xFF\xFF\xFF\xFF\x55".$chalnr;
	echo $so_qry;
	
	// Senden des Strings
	if(!fwrite($fp, $so_qry)) {
		echo "<br><br>ERROR: Could NOT write data to server!<br><br>";
	}
	
	// Daten abholen und speichern
	unset($data);
	while ($buffer = fgets($fp,4096)) {
		$data.= $buffer;
	}
	
	$i = 5;
	$server['playerlist']['count'] = ord($data{$i++});

Hier findet man noch die offizielle erklärung wie man das macht seitens Valve:

http://www.valve-erc.com/srcsdk/Code/Networking/serverqueries.html
 
Zuletzt bearbeitet:
Das Problem liegt meiner Meinung nach darin, dass dein Script bei der while-Schleife hängen bleibt. Abbruchbedingung für diese Schleife wäre nämlich, dass [phpf]fgets[/phpf] false zurück gibt. Da es sich hier aber um eine UDP-Verbindung handelt, wird dies nicht auftreten.

Weil ich grad etwas Ablenkung gebraucht hab, hab ich dir mal ein (hoffentlich) funktionierendes Script zusammengefrickelt. Viel Spaß damit :)

PHP:
<?php
/*
* Beispielcode zur Abfrage eines HL2-Servers
* 
* @author	Matthias Reitinger
* @date		20.06.2005 
*/


/*
* Servernachrichten
*
* A2S_SERVERQUERY_GETCHALLENGE:	Anforderung des Challenge-Werts
* A2S_PLAYER:					Anforderung der Spieler-Liste
*/
define('A2S_SERVERQUERY_GETCHALLENGE', "\xFF\xFF\xFF\xFF\x57");
define('A2S_PLAYER', "\xFF\xFF\xFF\xFF\x55");


/*
* Liest ein unsigned byte aus und gibt es zurück
* 
* @param	resource	Dateihandle
*
* @return	int			ausgelesener Byte-Wert
*/
function getByte($fp)
{
	$b = fgetc($fp);
	if ($b === false) return -1;
	return ord($b);
}


/*
* Liest ein Zeichen aus und gibt es zurück
* 
* @param	resource	Dateihandle
*
* @return	string		ausgelesenes Zeichen
*/
function getChar($fp)
{
	$c = fgetc($fp);
	if ($c === false) return -1;
	return $c;
}


/*
* Liest einen nullterminierten String aus und gibt ihn zurück
* 
* @param	resource	Dateihandle
*
* @return	string		ausgelesener String
*/
function getString($fp)
{
	$str = '';
	while (($c = fgetc($fp)) !== false && ord($c) != 0) {
		$str .= $c;
	}
	return $str;
}


/*
* Liest einen Long-Wert aus und gibt ihn zurück
* 
* @param	resource	Dateihandle
*
* @return	string		ausgelesener Long-Wert
*/
function getLong($fp)
{
	$ary = unpack('L', getChar($fp).getChar($fp).getChar($fp).getChar($fp));
	return $ary[1];
}

/*
* Liest einen Float-Wert aus und gibt ihn zurück
* 
* @param	resource	Dateihandle
*
* @return	string		ausgelesener Float-Wert
*/
function getFloat($fp)
{
	$ary = unpack('f', getChar($fp).getChar($fp).getChar($fp).getChar($fp));
	return $ary[1];
}




/*
*
* Implementation
*
*/

$fp = fsockopen('udp://'.$ip, $port);

if (!$fp) {
	die('Server connection failed.');
}

/*
* Challenge holen
*/
if (!fwrite($fp, A2S_SERVERQUERY_GETCHALLENGE)) {
	die('fwrite to server failed.');
}

while (($c = getByte($fp)) != -1) {
	if ($c == 0x41) {
		// 0x41 markiert Anfang der Antwort
		$chall = fread($fp, 4);
		break;
	}
}

/*
* Spielerliste holen
*/
if (!fwrite($fp, A2S_PLAYER.$chall)) {
	die('fwrite to server failed.');
}

$players = array();

while (($c = getByte($fp)) != -1) {
	if ($c == 0x44) {
		// 0x44 markiert Anfang der Antwort
		$num_players = getByte($fp);
		for ($i=0; $i<$num_players; $i++) {
			$index = getByte($fp);
			$players[$index] = array(
				'name' => getString($fp),
				'kills' => getLong($fp),
				'time' => getFloat($fp)
			);				
		}
		break;
	}
}

fclose($fp);

/*
* Debugausgabe
*/
print_r($players);

?>
 
Zurück