AW: Query an Gameserver
Nachdem das OnError Event deaktiviert wurde, funktionierte dann auch "bmNonBlocking"
Der Workaround funktioniert zwar, aber die Abfragezeit ist mit 5 Sekunden etwas lang.
Delphi-Quellcode:
Dies funktioniert so ohne extra Zeitüberprüfung. Ob Queryport offen oder eben nicht.
form4.udp1.BlockMode := bmNonBlocking;
form4.udp1.RemoteHost:= form4.edit1.Text; form4.udp1.RemotePort:= form4.edit2.Text; form4.udp1.Open; if form4.udp1.Connected then begin form4.Udp1.SendBuf(request, SizeOf(TInfoRequest)); form4.udp1.WaitForData(250); form4.Udp1.ReceiveBuf(buffer, SizeOf(buffer)); i := 0; |
AW: Query an Gameserver
Zitat:
Zitat:
|
AW: Query an Gameserver
Dies hier funktioniert bei mir:
Delphi-Quellcode:
Das Error Event:
procedure Get_A2S_INFO;
var request: TInfoRequest; response: TInfoResponse; buffer: TBufferArray; i: Integer; CheckTime: TDateTime; begin request.RequestHeader := -1; request.PacketHeader := 'T'; request.Payload := 'Source Engine Query'; // Von mir aus auch mit einer Konstante oder einem Ressourcestring request.Payload[19] := #0; form4.udp1.BlockMode := bmNonBlocking; form4.udp1.RemoteHost:= form4.edit1.Text; form4.udp1.RemotePort:= form4.edit2.Text; form4.udp1.Open; if form4.udp1.Connected then begin form4.Udp1.SendBuf(request, SizeOf(TInfoRequest)); form4.udp1.WaitForData(250); form4.Udp1.ReceiveBuf(buffer, SizeOf(buffer)); i := 0; Move(buffer[i], response.ResponseHeader, SizeOf(response.ResponseHeader)); inc(i, SizeOf(response.ResponseHeader)); Move(buffer[i], response.PacketHeader, SizeOf(response.PacketHeader)); inc(i, SizeOf(response.PacketHeader)); Move(buffer[i], response.Protocol, SizeOf(response.Protocol)); inc(i, SizeOf(response.Protocol)); if response.ResponseHeader = -1 then begin response.Name := GetString(buffer, i); response.Map := GetString(buffer, i); response.Folder := GetString(buffer, i); response.Game := GetString(buffer, i); Move(buffer[i], response.ID, SizeOf(response.ID)); inc(i, SizeOf(response.ID)); Move(buffer[i], response.Players, SizeOf(response.Players)); inc(i, SizeOf(response.Players)); Move(buffer[i], response.MaxPlayers, SizeOf(response.MaxPlayers)); inc(i, SizeOf(response.MaxPlayers)); Move(buffer[i], response.Bots, SizeOf(response.Bots)); inc(i, SizeOf(response.Bots)); Move(buffer[i], response.ServerType, SizeOf(response.ServerType)); inc(i, SizeOf(response.ServerType)); Move(buffer[i], response.Environment, SizeOf(response.Environment)); inc(i, SizeOf(response.Environment)); Move(buffer[i], response.Visibility, SizeOf(response.Visibility)); inc(i, SizeOf(response.Visibility)); Move(buffer[i], response.VAC, SizeOf(response.VAC)); inc(i, SizeOf(response.VAC)); response.Version := GetString(buffer, i); Move(buffer[i], response.EDF, SizeOf(response.EDF)); inc(i, SizeOf(response.EDF)); Move(buffer[i], response.EDFPort, SizeOf(response.EDFPort)); inc(i, SizeOf(response.EDFPort)); Move(buffer[i], response.EDFSteamID, SizeOf(response.EDFSteamID)); inc(i, SizeOf(response.EDFSteamID)); Move(buffer[i], response.EDFSpecPort, SizeOf(response.EDFSpecPort)); inc(i, SizeOf(response.EDFSpecPort)); //response.EDFSpecName := GetString(buffer, i); response.EDFKeywords := GetString(buffer, i); Move(buffer[i], response.EDFGameID, SizeOf(response.EDFGameID)); inc(i, SizeOf(response.EDFGameID)); form4.lblServerHeader.Caption := chr(response.PacketHeader); form4.lblServerProtocol.Caption := IntToStr(response.Protocol); form4.lblServerName.Caption := response.Name; form4.lblServerMap.Caption := response.Map; form4.lblServerFolder.Caption := response.Folder; form4.lblServerGame.Caption := response.Game; form4.lblServerID.Caption := inttostr(response.ID); form4.lblServerPlayers.Caption := IntToStr(response.Players); form4.lblServerMaxPlayers.Caption := IntToStr(response.MaxPlayers); form4.lblServerBots.Caption := IntToStr(response.Bots); form4.lblServerType.Caption := chr(response.ServerType); form4.lblServerEnvironment.Caption := chr(response.Environment); form4.lblServerVisibility.Caption := inttostr(response.Visibility); form4.lblServerVAC.Caption := IntToStr(response.VAC); form4.lblServerVersion.Caption := response.Version; end else form4.lblServerName.Caption := 'Server nicht erreichbar'; end; end;
Delphi-Quellcode:
procedure TForm4.udp1Error(Sender: TObject; SocketError: Integer);
begin //showmessage('Could not connect. The server you are trying to query might be down'); //udp1.Active:= false; end; |
AW: Query an Gameserver
Die Sekundenanzeige bei Der Playerinfo will auch nicht so ganz.
Delphi-Quellcode:
TPlayerResponse = record
ResponseHeader: Integer; PacketHeader: Byte; Challenge: Integer; PlayerCount: Byte; PlayerIndex: Byte; PlayerName: String; PlayerScore: Integer; PlayerDuration: Integer; end;
Delphi-Quellcode:
Lese ich die Zeit flasch aus?
procedure Get_PLAYER_INFO;
var request: TInfoRequest; response: TPlayerResponse; buffer: TBufferArray; i: Integer; y: integer; PlayerList: TTreeNode; begin request.RequestHeader := -1; request.PacketHeader := 'U'; request.Payload := 'FFFFFFFF'; Form1.udp1.BlockMode := bmNonBlocking; Form1.udp1.RemoteHost:= Form1.edit1.Text; Form1.udp1.RemotePort:= Form1.edit2.Text; Form1.udp1.Open; if (Form1.udp1.Connected) then begin Form1.Udp1.SendBuf(request, SizeOf(TInfoRequest)); Form1.udp1.WaitForData(250); Form1.Udp1.ReceiveBuf(buffer, SizeOf(buffer)); //Challenge aus Buffer lesen i := 0; Move(buffer[i], response.ResponseHeader, SizeOf(response.ResponseHeader)); inc(i, SizeOf(response.ResponseHeader)); Move(buffer[i], response.PacketHeader, SizeOf(response.PacketHeader)); inc(i, SizeOf(response.PacketHeader)); Move(buffer[i], response.Challenge, SizeOf(response.Challenge)); inc(i, SizeOf(response.Challenge)); if chr(response.PacketHeader) = 'A' then begin //Challende in den PayLoad schreiben request.Payload[0] := chr(buffer[5]); request.Payload[1] := chr(buffer[6]); request.Payload[2] := chr(buffer[7]); request.Payload[3] := chr(buffer[8]); //A2S_PLAYER request mit Challenge senden Form1.Udp1.SendBuf(request, SizeOf(TInfoRequest)); Form1.udp1.WaitForData(250); Form1.Udp1.ReceiveBuf(buffer, SizeOf(buffer)); i := 0; Move(buffer[i], response.ResponseHeader, SizeOf(response.ResponseHeader)); inc(i, SizeOf(response.ResponseHeader)); Move(buffer[i], response.PacketHeader, SizeOf(response.PacketHeader)); inc(i, SizeOf(response.PacketHeader)); if chr(response.PacketHeader) = 'D' then begin Move(buffer[i], response.PlayerCount, SizeOf(response.PlayerCount)); inc(i, SizeOf(response.PlayerCount)); Form1.TreeView1.Items.Clear; for y := 0 to response.PlayerCount - 1 do begin Move(buffer[i], response.PlayerIndex, SizeOf(response.PlayerIndex)); inc(i, SizeOf(response.PlayerIndex)); response.PlayerName := GetString(buffer, i); Move(buffer[i], response.PlayerScore, SizeOf(response.PlayerScore)); inc(i, SizeOf(response.PlayerScore)); Move(buffer[i], response.PlayerDuration, SizeOf(response.PlayerDuration)); inc(i, SizeOf(response.PlayerDuration)); PlayerList := Form1.TreeView1.Items.Add(Nil, response.PlayerName); Form1.TreeView1.Items.AddChild(PlayerList, 'ID: ' + IntToStr(response.PlayerIndex)); Form1.TreeView1.Items.AddChild(PlayerList, 'Kills: ' + IntToStr(response.PlayerScore)); Form1.TreeView1.Items.AddChild(PlayerList, 'Seconds: ' + IntToStr(response.PlayerDuration)); Application.ProcessMessages; end; end; end; end; form1.TreeView1.FullExpand; Form1.udp1.Active := false; end; |
AW: Query an Gameserver
Wie immer gilt: Dokumentation lesen hilft.
|
AW: Query an Gameserver
|
AW: Query an Gameserver
Float ist eine Fließkommazahl. Single wäre der entsprechende Datentyp in Delphi.
|
AW: Query an Gameserver
Ich versuche jetzt die Master-Serverliste abzufragen.
Ich bekomme sogar Antwort. :thumb: Ich hab jetzt etliche Tests gemacht und rumprobiert, aber ich bekomme einfach keine vernünftige Liste mit servern die ich dann per Query abfragen könnte.
Delphi-Quellcode:
TServerListResponse = record
ResponseHeader: Integer; PacketHeader: Word; First: Byte; // Byte Secound: Byte; // Byte Third: Byte; // Byte Fourth: Byte; // Byte Port: Word; // Short end;
Delphi-Quellcode:
Danke im Voraus diesmal :oops:
procedure Get_SERVER_LIST;
var request: TInfoRequest; response: TServerListResponse; buffer: TBufferArray; i: Integer; y: integer; begin // Abfrage der Arma 2 OA Server // Example // 31 FF 30 2E 30 2E 30 2E 30 3A 30 00 5C 6E 61 70 70 5C 35 30 30 00 // Tests // 1ÿ0.0.0.0:0\x00\gamedir\arma2arrowpc\x00 // 31 ff 30 2e 30 2e 30 2e 30 3a 30 5c 78 30 30 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 5c 78 30 30 // 1ÿ0.0.0.0:0\x00\gamedir\arma2arrowpc\x00 // 31 ff 30 2e 30 2e 30 2e 30 3a 30 5c 30 30 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 5c 30 30 // 1ÿ0.0.0.0:0\00\gamedir\arma2arrowpc\00 // 31 ff 30 2e 30 2e 30 2e 30 3a 30 5c 30 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 5c 30 // 1ÿ0.0.0.0:000\gamedir\arma2arrowpc00 // 31 ff 30 2e 30 2e 30 2e 30 3a 30 30 30 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 30 30 // 1ÿ0.0.0.0:0ß\gamedir\arma2arrowpcß // 31 ff 30 2e 30 2e 30 2e 30 3a 30 df 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 df // 1ÿ0.0.0.0:00\gamedir\arma2arrowpc0 // 31 ff 30 2e 30 2e 30 2e 30 3a 30 30 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 30 request.Payload[0] := $31; request.Payload[1] := $FF; request.Payload[2] := $30; request.Payload[3] := $2E; request.Payload[4] := $30; request.Payload[5] := $2E; request.Payload[6] := $30; request.Payload[7] := $2E; request.Payload[8] := $30; request.Payload[9] := $3A; request.Payload[10] := $00; request.Payload[11] := $30; request.Payload[12] := $5C; request.Payload[13] := $67; request.Payload[14] := $61; request.Payload[15] := $6D; request.Payload[16] := $65; request.Payload[17] := $64; request.Payload[18] := $69; request.Payload[19] := $72; request.Payload[20] := $5C; request.Payload[21] := $61; request.Payload[22] := $72; request.Payload[23] := $6D; request.Payload[24] := $61; request.Payload[25] := $32; request.Payload[26] := $61; request.Payload[27] := $72; request.Payload[28] := $72; request.Payload[29] := $6F; request.Payload[30] := $77; request.Payload[31] := $70; request.Payload[32] := $63; request.Payload[33] := $00; Form1.udp1.BlockMode := bmNonBlocking; Form1.udp1.RemoteHost:= 'hl2master.steampowered.com'; Form1.udp1.RemotePort:= '27011'; Form1.udp1.Open; if (Form1.udp1.Connected) then begin Form1.Udp1.SendBuf(request.Payload, SizeOf(request.Payload)); Form1.udp1.WaitForData(250); Form1.Udp1.ReceiveBuf(buffer, SizeOf(buffer)); i := 0; Move(buffer[i], response.ResponseHeader, SizeOf(response.ResponseHeader)); inc(i, SizeOf(response.ResponseHeader)); form1.ListBox1.Clear; for y := 0 to 255 do begin Move(buffer[i], response.First, SizeOf(response.First)); inc(i, SizeOf(response.First)); Move(buffer[i], response.Secound, SizeOf(response.Secound)); inc(i, SizeOf(response.Secound)); Move(buffer[i], response.Third, SizeOf(response.Third)); inc(i, SizeOf(response.Third)); Move(buffer[i], response.Fourth, SizeOf(response.Fourth)); inc(i, SizeOf(response.Fourth)); Move(buffer[i], response.Port, SizeOf(response.Port)); inc(i, SizeOf(response.Port)); Form1.ListBox1.Items.Add(Inttostr(response.First) + '.' + Inttostr(response.Secound) + '.' + inttostr(response.Third) + '.' + inttostr(response.Fourth) + ':' + FloatToStr(response.Port)); Application.ProcessMessages; end; end; Form1.udp1.Active := false; end; |
AW: Query an Gameserver
Was wollen einem wohl diese Worte sagen:
Zitat:
Zitat:
Delphi-Quellcode:
TServerAddressBlock = record
First: Byte; // Byte Second: Byte; // Byte Third: Byte; // Byte Fourth: Byte; // Byte Port: Word; // unsigned Short end; TServerAddresses = array of TServerAddressBlock; TServerListResponse = record ResponseHeader: Integer; PacketHeader: Word; ServerAddresses : TServerAddresses; end; |
AW: Query an Gameserver
Delphi-Quellcode:
nach dem Doppelpunkt fehlt noch die 0 für den Port.
lRequest.Payload[9] := $3A;
lRequest.Payload[10] := $00; |
AW: Query an Gameserver
Ich hatte die Definitionen ja exakt ganauso schon gepostet.
Dass es mehrere Pakete werden für die komplette Serverliste hab ich auch schon verstanden. Ich wollte erstmal nur ein Paket "sortieren" und glaube, dass ich einfach einen falschen Query ausführe. Als Response bekomme ich IP Adressen von Servern die nicht dem Filter entsprechen. Das kann doch nicht an der Aufteilung der Arrays liegen :? Damit kommen auch nur falsche Server raus.
Delphi-Quellcode:
Damit auch:
request.Payload[9] := $3A;
request.Payload[10] := $00; request.Payload[11] := $00; request.Payload[12] := $30; request.Payload[13] := $5C;
Delphi-Quellcode:
request.Payload[9] := $3A;
request.Payload[10] := $00; request.Payload[11] := $30; request.Payload[12] := $30; request.Payload[13] := $5C; |
AW: Query an Gameserver
Dein altes aus Post #88
Delphi-Quellcode:
fehlende 0 also die Zahl 0
request.Payload[0] := $31;
request.Payload[1] := $FF; request.Payload[2] := $30; request.Payload[3] := $2E; request.Payload[4] := $30; request.Payload[5] := $2E; request.Payload[6] := $30; request.Payload[7] := $2E; request.Payload[8] := $30; request.Payload[9] := $3A; // hier ist der Doppelpunkt request.Payload[10] := $00; // StringEnde
Delphi-Quellcode:
Bitte, bitte, bitte Flo. Immer alles aufmerksam lesen.
lRequest.Payload[0] := $31;
lRequest.Payload[1] := $FF; lRequest.Payload[2] := $30; lRequest.Payload[3] := $2E; lRequest.Payload[4] := $30; lRequest.Payload[5] := $2E; lRequest.Payload[6] := $30; lRequest.Payload[7] := $2E; lRequest.Payload[8] := $30; lRequest.Payload[9] := $3A; // hier ist der Doppelpunkt lRequest.Payload[10] := $30; //Port 0 hat hier gefehlt lRequest.Payload[11] := $00; // StringEnde Du machst es uns wirklich nicht leicht. |
AW: Query an Gameserver
Ja entschuldigung .
Es sind meisst nur Flüchtigkeitsfehler und ich mag schon garnicht mehr weiter Fragen stellen weil ich mich langsam anfange über mich selber zu ärgern und schämen. :roll: Dieser Query sollte doch eigentlich dann richtig sein:
Delphi-Quellcode:
Mit diesem Query kommt aber nicht das an was ich angefordert habe.:(
request.Payload[0] := $31; // die "1"
request.Payload[1] := $FF; // ÿ für Weltweit request.Payload[2] := $30; // 0 request.Payload[3] := $2E; // . request.Payload[4] := $30; // 0 request.Payload[5] := $2E; // . request.Payload[6] := $30; // 0 request.Payload[7] := $2E; // . request.Payload[8] := $30; // 0 request.Payload[9] := $3A; // : request.Payload[10] := $30; // 0 request.Payload[11] := $00; // erstes Stringende request.Payload[12] := $5C; // \ request.Payload[13] := $67; // g request.Payload[14] := $61; // a request.Payload[15] := $6D; // m request.Payload[16] := $65; // e request.Payload[17] := $64; // d request.Payload[18] := $69; // i request.Payload[19] := $72; // r request.Payload[20] := $5C; // \ request.Payload[21] := $61; // a request.Payload[22] := $72; // r request.Payload[23] := $6D; // m request.Payload[24] := $61; // a request.Payload[25] := $32; // 2 request.Payload[26] := $61; // a request.Payload[27] := $72; // r request.Payload[28] := $72; // r request.Payload[29] := $6F; // o request.Payload[30] := $77; // w request.Payload[31] := $70; // p request.Payload[32] := $63; // c request.Payload[33] := $00; // Ende 2ter String |
AW: Query an Gameserver
Wie ist denn request.Payload deklariert?
Denn wie in Post 52 kann es ja nicht sein:
Delphi-Quellcode:
TInfoRequest = packed record
RequestHeader: Integer; PacketHeader: AnsiChar; Payload: array[0..19] of AnsiChar; end; |
AW: Query an Gameserver
Ich habe es abgeändert um die Querys wieder Byte für Byte eingeben zu können:
Delphi-Quellcode:
Die anderen beiden Querys habe ich dementsprechend umgebaut und die funktionieren weiterhin.
TInfoRequest = packed record
RequestHeader: array[0..3] of Byte; PacketHeader: array[0..0] of Byte; Payload: array[0..40] of Byte; end; |
AW: Query an Gameserver
Die Syntax aus #93 ist ok und gibt die "arma2arrowpc"-Server von "FF" = "Rest der Welt" (nicht weltweit) ordnungsgemäß zurück.
Mit der Deklaration aus #95 wirst Du allerdings an Grenzen stoßen, wenn Du es dem Benutzer ermöglichen willst, die Auslese-Parameter über Dein Programm zu ändern. |
AW: Query an Gameserver
Ich habe dafür ja auch einen PHP-Vorlage:
Code:
Dort wird ja im oberen Teil Filter und Region definiert:
<pre>
<?php /* Example of how to get server list from steam. Works for both Arma 2 and 3 servers Original Source: https://developer.valvesoftware.com/wiki/User:Pizzahut/test.php */ $master_servers = array("hl2master.steampowered.com"); define("MIN_PORT", 27010); // Range of port numbers which the master servers define("MAX_PORT", 27013); // potentially use. // define("FILTER", '\gamedir\arma3'); // A3 define("FILTER", '\gamedir\arma2arrowpc'); // A2 define("REGION", "\xFF"); // region = world define("TIMEOUT", 2.0); // 2s timeout function query_timeout(&$socket, $seed) { echo "Sending query to master server.\n"; stream_set_timeout($socket, TIMEOUT); if (!fwrite($socket, "1".REGION."$seed\0".FILTER."\0")) { fclose($socket); exit("fwrite error\n"); } echo "Reading response header.\n"; stream_set_timeout($socket, TIMEOUT); $s = bin2hex(fread($socket, 6)); $info = stream_get_meta_data($socket); if ($info['timed_out']) echo "Master server timed out.\n"; else { if ($s !== "ffffffff660a") { fclose($socket); if ($s == "") echo "Expected ff ff ff ff 66 0a (hex) but got nothing.\n"; else echo "Expected ff ff ff ff 66 0a (hex) but got $s.\n"; return True; } } return $info['timed_out']; } // Connect to master server, return timeout info. // The socket is passed as reference and thus returned as well. function master_server_timeout(&$socket, $ip) { $port = MIN_PORT; do { echo "Connecting to master server \"$ip:$port\".\n"; $socket = fsockopen("udp://$ip", $port, $errno, $errstr, TIMEOUT); if (!$socket) exit("Error $errno : $errstr \n"); $timeout = query_timeout($socket, "0.0.0.0:0"); $port = $port + 1; } while ($timeout && ($port <= MAX_PORT)); return $timeout; } // Repeat until list isn't empty. do { // Try all master servers until we find one that isn't timing out. do foreach ($master_servers as $ip) if ($timeout=master_server_timeout($socket, $ip)) fclose($socket); else break; while ($timeout); // Read list with server addresses (IP:port). $count = 0; $old_a1 = 0; $old_a2 = 0; $old_a3 = 0; $old_a4 = 0; $old_a5 = 0; $max_timeouts = 6; do { stream_set_timeout($socket, TIMEOUT); $a1 = ord(fread($socket,1)); $info = stream_get_meta_data($socket); if ($info['timed_out']) { $seed = "$old_a1.$old_a2.$old_a3.$old_a4:$old_a5"; echo "Seed: $seed\n"; while (query_timeout($socket, $seed)); stream_set_timeout($socket, TIMEOUT); $a1 = ord(fread($socket,1)); $info = stream_get_meta_data($socket); if ($info['timed_out']) { echo "Timeout occured.\n"; break; } $check_for_duplicate = 1; } else $check_for_duplicate = 0; // Let's always read the rest of the address (even if it starts with 0) in // order to empty the master server's write buffer. This may avoid subsequent // problems, but I'm paranoid here. $a2 = ord(fread($socket,1)); $a3 = ord(fread($socket,1)); $a4 = ord(fread($socket,1)); $a5 = ord(fread($socket,1))*256 + ord(fread($socket,1)); if ($a1 != 0) { if (($check_for_duplicate==0)||($a1!=$old_a1)||($a2!=$old_a2)|| ($a3!=$old_a3)||($a4!=$old_a4)||($a5!=$old_a5)) { $count++; //echo "$count $a1.$a2.$a3.$a4:$a5\n"; $addy = "$a1.$a2.$a3.$a4"; $key = $addy.":".$a5; echo $key."\n"; } $old_a1 = $a1; $old_a2 = $a2; $old_a3 = $a3; $old_a4 = $a4; $old_a5 = $a5; } } while ($a1 != 0); fclose($socket); } while ($count == 0); echo "Retrieved $count server addresses.\n"; ?> </pre>
Code:
Wenn ich das Script ausführe:
define("FILTER", '\gamedir\arma2arrowpc'); // A2
define("REGION", "\xFF"); // region = world http://last-templers.de/a2epoch/serverlist.php (dauert etwas das Laden) Die Ausgabe ist die, die ich im Programm haben möchte. |
AW: Query an Gameserver
Zitat:
Die ersten 10 Server, welche ich über die Abfrage erhalte sind zum Beispiel: 84.191.11.101:2316 81.169.231.59:2313 85.214.238.7:27016 193.111.140.177:2311 146.0.42.124:2304 217.114.196.201:2301 85.190.173.146:2301 146.0.32.146:2301 178.254.34.206:2311 81.169.250.14:2301 |
AW: Query an Gameserver
So werte ich den Buffer aus:
Delphi-Quellcode:
Die 10 Server die bei mir rauskommen:
if chr(response.PacketHeader) = 'f' then
begin for y := 0 to 10 do begin Move(buffer[i], response.First, SizeOf(response.First)); inc(i, SizeOf(response.First)); Move(buffer[i], response.Second, SizeOf(response.Second)); inc(i, SizeOf(response.Second)); Move(buffer[i], response.Third, SizeOf(response.Third)); inc(i, SizeOf(response.Third)); Move(buffer[i], response.Fourth, SizeOf(response.Fourth)); inc(i, SizeOf(response.Fourth)); Move(buffer[i], response.Port, SizeOf(response.Port)); inc(i, SizeOf(response.Port)); Form1.ListBox1.Items.Add(IntToStr(response.First) + '.' + IntToStr(response.Second) + '.' + IntToStr(response.Third) + '.' + IntToStr(response.Fourth) + ':' + IntToStr(response.Port)); Application.ProcessMessages; end; end; end; 89.163.212.29:64776 89.163.202.2:34921 78.51.20.26:64776 91.64.197.127:34921 213.23.101.70:34921 134.255.218.121:53781 134.255.236.171:34921 134.255.217.20:34329 134.255.220.9:18460 134.255.217.200:24606 :? |
AW: Query an Gameserver
Deine Ports sind falsch.
Schau in Ruhe noch einmal das PHP-Beispiel an, welches Du selbst oben gepostet hast. Wenn Du es dann noch nicht erkannt hast, dann gib nochmals bescheid. |
AW: Query an Gameserver
Im PHP-Code wird IP : PORT wie folgt per "echo" ausgegeben:
Code:
Einige Zeilen zuvor werden $a2 - $a5 gefüllt:
$addy = "$a1.$a2.$a3.$a4";
$key = $addy.":".$a5; echo $key."\n";
Code:
$a1 wird vorher schon auf die selbe Weise gefüllt und es wird überprüft ob "$a1 = 0" bzw. in diesem Fall "$a1 != 0" ist.
$a2 = ord(fread($socket,1));
$a3 = ord(fread($socket,1)); $a4 = ord(fread($socket,1)); $a5 = ord(fread($socket,1))*256 + ord(fread($socket,1)); Wenn ich jetzt den OBEREN Code richtig deute, dann ist "$a5" der Port. Also betrachte ich mir folgende Zeile genauer:
Code:
Ich versuche den Code jetzt einfach mal zu übersetzen:
$a5 = ord(fread($socket,1))*256 + ord(fread($socket,1));
Variable "a5" ist gleich der ASCII-Wert des Binärwertes der empfangenen Daten multipliziert mit 256. Zu diesem wird dann nochmal der ASCII-Wert des Binärwertes von eben addiert. Quellen: http://php.net/manual/de/function.ord.php http://php.net/manual/de/function.fread.php Wenn ich jetzt nachschaue, was "Ord" in Delphi bedeutet: http://www.delphibasics.co.uk/RTL.asp?Name=Ord Dort lese ich heraus, dass ich mit "Ord" in Delphi einen "Integer"-Wert aus folgenden Typen bekomme: " AnsiChar | Char | WideChar | Enumeration | Integer " Dann schaue ich mir mal meine Typ-Definition für den Port an:
Delphi-Quellcode:
Laut diesen Tabellen ist der Typ "Word" in C gleich der Typ "unsigned int".
TServerListResponse = record
ResponseHeader: Integer; PacketHeader: Word; First: Byte; // Byte Second: Byte; // Byte Third: Byte; // Byte Fourth: Byte; // Byte Port: Word; // unsigned Short ServerAdresses: TserverAddresses; end; ganz unten: http://edn.embarcadero.com/article/10156#H15 ca. in der mitte: http://stackoverflow.com/questions/1...void-parameter Ein Blick in die Protokol Doku von Valve: https://developer.valvesoftware.com/...Query_Protocol Port ist in C Typ "unsigned short" und das Equivalent in Delphi dazu ist ein Typ "Char". Eigener Code abgeändert:
Delphi-Quellcode:
Wenn ich jetzt den Serverquery ausführe:
TServerListResponse = record
ResponseHeader: Integer; PacketHeader: Word; First: Byte; // Byte Second: Byte; // Byte Third: Byte; // Byte Fourth: Byte; // Byte Port: Char; // unsigned Short ServerAdresses: TserverAddresses; end;
Delphi-Quellcode:
Das Ergebnis ist weniger befriedigend:
if chr(response.PacketHeader) = 'f' then
begin for y := 0 to 10 do begin Move(buffer[i], response.First, SizeOf(response.First)); inc(i, SizeOf(response.First)); Move(buffer[i], response.Second, SizeOf(response.Second)); inc(i, SizeOf(response.Second)); Move(buffer[i], response.Third, SizeOf(response.Third)); inc(i, SizeOf(response.Third)); Move(buffer[i], response.Fourth, SizeOf(response.Fourth)); inc(i, SizeOf(response.Fourth)); Move(buffer[i], response.Port, SizeOf(response.Port)); inc(i, SizeOf(response.Port)); Form1.ListBox1.Items.Add((IntToStr(response.First)) + '.' + (IntToStr(response.Second)) + '.' + (IntToStr(response.Third)) + '.' + (IntToStr(response.Fourth)) + ':' + response.Port ); Application.ProcessMessages; end; end; end;
Code:
Oh da ist ja das "ÿ" !! Das kenne ich doch vom vorherigen Query!! "ÿ" war doch die von HEX zu Text umgewandelte "FF". Also würde mir eine Umwandlung zu HEX schonmal nichts bringen.
121.21.210.134:ÿ
Ach... sind wir ma experimentierfreudig:
Delphi-Quellcode:
Ergebnis:
char(response.Port) );
Code:
Herrje !! :twisted:
111.105.136.134:ÿ
Okay warte mal wir hatten doch auch in den vorherigen Querys "Shorts", "Bytes", "Strings" und "Words". Ersetzen wir mal die anderen Typen durch die in den gerade gefundenen Listen. Ergebnis ist, dass mit den Typ-Definitionen von den Quellen die Querys falsche Werte zurückliefern. Sind die Quellen falsch ? Lese ich sie einfach nur falsch? Das kann doch nicht so schwer sein die Typen aus einer Tabelle zu übertragen und dann die jeweiligen Funktionen zur Umwandlung in einen String zur Ausgabe in einer Listbox zu finden. |
AW: Query an Gameserver
Ich verstehe nicht warum du jetzt den Port von Word (RICHTIG!) in Char umgewandelt hast..
Der Port ist wie immer eine Zahl und hat nix mit einem String zu tun. |
AW: Query an Gameserver
Lese bitte die Tabelle am Ende dieser Seite:
http://edn.embarcadero.com/article/10156#H15 Laut dieser Tabelle ist ein "unsigned short" in C ein "Char" in Delphi. |
AW: Query an Gameserver
Laut mir ist es ein Word.
Die Tabelle von Embarcadero ist wenn nicht falsch zumindest veraltet oder/und sehr ungenau. |
AW: Query an Gameserver
nagut als Word hab ichs ja auch nicht hinbekommen.
|
AW: Query an Gameserver
Wen interessiert es hier, was ein "unsigned short" von C übersetzt nach Delphi bedeutet?
Es interessiert doch ausschliesslich was der "unsigned short" in der Schnittstelle bedeutet. Es ist ein 16bit Wert (little endian) und den kann man einfach so in ein
Delphi-Quellcode:
oder auch
Word
Delphi-Quellcode:
einlesen.
UInt16
|
AW: Query an Gameserver
Wenn mich nicht alles täuscht kommt der Port als Big Endian an.
Du musst also die Bytereihenfolge tauschen nachdem du den Port ausgelesen hast. Das geht z.B. mit dieser Funktion:
Delphi-Quellcode:
Edit: Auch wenn mir das komisch erscheint weil alle anderen Werte doch als Little Endian ankamen oder nicht?
function SwapWord(W: Word): Word;
asm xchg al, ah end; // .... Move(buffer[i], response.Port, SizeOf(response.Port)); inc(i, SizeOf(response.Port)); response.Port := SwapWord(response.Port); Aber laut
Code:
ist das erste Byte ja scheinbar das MSB, daher Big Endian.
$a5 = ord(fread($socket,1))*256 + ord(fread($socket,1));
(Das irritiert mich grad selbst etwas aber schau mal obs so funktioniert :gruebel:) |
AW: Query an Gameserver
Den PHP-Code kann man nur dann richtig interpretieren, wenn man weiß, wie dieser Ausdruck denn abgearbeitet wird.
PHP-Quellcode:
.
$a5 = ord(fread($socket,1))*256 + ord(fread($socket,1));
Ist die Ausführungs-Reihenfolge von rechts nach links, dann wird zuerst
PHP-Quellcode:
und dann
ord(fread($socket,1))
PHP-Quellcode:
ausgeführt. ;)
ord(fread($socket,1))*256
|
AW: Query an Gameserver
Zitat:
Oder als direkte Übersetzung aus dem PHP-Code so:
Delphi-Quellcode:
Einfach nur eine Zeile im Quellcode geändert und schon kommt der richtige Port-Wert heraus.
Move(lBuffer[lPos], lResponseServer.Fourth, SizeOf(lResponseServer.Fourth));
Inc(lPos, SizeOf(lResponseServer.Fourth)); //Move(lBuffer[lPos], lResponseServer.Port, SizeOf(lResponseServer.Port)); lResponseServer.Port := lBuffer[lPos] * 256 + lBuffer[lPos+1]; Inc(lPos, SizeOf(lResponseServer.Port)); |
AW: Query an Gameserver
Mit der Swapword-Funktion klappt es. Danke Neutral General
Ich muss jetzt aber dazu sagen, dass ich die ganze Zeit den Verdacht hatte, dass die Bytes vertauscht sind. Drauf gekommen bin ich durch das "unsigned" davor; bei den Anderen stand es nicht davor. Aber ich war fest davon überzeugt, dass das nicht so sein wird, da die anderen "Word" ja auch nicht vertauscht waren. Ich hätt ma früher fragen sollen. Jetzt kanns ja jeder sagen. Ich meld mich wieder wenn ich die komplette Serverliste selbst hinbekommen habe, und ja ich weiss keiner glaubt dran, oder wenn ich es nicht geschafft habe.:? |
AW: Query an Gameserver
Zitat:
Da bei einer Port-Angabe es sinnlos wäre negative Werte zu ermöglichen ist der Wert als "unsigned" vorgegeben. Dass die Bytes vertaucht sind, hätte Dir allerdings die Zuhilfename von Windows-Bordmitteln, wie z.B. dem Taschenrechner gezeigt. Dort hättest Du einfach einmal die Zahl, welche Du erhalten hast eingeben können und in Hex umwandeln lassen. Dann eifach die Hex-Werte vertauchen und zurück nach Dezimal umwandeln. Wenn Du dann die erhaltene Zahl als Portadresse in Deinem Programm benutzt hättest. dann hättest Du gesehen, dass Daten empfangen werden. |
AW: Query an Gameserver
Liste der Anhänge anzeigen (Anzahl: 1)
Das die Daten vertauscht sind steht doch lang und breit in der Dokumentation:
Zitat:
Da ich mir dieses Elend mit dem Auslesen und Schreiben nicht mehr ansehen kann, hier mal eine Unit, womit man dieses Pakete sehr einfach zusammenbauen und auch wieder auseinander nehmen kann. Kleine Demo vorweg (alles was einem unbekannt vorkommt ist in der Unit
Delphi-Quellcode:
definiert):
SourceQuery
Delphi-Quellcode:
Ausgabe von
program SimpleTests;
{$APPTYPE CONSOLE} {$R *.res} uses IdGlobal, IdUDPClient, StrUtils, SysUtils, SourceQuery in 'SourceQuery.pas'; procedure ParseInfoResponse( AResponse: TSourceQueryBytes ); var LID: SQUShort; LEDF: SQByte; begin Writeln( 'Parse-Data:' ); Writeln; Writeln( 'Protocol-Header ', AResponse.ReadLong ); Writeln( 'Packet-Header ', AResponse.ReadChar ); Writeln( 'Protocol ', AResponse.ReadByte ); Writeln( 'Name ', AResponse.ReadString ); Writeln( 'Map ', AResponse.ReadString ); Writeln( 'Folder ', AResponse.ReadString ); Writeln( 'Game ', AResponse.ReadString ); LID := AResponse.ReadUShort; Writeln( 'ID ', LID ); Writeln( 'Players ', AResponse.ReadByte ); Writeln( 'Max. Players ', AResponse.ReadByte ); Writeln( 'Bots ', AResponse.ReadByte ); Writeln( 'Server Type ', AResponse.ReadChar ); Writeln( 'Environment ', AResponse.ReadChar ); Writeln( 'Visibility ', AResponse.ReadByte ); Writeln( 'VAC ', AResponse.ReadByte ); // Testen auf "The Ship" if ( LID >= 2400 ) and ( LID <= 2499 ) then begin Writeln( 'Mode ', AResponse.ReadByte ); Writeln( 'Witnesses ', AResponse.ReadByte ); Writeln( 'Duration ', AResponse.ReadByte ); end; Writeln( 'Version ', AResponse.ReadString ); if not AResponse.Eof then begin LEDF := AResponse.ReadByte; Writeln( 'EDF ', LEDF ); if LEDF and $80 = $80 then begin Writeln( 'Port ', AResponse.ReadShort ); end; if LEDF and $10 = $10 then begin Writeln( 'SteamID ', AResponse.ReadLongLong ); end; if LEDF and $40 = $40 then begin Writeln( 'Port ', AResponse.ReadShort ); Writeln( 'Name ', AResponse.ReadString ); end; if LEDF and $20 = $20 then begin Writeln( 'Keywords ', AResponse.ReadString ); end; if LEDF and $01 = $01 then begin Writeln( 'GameID ', AResponse.ReadLongLong ); end; end; end; procedure TestInfoResponse; var LResponse: TSourceQueryBytes; begin Writeln( 'Example response for Counter Strike: Source:' ); Writeln; LResponse.SetData( {AData} HexStrToBytes( {AHexStr} StringReplace( {} 'FF FF FF FF 49 02 67 61 6D 65 32 78 73 2E 63 6F' + {} '6D 20 43 6F 75 6E 74 65 72 2D 53 74 72 69 6B 65' + {} '20 53 6F 75 72 63 65 20 23 31 00 64 65 5F 64 75' + {} '73 74 00 63 73 74 72 69 6B 65 00 43 6F 75 6E 74' + {} '65 72 2D 53 74 72 69 6B 65 3A 20 53 6F 75 72 63' + {} '65 00 F0 00 05 10 04 64 6C 00 00 31 2E 30 2E 30' + {} '2E 32 32 00', {OldPattern} ' ', {NewPattern} '', {Flags} [rfReplaceAll] ) ) ); ParseInfoResponse( LResponse ); end; procedure RealInfoRequest; var LRequest, LResponse: TSourceQueryBytes; LUdp: TIdUDPClient; LBuffer: TIdBytes; LResponseSize: Integer; begin // Prepare Request LRequest.WriteLong( SQ_SIMPLEPACKET_PROTOCOL_HEADER ); LRequest.WriteByte( SQ_INFO_REQUEST_HEADER ); LRequest.WriteString( 'Source Engine Query' ); Writeln( 'REQUEST-DATA:' ); Writeln; Writeln( LRequest.ToString ); Writeln; LBuffer := LRequest.GetData; LUdp := TIdUDPClient.Create( nil ); try // Send Request Write( 'Sending ... ' ); LUdp.SendBuffer( '5.45.97.44', 2301, LBuffer ); // Receive Response SetLength( LBuffer, SQ_PACKET_MAXSIZE ); Write( 'Receiving ... ' ); LResponseSize := LUdp.ReceiveBuffer( LBuffer ); Writeln( LResponseSize, ' Bytes' ); SetLength( LBuffer, LResponseSize ); Writeln; finally LUdp.Free; end; Writeln( 'RESPONSE-DATA:' ); Writeln; Writeln( DumpBuffer( LBuffer ) ); Writeln; // Parse Response LResponse.SetData( LBuffer ); ParseInfoResponse( LResponse ); end; procedure RealMasterQueryRequest; var LRequest, LResponse: TSourceQueryBytes; LBuffer: TIdBytes; LBufferSize: Integer; LUdp: TIdUDPClient; LServerAddress: TSQServerAddressBlock; LCount, LRetries: Integer; begin LServerAddress.IP1 := 0; LServerAddress.IP2 := 0; LServerAddress.IP3 := 0; LServerAddress.IP4 := 0; LServerAddress.Port := 0; LUdp := TIdUDPClient.Create( nil ); try LCount := 0; repeat // Daten abrufen ... LRequest.Clear; LRequest.WriteByte( $31 ); // Message Type LRequest.WriteByte( SQ_REGIONCODE_RESTOFTHEWORLD ); // Region Code LRequest.WriteString( LServerAddress.ToString ); // IP-Address LRequest.WriteString( '\gamedir\arma2arrowpc' ); // Filter LBuffer := LRequest.GetData; // Send Request LUdp.SendBuffer( 'hl2master.steampowered.com', 27011, LBuffer ); LRetries := 0; repeat if LRetries >= 3 then raise Exception.Create( 'Too many retries' ); SetLength( LBuffer, SQ_PACKET_MAXSIZE ); LBufferSize := LUdp.ReceiveBuffer( LBuffer, 2000 ); Inc( LRetries ); until LBufferSize > 0; SetLength( LBuffer, LBufferSize ); LResponse.SetData( LBuffer ); Assert( LResponse.ReadLong = SQ_SIMPLEPACKET_PROTOCOL_HEADER ); Assert( LResponse.ReadByte = $66 ); Assert( LResponse.ReadByte = $0A ); // Parse the Server-Addresses while not LResponse.Eof do begin Inc( LCount ); LServerAddress.IP1 := LResponse.ReadByte; LServerAddress.IP2 := LResponse.ReadByte; LServerAddress.IP3 := LResponse.ReadByte; LServerAddress.IP4 := LResponse.ReadByte; LServerAddress.Port := swap( LResponse.ReadUShort ); // swap weil die Doku das sagt Writeln( LCount:7, '. ', LServerAddress.ToString ); end; until ( LServerAddress.ToString = '0.0.0.0:0' ); // ... bis die leere Adresse zurückkommt finally LUdp.Free; end; end; begin try TestInfoResponse; RealInfoRequest; RealMasterQueryRequest; except on E: Exception do Writeln( E.ClassName, ': ', E.Message ); end; ReadLn; end.
Delphi-Quellcode:
:
RealInfoRequest
Code:
In der ganz kurzen Form (ohne Dump und Kommentare)) sieht ein Request dann wie folgt aus
REQUEST-DATA:
FF FF FF FF 54 53 6F 75 72 63 65 20 45 6E 67 69 ÿÿÿÿTSource Engi 6E 65 20 51 75 65 72 79 00 ne Query. Sending ... Receiving ... 196 Bytes RESPONSE-DATA: FF FF FF FF 49 11 5B 4C 2D 54 2D 53 5D 20 45 70 ÿÿÿÿI.[L-T-S] Ep 6F 63 68 20 4F 72 69 67 69 6E 73 20 28 31 2E 30 och Origins (1.0 2E 35 2E 31 2F 31 32 35 35 34 38 29 00 54 61 76 .5.1/125548).Tav 69 00 61 72 6D 61 32 61 72 72 6F 77 70 63 00 44 i.arma2arrowpc.D 61 79 5A 20 45 70 6F 63 68 20 4F 72 69 67 69 6E ayZ Epoch Origin 73 00 8A 84 01 19 00 64 77 00 00 31 2E 36 33 2E s.??...dw..1.63. 31 32 35 35 34 38 00 B1 FE 08 01 CC 2C AF 75 14 125548.±þ..Ì,¯u. 40 01 62 74 2C 72 31 36 33 2C 6E 31 32 35 35 34 @.bt,r163,n12554 38 2C 73 37 2C 69 31 2C 6D 66 2C 6C 66 2C 76 66 8,s7,i1,mf,lf,vf 2C 64 74 2C 74 63 6F 6F 70 2C 67 36 35 35 34 35 ,dt,tcoop,g65545 2C 63 32 31 34 37 34 38 33 36 34 37 2D 32 31 34 ,c2147483647-214 37 34 38 33 36 34 37 2C 70 77 2C 00 8A 84 00 00 7483647,pw,.??.. 00 00 00 00 .... Parse-Data: Protocol-Header -1 Packet-Header I Protocol 17 Name [L-T-S] Epoch Origins (1.0.5.1/125548) Map Tavi Folder arma2arrowpc Game DayZ Epoch Origins ID 33930 Players 1 Max. Players 25 Bots 0 Server Type d Environment w Visibility 0 VAC 0 Version 1.63.125548 EDF 177 Port 2302 SteamID 90094488230087681 Keywords bt,r163,n125548,s7,i1,mf,lf,vf,dt,tcoop,g65545,c2147483647-21474 83647,pw, GameID 33930
Delphi-Quellcode:
Der komplette Source im Anhang
procedure InfoRequest;
var LRequest, LResponse: TSourceQueryBytes; LUdp: TIdUDPClient; LBuffer: TIdBytes; LResponseSize: Integer; begin LRequest.WriteLong( SQ_SIMPLEPACKET_PROTOCOL_HEADER ); LRequest.WriteByte( SQ_INFO_REQUEST_HEADER ); LRequest.WriteString( 'Source Engine Query' ); LBuffer := LRequest.GetData; LUdp := TIdUDPClient.Create( nil ); try LUdp.SendBuffer( '5.45.97.44', 2301, LBuffer ); SetLength( LBuffer, SQ_PACKET_MAXSIZE ); LResponseSize := LUdp.ReceiveBuffer( LBuffer ); SetLength( LBuffer, LResponseSize ); finally LUdp.Free; end; LResponse.SetData( LBuffer ); ParseInfoResponse( LResponse ); end; |
AW: Query an Gameserver
Zitat:
Da wundert es mich nicht mehr, dass viele Programme, welche nur ein Fenster haben zum Teil und das ohne Daten geladen zu haben, bereits 50kb im Hauptspeicher belegen, statt den eigentlich erforderlichen 4kb. |
AW: Query an Gameserver
Jeder wie er will von Spaghetticode bis ordentlich strukturiert. Irgendwo dazwischen sortiert man sich ein. Wo siehst du dich da (rhetorische Frage, es reicht wenn du dir die selber beantwortest).
|
AW: Query an Gameserver
...
Ich häng immernoch an der Kompletten Serverliste... Ich bekomme stets nur den ersten Teil, danch bekomme ich nichts brauchbares... Noch einer Lust mir zu helfen ? MFG Flo |
AW: Query an Gameserver
Irgendwie hab ich meinen aktuellen Code vergessen:
Delphi-Quellcode:
irgendwie bekomme ich 4 mal die selbe liste.
procedure Get_SERVER_LIST(a1: byte; a2: byte; a3: byte; a4: byte; a5: Word);
var // request : TA2S_InfoRequest; request : TServerListRequest; response : TServerListResponse; buffer : TBufferArray; i : Integer; y : Integer; endoflist : Boolean; endofpartlist : Boolean; new_a1 : byte; new_a2 : byte; new_a3 : byte; new_a4 : byte; new_a5 : word; old_a1 : byte; old_a2 : byte; old_a3 : byte; old_a4 : byte; old_a5 : word; old_seed : String; new_seed : String; newport_plain: Integer; oldport_plain: Integer; begin old_a1 := $30; old_a2 := $30; old_a3 := $30; old_a4 := $30; old_a5 := $3030; // \gamedir\arma2arrowpc // 31 FF 30 2e 30 2e 30 2e 30 3a 30 00 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 00 // \gamedir\arma3 // 31 ff 30 2e 30 2e 30 2e 30 3a 30 00 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 33 request.RequestHeader := $31; request.PacketHeader := $FF; request.First := $30; request.First_dot := $2E; request.Second := $30; request.Second_dot := $2E; request.Third := $30; request.Third_dot := $2E; request.Fourth := $30; request.double_dot := $3A; request.Port := $3030; request.Payload[0] := $00; request.Payload[1] := $5C; request.Payload[2] := $67; request.Payload[3] := $61; request.Payload[4] := $6D; request.Payload[5] := $65; request.Payload[6] := $64; request.Payload[7] := $69; request.Payload[8] := $72; request.Payload[9] := $5C; request.Payload[10] := $61; request.Payload[11] := $72; request.Payload[12] := $6D; request.Payload[13] := $61; request.Payload[14] := $33; request.Payload[15] := $00; Form1.udp1.BlockMode := bmNonBlocking; Form1.udp1.RemoteHost := 'hl2master.steampowered.com'; Form1.udp1.RemotePort := '27011'; if Form1.udp1.Active = false then begin form1.udp1.Active := true; form1.ListBox1.Clear; endoflist := false; end; if (Form1.udp1.Connected) then begin y := 0; repeat i := 0; form1.udp1.CleanupInstance; Form1.Udp1.SendBuf(request, SizeOf(request)); Form1.udp1.WaitForData(250); Form1.Udp1.ReceiveBuf(buffer, SizeOf(buffer)); Move(buffer[i], response.ResponseHeader, SizeOf(response.ResponseHeader)); inc(i, SizeOf(response.ResponseHeader)); Move(buffer[i], response.PacketHeader, SizeOf(response.PacketHeader)); inc(i, SizeOf(response.PacketHeader)); // form1.Caption := chr(response.ResponseHeader) + chr(response.PacketHeader) + IntToStr(i); form1.Memo1.Text := bintostr((buffer)); repeat Move(buffer[i], response.First, SizeOf(response.First)); inc(i, SizeOf(response.First)); Move(buffer[i], response.Second, SizeOf(response.Second)); inc(i, SizeOf(response.Second)); Move(buffer[i], response.Third, SizeOf(response.Third)); inc(i, SizeOf(response.Third)); Move(buffer[i], response.Fourth, SizeOf(response.Fourth)); inc(i, SizeOf(response.Fourth)); // Response.Port := Buffer[i] * 256 + Buffer[i+1]; Inc(i, SizeOf(Response.Port)); // Weil die Bytes vertauscht sind, müssen sie umgedreht werden für ein richtiges newport_plain := Buffer[i] * 256 + Buffer[i+1]; Inc(i, SizeOf(Response.Port)); // Weil die Bytes vertauscht sind, müssen sie umgedreht werden für ein richtiges new_a1 := response.First; new_a2 := response.Second; new_a3 := response.Third; new_a4 := response.Fourth; new_a5 := response.Port; new_seed := IntToStr(new_a1) + IntToStr(new_a2) + IntToStr(new_a3) + IntToStr(new_a4) + IntToStr(new_a5); if (response.First <> 00) AND (response.Second <> 00) AND (response.Third <> 00) AND (response.Fourth <> 00) then begin form1.duplicatcounter := 0; Form1.ListBox1.Items.Add ((IntToStr(new_a1)) + '.' + (IntToStr(new_a2)) + '.' + (IntToStr(new_a3)) + '.' + (IntToStr(new_a4)) + ':' + IntToStr((newport_plain)) ); old_a1 := response.First; old_a2 := response.Second; old_a3 := response.Third; old_a4 := response.Fourth; old_a5 := newport_plain; old_seed := IntToStr(old_a1) + IntToStr(old_a2) + IntToStr(old_a3) + IntToStr(old_a4) + IntToStr(newport_plain); Application.ProcessMessages; end else begin Form1.duplicatcounter := form1.duplicatcounter + 1; request.First := strtoint( StringToHex(inttostr(old_a1))); request.Second := strtoint( StringToHex(inttostr(old_a2))); request.Third := strtoint( StringToHex(inttostr(old_a3))); request.Fourth := strtoint( StringToHex(inttostr(old_a4))); request.Port := strtoint( StringToHex(inttostr(old_a5))); Form1.Edit3.Text := StringToHex(inttostr(old_a1) + inttostr(old_a2) + inttostr(old_a3) + inttostr(old_a4) + inttostr(old_a5)) ; end; y := y + 1; form1.Caption := inttostr(y); // until (IntToStr(response.First)) + '.' + (IntToStr(response.Second)) + '.' + (IntToStr(response.Third)) + '.' + (IntToStr(response.Fourth)) + ':' + IntToStr((response.Port)) = '0.0.0.0:0'; until form1.duplicatcounter = 2; Form1.ListBox1.Items.Add ('---------------'); Form1.ListBox1.Items.Add ('---------------'); Form1.ListBox1.Items.Add ('NewSeed: ' + new_seed); Form1.ListBox1.Items.Add ('OldSeed: ' + old_seed); Form1.ListBox1.Items.Add ('---------------'); Form1.ListBox1.Items.Add ('---------------'); until y > 500; end; Form1.udp1.Active := false; form1.Caption := 'Servers: ' + inttostr(Form1.ListBox1.Items.Count -1); end; |
AW: Query an Gameserver
Zitat:
Darum würde ich zunächst einmal den Buffer vor versenden des Request nullen
Delphi-Quellcode:
wenn beim zweiten lesen nur Nullen kommen, scheint die Gegenstelle keine Daten geliefert zu haben.
fillchar
Delphi-Quellcode:
Und wofür ist dieses seltsame Konstrukt gut?
request.First := strtoint( StringToHex(inttostr(old_a1)));
Gruß K-H |
AW: Query an Gameserver
Danke für den Hinweis mit dem Leeren des Buffers. Leider hat dies noch nicht zum Erfolg geführt.
Delphi-Quellcode:
Nachdem ich das ganze ein wenig überarbeitet habe, komme ich nun wenigstens schonmal zu einem sicheren Ergebnis. Ich bekomme immer exakt 2 Mal die selbe Liste (geplant -> y - Vaiable) obwohl ich die IP Adresse im "response" ändere.
FillChar(buffer, SizeOf(buffer), 0);
Hier erstmal der Code:
Delphi-Quellcode:
Mir scheint ich hab immernoch ein Problem damit die empfangenen Bytes für die IP und das Word für den Port richtig zu übergeben.
procedure Get_SERVER_LIST();
var request : TServerListRequest; response : TServerListResponse; buffer : TBufferArray; i : Integer; y : Integer; new_a1 : byte; new_a2 : byte; new_a3 : byte; new_a4 : byte; new_a5 : word; old_a1 : byte; old_a2 : byte; old_a3 : byte; old_a4 : byte; old_a5 : word; old_seed : String; new_seed : String; begin old_a1 := 30; old_a2 := 30; old_a3 := 30; old_a4 := 30; old_a5 := 3030; // \gamedir\arma2arrowpc // 31 FF 30 2e 30 2e 30 2e 30 3a 30 00 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 32 61 72 72 6f 77 70 63 00 // \gamedir\arma3 // 31 ff 30 2e 30 2e 30 2e 30 3a 30 00 5c 67 61 6d 65 64 69 72 5c 61 72 6d 61 33 Form1.udp1.BlockMode := bmNonBlocking; Form1.udp1.RemoteHost := 'hl2master.steampowered.com'; Form1.udp1.RemotePort := '27011'; form1.udp1.Open; y := 0; form1.ListBox1.Clear; if (Form1.udp1.Connected) then begin repeat request.RequestHeader := $31; request.PacketHeader := $FF; request.First := old_a1; request.First_dot := $2E; request.Second := old_a2; request.Second_dot := $2E; request.Third := old_a3; request.Third_dot := $2E; request.Fourth := old_a4; request.double_dot := $3A; request.Port := old_a5; request.Payload[0] := $00; request.Payload[1] := $5C; request.Payload[2] := $67; request.Payload[3] := $61; request.Payload[4] := $6D; request.Payload[5] := $65; request.Payload[6] := $64; request.Payload[7] := $69; request.Payload[8] := $72; request.Payload[9] := $5C; request.Payload[10] := $61; request.Payload[11] := $72; request.Payload[12] := $6D; request.Payload[13] := $61; request.Payload[14] := $33; request.Payload[15] := $00; Form1.Udp1.SendBuf(request, SizeOf(request)); Form1.udp1.WaitForData(250); Form1.Udp1.ReceiveBuf(buffer, SizeOf(buffer)); i := 0; Move(buffer[i], response.ResponseHeader, SizeOf(response.ResponseHeader)); inc(i, SizeOf(response.ResponseHeader)); Move(buffer[i], response.PacketHeader, SizeOf(response.PacketHeader)); inc(i, SizeOf(response.PacketHeader)); repeat Move(buffer[i], response.First, SizeOf(response.First)); inc(i, SizeOf(response.First)); Move(buffer[i], response.Second, SizeOf(response.Second)); inc(i, SizeOf(response.Second)); Move(buffer[i], response.Third, SizeOf(response.Third)); inc(i, SizeOf(response.Third)); Move(buffer[i], response.Fourth, SizeOf(response.Fourth)); inc(i, SizeOf(response.Fourth)); Response.Port := Buffer[i] * 256 + Buffer[i+1]; Inc(i, SizeOf(Response.Port)); // Weil die Bytes vertauscht sind, müssen sie umgedreht werden für ein richtiges new_a1 := response.First; new_a2 := response.Second; new_a3 := response.Third; new_a4 := response.Fourth; new_a5 := response.Port; new_seed := IntToStr(new_a1) + IntToStr(new_a2) + IntToStr(new_a3) + IntToStr(new_a4) + IntToStr(new_a5); if (new_seed <> '00000') then begin form1.duplicatcounter := 0; Form1.ListBox1.Items.Add ((IntToStr(new_a1)) + '.' + (IntToStr(new_a2)) + '.' + (IntToStr(new_a3)) + '.' + (IntToStr(new_a4)) + ':' + IntToStr((new_a5)) ); old_a1 := new_a1; old_a2 := new_a2; old_a3 := new_a3; old_a4 := new_a4; old_a5 := new_a5; old_seed := IntToStr(old_a1) + IntToStr(old_a2) + IntToStr(old_a3) + IntToStr(old_a4) + IntToStr(new_a5); Application.ProcessMessages; end else begin Form1.duplicatcounter := form1.duplicatcounter + 1; end; until form1.duplicatcounter = 1; y := y + 1; Form1.ListBox1.Items.Add ('---------------'); Form1.ListBox1.Items.Add ('---------------'); Form1.ListBox1.Items.Add ('NewSeed: ' + new_seed); Form1.ListBox1.Items.Add ('OldSeed: ' + old_seed); Form1.ListBox1.Items.Add ('---------------'); Form1.ListBox1.Items.Add ('---------------'); FillChar(Buffer, SizeOf(buffer), 0); // Buffer leeren until y = 2; end; Form1.udp1.Close; form1.Caption := 'Servers: ' + inttostr(Form1.ListBox1.Items.Count -1); end; :oops::cry: |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:42 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz