Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Netzwerke (https://www.delphipraxis.net/14-netzwerke/)
-   -   Delphi Query an Gameserver (https://www.delphipraxis.net/183987-query-gameserver.html)

Neutral General 24. Feb 2015 12:53

AW: Query an Gameserver
 
Du solltest dir mal TMemoryStream oder TByteStream anschauen.
Das was du da machst kann man damit um einiges übersichtlicher/besser/einfacher lösen.

Deine ganzen Hexstrings sind total unnötig :duck:

Flodding 24. Feb 2015 12:55

AW: Query an Gameserver
 
ja das hat super funktioniert :thumb:

Schlussendlich benötige ich doch noch eine bessere Variante um die Einzelnen Stellen der Antwort auszulesen. So, wie man die Informationen von einem Gameserver per Query abfragen kann, kann man auch die globale serverliste beim Masterserver per Query abfragen. dieses Script habe ich ebenfalls in PHP vorliegen.
Hier ein Link zum Script das die Serverliste anzeigt (Laden dauert etwas):
http://last-templers.de/a2epoch/serverlist.php
Nicht alle Server in der Liste funktionieren.

Problem besteht in den letzten Bytes, die angeben ob der Server Passwortgeschützt ist und ob VAC aktiviert ist.

Code:
Bei Servern OHNE Passwort (647700;00;) funktioniert mein Code.
Bei Servern MIT Passwort (64770100;) funktioniert mein code natürlich nicht, da die letzten Strings des Array dann verschoben werden.
Ich kann das auch mit einer IF ELSE Abfrage lösen, aber irgendwie scheint mir das ganze ziemlich "dreckig" programmiert.
Die einen mögen jetzt sagen: "Funktioniert doch, lass es so" .

Andererseits verstehe ich die Funktion von Sir Rufo nicht so ganz. Ehrlich gesagt garnicht.

Klar ist schon, dass er nur den Header ausliest und überprüft ob die Antwort Gesplittet ist oder nicht. Ich stocke schon an dem punkt, wie ich die ersten 4 Strings, die ja variable Längen haben, auslesen oder definieren soll.

Das mit dem TMemoryStream hatte ich schon probiert. Da kam bei mir nur Gemurkse bei raus.
Da blicke ich nicht durch.

Neutral General 24. Feb 2015 13:14

AW: Query an Gameserver
 
Ein kleines Beispiel:

Delphi-Quellcode:
var
  mem: TMemoryStream;
  intVar, intVarLesen: Integer;
  boolVar, boolVarLesen: Boolean;
begin
  boolVar := true;
  intVar := 123;
 
  mem := TMemoryStream.Create;
  try
    // Integer schreiben
    mem.Write(intVar, SizeOf(Integer));
    // Boolean schreiben
    mem.Write(boolVar, SizeOf(Boolean));
   
    // Vor dem auslesen den Stream an den Anfang positionieren
    mem.Position := 0;

    // Daten in gleicher Reihenfolge auslesen wie sie eingelesen wurden
    mem.Read(intVarLesen, SizeOf(Integer));
    mem.Read(boolVarLesen, SizeOf(Integer));
  finally
    mem.Free;
  end;  
end;
Was du wahrscheinlich machen könntest wär sowas wie:

Delphi-Quellcode:
var
  PreHeader: Array[0..3] of Byte;
  Header: Byte;
  Protocol: Byte;
  tmpChar: AnsiChar;
  ServerName: AnsiString;
begin
  mem.SetSize({größe des Antwortpakets});
  udp1.ReceiveBuf(mem.Memory^, mem.Size);
 
  mem.Position := 0;

  mem.Read(PreHeader[0], SizeOf(PreHeader)); // FF FF FF FF
  mem.Read(Header, SizeOf(Byte));
  mem.Read(Protocol, SizeOf(Byte));

  // Aus folgenden kann/sollte man ne Funktion machen
  ServerName:= '';
  repeat
    mem.Read(tmpChar, SizeOf(AnsiChar));
    if (tmpChar <> #0) then
      ServerName:= ServerName + tmpChar;
  until tmpChar = #0;

  // usw..
end;

p80286 24. Feb 2015 13:31

AW: Query an Gameserver
 
Zitat:

Zitat von Neutral General (Beitrag 1291284)
Du solltest dir mal TMemoryStream oder TByteStream anschauen.
Das was du da machst kann man damit um einiges übersichtlicher/besser/einfacher lösen.

Deine ganzen Hexstrings sind total unnötig :duck:

Zitat:

Zitat von Flodding (Beitrag 1291285)
ja das hat super funktioniert :thumb:

Schön, dann ist ja gut (aber was ist damit konkret gemeint? :gruebel:
Zitat:

Zitat von Flodding (Beitrag 1291285)
Schlussendlich benötige ich doch noch eine bessere Variante um die Einzelnen Stellen der Antwort auszulesen. So, wie man die Informationen von einem Gameserver per Query abfragen kann, kann man auch die globale serverliste beim Masterserver per Query abfragen. dieses Script habe ich ebenfalls in PHP vorliegen.
Hier ein Link zum Script das die Serverliste anzeigt (Laden dauert etwas):
http://last-templers.de/a2epoch/serverlist.php
Nicht alle Server in der Liste funktionieren.

Problem besteht in den letzten Bytes, die angeben ob der Server Passwortgeschützt ist und ob VAC aktiviert ist.

Code:
Bei Servern OHNE Passwort (647700;00;) funktioniert mein Code.
Bei Servern MIT Passwort (64770100;) funktioniert mein code natürlich nicht, da die letzten Strings des Array dann verschoben werden.
Ich kann das auch mit einer IF ELSE Abfrage lösen, aber irgendwie scheint mir das ganze ziemlich "dreckig" programmiert.
Die einen mögen jetzt sagen: "Funktioniert doch, lass es so" .

Das was ich bisher von Deinem Programm gesehen habe, war nun wahrhaftig nicht als positives Codierungsbeispiel zu gebrauchen

Zitat:

Zitat von Flodding (Beitrag 1291285)
Andererseits verstehe ich die Funktion von Sir Rufo nicht so ganz. Ehrlich gesagt garnicht.

Klar ist schon, dass er nur den Header ausliest und überprüft ob die Antwort Gesplittet ist oder nicht. Ich stocke schon an dem punkt, wie ich die ersten 4 Strings, die ja variable Längen haben, auslesen oder definieren soll.

Man könnte z.B. ein pAnsiChar auf das erste Zeichen eines String zeigen lassen und mit Hilfe dieses Pointers den String auslesen.
Aber so lange wir nicht wissen wie Dein Programm jetzt aussieht, ist das eigentlich nur unverbindliches Geblubber.

[OT]
Bevor man sich an's programmieren macht, ist es kein Fehler zunächst einmal die zu verarbeitenden Daten zu analysieren, und diese Datenstruktur zu beschreiben. Oft ergeben sich dan ein oder zwei (Record-)Definitionen mit denen dann auf einmal alles ganz einfach ist. Ein kleines Beispiel hierzu ist #32.
[/OT]


Gruß
K-H

Flodding 24. Feb 2015 13:43

AW: Query an Gameserver
 
Das Funktionierende war auf die Verbindungsproblematik bezogen. Dies funktioniert jetzt schon soweit, dass wenn der Server nicht erreichbar ist, einfach nichts ausgewertet wird. Ändere ich den Queryport aber auf den Spielport zB, dann hängts immernoch.

Delphi-Quellcode:
  ServerName:= '';
  repeat
    mem.Read(tmpChar, SizeOf(AnsiChar));
    if (tmpChar <> #0) then
      ServerName:= ServerName + tmpChar;
  until tmpChar = #0;
da würde spätestens unten bei den Bytes nach den Strings dann wieder die Problematik aufkommen:

Mit Passwort: 8A 84 01 40 00 64 77 01 00

8A84 = Version
01 = Spieler aktuell
40 = Spieler max.
00 = Bots
64 = Typ
77 = Environment
01 = Passwort
00 = VAC status

Ohne Passwort: 8A 84 01 40 00 64 77 00

8A84 = Version
01 = Spieler aktuell
40 = Spieler max.
00 = Bots
64 = Typ
77 = Environment
--> PASSWORT FEHLT
00 = VAC status

Ebenso verhällt es sich bei den aktuellen Spielern auf dem Server. die werden auch als 00 gesendet und somit würden sie dann nur als "stop" für den Stream behandelt werden.

p80286 24. Feb 2015 14:01

AW: Query an Gameserver
 
Ich hab mal aus Deinem HexDump ein Beispiel heraus gefischt:
Code:
8A84 
00 
00 
00 - Bots
00 - Typ
00 - Enviroment
00 - Passwortkenner(?)
00 - VAC status?
00 
00 
00 
C4
Ist der Passwortkenner jetzt nicht gesetzt (x00) oder fehlt er? Und wenn Ja, dan gibt es also mind. 2 verschiedene Satztypen?


Gruß
K-H

Flodding 24. Feb 2015 14:23

AW: Query an Gameserver
 
Wenn man das so betrachtet, dann macht das mit dem Zerlegen und dem ";" und dem Array am Ende keinen Sinn mehr.

Dann wäre es ja sinnvoller im oberen Teil einfach die ersten 4 variablen Strings zu lesen mit den 00en, danach die Bytes direkt an ihrer Position auszuwerten. Dann ist es egal ob 00 dort steht oder 0000 denn dann stehen die ersten 00 für 0 Spieler und die zweiten zB für 0 Bots.

Sir Rufo 24. Feb 2015 14:43

AW: Query an Gameserver
 
Also dieses ganz Rätselraten durch das falsche Zuordnen der einzelnen Bytes ist ja nicht zum Aushalten.

Nimm Papier und Bleistift zu Hand und mach dir mal eine Tabelle mit dem Satzaufbau (Name, Typ, Anzahl der Bytes, Bytes) und trage dann die empfangenen Bytes dort nach den vorgegebenen Regeln ein.

So wie ich die Dokumentation lese und verstehe gibt es da nichts mit einem Passwort Feld. Nach Environment (Byte) kommt Visibility (Byte) und danach VAC (Byte).

Also frisch ans Werk, das hilft dann auch bei der Umsetzung.

Flodding 24. Feb 2015 14:56

AW: Query an Gameserver
 
Zitat:

Zitat von Sir Rufo (Beitrag 1291309)
So wie ich die Dokumentation lese und verstehe gibt es da nichts mit einem Passwort Feld. Nach Environment (Byte) kommt Visibility (Byte) und danach VAC (Byte).

Code:
Visibility   byte   Indicates whether the server requires a password:
0 for public
1 for private

p80286 24. Feb 2015 15:58

AW: Query an Gameserver
 
Zitat:

Zitat von Sir Rufo (Beitrag 1291309)
Also dieses ganz Rätselraten durch das falsche Zuordnen der einzelnen Bytes ist ja nicht zum Aushalten.

Nimm Papier und Bleistift zu Hand und mach dir mal eine Tabelle mit dem Satzaufbau (Name, Typ, Anzahl der Bytes, Bytes) und trage dann die empfangenen Bytes dort nach den vorgegebenen Regeln ein.

:thumb: :thumb:

Flodding 24. Feb 2015 16:02

AW: Query an Gameserver
 
Ich hoffe du hast es so gemeint. Ja... kein Papier :oops:

DataTypeDescriptionByte-LängeHEXErwartet
Headerbyte8 bit character or unsigned integer249I
Protocolbyte8 bit character or unsigned integer21117
Namestringvariable-length byte field, encoded in UTF-8, terminated by 0x00~5B4C2D542D535D2045706F6368204F726967696E732028312E302E352E312F3132353534382900[L-T-S] Epoch Origins (1.0.5.1/125548)
Mapstringvariable-length byte field, encoded in UTF-8, terminated by 0x00~5461766900Tavi
Folderstringvariable-length byte field, encoded in UTF-8, terminated by 0x00~61726D61326172726F77706300arma2arrowpc
Gamestringvariable-length byte field, encoded in UTF-8, terminated by 0x00~4461795A2045706F6368204F726967696E7300Dayz Epoch Origins
IDshort16 bit signed integer48A8433930
Playersbyte8 bit character or unsigned integer200 oder größer0
Max. Playersbyte8 bit character or unsigned integer219 oder kleiner / größer25
Botsbyte8 bit character or unsigned integer200 oder kleiner /größer0
Server Typebyte8 bit character or unsigned integer264d
Environmentbyte8 bit character or unsigned integer277w
Visibilitybyte8 bit character or unsigned integer200 oder 010
VACbyte8 bit character or unsigned integer200 oder 010
Versionstringvariable-length byte field, encoded in UTF-8, terminated by 0x00~8A8433930
Extra Data Flagsbyte8 bit character or unsigned integer200 oder 010

Medium 24. Feb 2015 16:06

AW: Query an Gameserver
 
Ich bin immer noch komplett baff, was du mit diesen ganzen völlig beknackten Umwandlungen nach Hex willst. Die sind ÜBER! Hier, das folgende zusammengetippert, indem ich mir die Struktur von der Valve-Seite in meinen Editor kopiert habe, und daran den Record orientiert. Den mit Hilfe der Typinfos befüllen, und die Sache ist gelutscht. Was ein Gehampel hier.

Delphi-Quellcode:
TInfoRequest = packed record
  RequestHeader: Integer;
  PacketHeader: AnsiChar;
  Payload: array[0..19] of AnsiChar;
end;

TInfoResponse = record
  ResponseHeader: Integer;
  PacketHeader: Byte;
  Protocol: Byte;
  Name: String;
  Map: String;
  Folder: String;
  Game: String;
  ID: SmallInt;
  Players: Byte;
  MaxPlayers: Byte;
  Bots: Byte;
  ServerType: Byte;
  Environment: Byte;
  Visibility: Byte;
  VAC: Byte;
  Version: String;
end;

TBufferArray = array[0..1400] of Byte;


function GetString(aBuffer: TBufferArray; var aIndex: Integer): String;
var
  b: Byte;
begin
  result := '';
  repeat
    Move(aBuffer[aIndex], b, SizeOf(b));
    if b <> 0 then
      result := result + IntToStr(b);
    inc(aIndex);
  until b = 0;
end;

procedure GetInfo;
var
  request: TInfoRequest;
  response: TInfoResponse;
  buffer: TBufferArray;
  i: Integer;
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;
 
  Udp1.SendBuf(request, SizeOf(TInfoRequest));
  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));
  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);

  // In response steht jetzt alles richtig schön drin. Nicht als Hexkacke, sondern sauber als der Typ, den Valve vorgibt.
end;
(Komplett ungetestet und im Editor geschrieben. Mag gut sein, dass da 1-2 Dinge nicht 100%ig hin kommen. Aber NOCH mehr vorkauen geht fast nicht.)
Edit: War alles hübsch eingerückt, aber der "Beautifyer" der DP ist da ja anderer Meinung. Wenn man den Beitrag zitiert wird's besser.

Sir Rufo 24. Feb 2015 16:21

AW: Query an Gameserver
 
Und da sieht man doch schon, dass du immer noch nicht richtig in die Doku geschaut hast.

Wenn der Wert vom Typ BYTE ist, dann hat es da nur 1 (in Worten ein) Byte.
DataTypeDescriptionByte-LängeHEXErwartet
Headerbyte8 bit character or unsigned integer149I
Protocolbyte8 bit character or unsigned integer11117
Namestringvariable-length byte field, encoded in UTF-8, terminated by 0x00~5B 4C 2D 54 2D 53 5D 20 45 70 6F 63 68 20 4F 72 69 67 69 6E 73 20 28 31 2E 30 2E 35 2E 31 2F 31 32 35 35 34 38 29 00[L-T-S] Epoch Origins (1.0.5.1/125548)
Mapstringvariable-length byte field, encoded in UTF-8, terminated by 0x00~54 61 76 69 00Tavi
Folderstringvariable-length byte field, encoded in UTF-8, terminated by 0x00~61 72 6D 61 32 61 72 72 6F 77 70 63 00arma2arrowpc
Gamestringvariable-length byte field, encoded in UTF-8, terminated by 0x00~44 61 79 5A 20 45 70 6F 63 68 20 4F 72 69 67 69 6E 73 00Dayz Epoch Origins
IDshort16 bit signed integer28A 8433930
Playersbyte8 bit character or unsigned integer100 0
Max. Playersbyte8 bit character or unsigned integer11925
Botsbyte8 bit character or unsigned integer1000
Server Typebyte8 bit character or unsigned integer164d
Environmentbyte8 bit character or unsigned integer177w
Visibilitybyte8 bit character or unsigned integer1000
VACbyte8 bit character or unsigned integer1000
Versionstringvariable-length byte field, encoded in UTF-8, terminated by 0x00~8A 84DAS PASST DOCH HIER NICHT
Extra Data Flagsbyte8 bit character or unsigned integer1000
Bei der Version hast du dich definitiv vertan und falsche Daten aufgeschrieben.

Hier Beispielhaften von der Valve Seite
Code:
FF FF FF FF 49 02 67 61 6D 65 32 78 73 2E 63 6F    ÿÿÿÿI.game2xs.co
6D 20 43 6F 75 6E 74 65 72 2D 53 74 72 69 6B 65    m Counter-Strike
20 53 6F 75 72 63 65 20 23 31 00 64 65 5F 64 75     Source #1.de_du
73 74 00 63 73 74 72 69 6B 65 00 43 6F 75 6E 74    st.cstrike.Count
65 72 2D 53 74 72 69 6B 65 3A 20 53 6F 75 72 63    er-Strike: Sourc
65 00 F0 00 05 10 04 64 6C 00 00 31 2E 30 2E 30    e......dl..1.0.0
2E 32 32 00                                        .22.
Das sieht man, dass es den Wert für Extra Data Flags nicht geben muss!

BadenPower 24. Feb 2015 16:29

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291293)
Ändere ich den Queryport aber auf den Spielport zB, dann hängts immernoch.

Zeig' mal her, was Du bereits geschafft hast, damit wir einmal einen Überblick erhalten.

Dann sind notwendige Änderungen und Verbesserungsvorschläge leichter zu beschreiben.

So ist es manchmal mehr oder weniger ein Rätselraten.

Flodding 24. Feb 2015 16:35

AW: Query an Gameserver
 
Möchtest du dass ich das Projekt hochlade? Oder soll ich gesammten Code Posten?

Sir Rufo 24. Feb 2015 17:05

AW: Query an Gameserver
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich habe jetzt mal den Beispiel-Response komplett aufgedröselt (Markdown-Format)
Code:
## A2S_INFO RESPONSE

### Example response for [Counter Strike: Source]:

<pre>
FF FF FF FF 49 02 67 61 6D 65 32 78 73 2E 63 6F   ÿÿÿÿI.game2xs.co
6D 20 43 6F 75 6E 74 65 72 2D 53 74 72 69 6B 65    m Counter-Strike
20 53 6F 75 72 63 65 20 23 31 00 64 65 5F 64 75     Source #1.de_du
73 74 00 63 73 74 72 69 6B 65 00 43 6F 75 6E 74    st.cstrike.Count
65 72 2D 53 74 72 69 6B 65 3A 20 53 6F 75 72 63    er-Strike: Sourc
65 00 F0 00 05 10 04 64 6C 00 00 31 2E 30 2E 30    e......dl..1.0.0
2E 32 32 00                                        .22.
</pre>

#### Check for Protocol

Field | Type | Bytes | Info
:-- | --- | :-- | :--
Header | [long] | <pre>FF FF FF FF</pre> | -1 = Simple Response Format
Payload | &#8734; | <pre>49 02 67 61 6D 65 32 78 73 2E 63 6F 6D 20 43 6F<br>75 6E 74 65 72 2D 53 74 72 69 6B 65 20 53 6F 75<br>72 63 65 20 23 31 00 64 65 5F 64 75 73 74 00 63<br>73 74 72 69 6B 65 00 43 6F 75 6E 74 65 72 2D 53<br>74 72 69 6B 65 3A 20 53 6F 75 72 63 65 00 F0 00<br>05 10 04 64 6C 00 00 31 2E 30 2E 30 2E 32 32 00</pre> |

#### Payload Data

Field | Type | Bytes | Info
:-- | --- | :-- | :--
Header | [byte] | <pre>49</pre> | I
Protocol | [byte] | <pre>02</pre> | 
Name | [string] | <pre>67 61 6D 65 32 78 73 2E 63 6F 6D 20 43 6F 75 6E<br>74 65 72 2D 53 74 72 69 6B 65 20 53 6F 75 72 63<br>65 20 23 31 00</pre> | game2xs.com Counter-Strike Source #1
Map | [string] | <pre>64 65 5F 64 75 73 74 00</pre> | de_dust
Folder | [string] |*<pre>63 73 74 72 69 6B 65 00</pre> | cstrike
Game | [string] | <pre>43 6F 75 6E 74 65 72 2D 53 74 72 69 6B 65 3A 20<br>53 6F 75 72 63 65 00</pre> | Counter-Strike: Source
ID | [short] | <pre>F0 00</pre> | 240
Players | [byte] | <pre>05</pre> | 5
Max. Players | [byte] | <pre>10</pre> | 16
Bots | [byte] | <pre>04</pre> | 4
Server type | [char] | <pre>64</pre> | d = dedicated Server
Environment | [char] | <pre>6C</pre> | l = Linux
Visibility | [byte] | <pre>00</pre> | 0 = public
VAC | [byte] | <pre>00</pre> | 0 = unsecured
Version | [string] | <pre>31 2E 30 2E 30 2E 32 32 00</pre> | 1.0.0.22

[byte]: https://developer.valvesoftware.com/wiki/Byte
[char]: https://developer.valvesoftware.com/wiki/Byte
[short]: https://developer.valvesoftware.com/wiki/Short
[long]: https://developer.valvesoftware.com/wiki/Long
[float]: https://developer.valvesoftware.com/wiki/Float
[string]: https://developer.valvesoftware.com/wiki/String

[Counter Strike: Source]: https://developer.valvesoftware.com/wiki/Counter_Strike:_Source
Im Anhang das gleiche als PDF gerendert

Medium 24. Feb 2015 17:06

AW: Query an Gameserver
 
Hab ich den ganzen Quatsch da oben jetzt umsonst geschrieben?

BadenPower 24. Feb 2015 17:27

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291337)
Möchtest du dass ich das Projekt hochlade? Oder soll ich gesammten Code Posten?

Hochladen wäre die geschicktere Variante.

Flodding 24. Feb 2015 17:29

AW: Query an Gameserver
 
Zitat:

Zitat von Medium (Beitrag 1291342)
Hab ich den ganzen Quatsch da oben jetzt umsonst geschrieben?

Nein ! Nichts ist umsonst wenn du helfen möchtest.

Das Konzept gefällt mir.
Ich kannte die Funktion MOVE nicht und wie man merkt habe ich auch sonst wenig mit dynamischen Inhalten gearbeitet in Delphi.

Ich habe ein wenig mit deinem Code rumprobiert und hab ihn halt um die IP und den Port erweitert. Das Ergebnis wenn ich zB. den Servernamen anzeigen lassen möchte ist jedoch mit mehrmaligem hin und her Probieren ernüchternd gewesen. Wahrscheinlich auf meine Dusseligkeit zurückzuführen.

Delphi-Quellcode:
procedure GetInfo;
var
  request: TInfoRequest;
  response: TInfoResponse;
  buffer: TBufferArray;
  i: Integer;
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.RemoteHost:= form4.edit1.Text;
  form4.udp1.RemotePort:= form4.edit2.Text;
  form4.udp1.Open;

  if (form4.udp1.Connected) then

  form4.Udp1.SendBuf(request, SizeOf(TInfoRequest));
  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));
  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);

     form4.lblServerName.Caption := response.Name;
Das Ergebnis sind nur viele Zahlen die ich meinen vorherigen Antworten vom Server nicht zuweisen konnte.
Zitat:

91764584458393326911211199104327911410510310511011 53240494648465346494749505353525641
Sir Rufo. Ich glaube du gehst von einer falschen Grundsituation aus. Es ist nett dass du mir helfen möchtest und du gibst dir auch gut Mühe mich "richtig" anzustupsen. Jedoch scheinst du zu denken, dass ich nicht verstehe, was du mir bis jetzt beibringen wolltest und scheinbar immernoch willst. Aber du musst einsehen, dass ich verstanden habe was du mir mitteilen möchtest.
Ich habe jetzt verstanden was Byte, String und short für mich zu bedeuten hat.
Wenn ich nach der Länge "Byte" "lesen" lasse, wird auch nur ein Byte (2 physische Zahlen im optischen Sinne) gesucht bzw. ausgegeben. wenn ich 2 Byte lesen lasse, werden 4 Zahlen gelesen.
Ich hoffe ich beruhige dich etwas damit und verärgere dich nicht noch mehr falls das nicht das war was du mir mitteilen wolltest.

MFG

Flodding 24. Feb 2015 17:33

AW: Query an Gameserver
 
Liste der Anhänge anzeigen (Anzahl: 1)
Anhang 42630

Sorry habe eben die Dateien vergessen hochzuladen.

Medium 24. Feb 2015 17:47

AW: Query an Gameserver
 
Würdest du uns Host und Port verraten? Dann würde ich meine Variante gerne mal selbst testen und ggf. debuggen. Vom Prinzip her sollte das an und für sich passen.

Flodding 24. Feb 2015 17:59

AW: Query an Gameserver
 
Zitat:

Zitat von Medium (Beitrag 1291349)
Würdest du uns Host und Port verraten? Dann würde ich meine Variante gerne mal selbst testen und ggf. debuggen. Vom Prinzip her sollte das an und für sich passen.

natürlich gerne :)

Es gibt einmal meinen privaten Server :

Host: 5.45.97.44
Port: 2301

Und dann gibt es die große Serverliste:

http://last-templers.de/a2epoch/serverlist.php

Dauert etwas bis sie geladen hat, aber dann hat man auch noch XXX andere Server zum testen mit verschiedenen Einstellungen. Die Ports in der Liste sind immer die Query Ports.

Medium 24. Feb 2015 18:27

AW: Query an Gameserver
 
Vor ca. einer Minute von deinem Server abgerufen:
Code:
Header: -1
Header2: 73
Protocol: 17
Name: [L-T-S] Epoch Origins (1.0.5.1/125548)
Map: Tavi
Folder: arma2arrowpc
Game: DayZ Epoch Origins
ID: -31606
Players: 1
MaxPlayers: 25
Bots: 0
ServerType: 100
Environment: 119
Visibility: 0
VAC: 0
Einzige Änderung: Das IntToStr() in der GetString Prozedur muss natürlich Chr() heissen. Der Rest passt.

BadenPower 24. Feb 2015 19:07

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291293)
Ändere ich den Queryport aber auf den Spielport zB, dann hängts immernoch.

In der Button2Click fehlt die Abfrage ob Connected.


und in der GetInfo

Delphi-Quellcode:
if (form4.udp1.Connected) then
form4.Udp1.SendBuf(request, SizeOf(TInfoRequest));
form4.Udp1.ReceiveBuf(buffer, SizeOf(buffer));
i := 0;
fehlt das begin-end. So wie Du es hier machst wird nur der Versuch unterbunden SendBuf auszuführen.

Aber die Zeilen danach werden immer ausgeführt, egal ob Connected oder nicht.

Flodding 24. Feb 2015 19:20

AW: Query an Gameserver
 
Also LOB an Medium der mit so wenig Aufwand doch so viel erreicht hat in diesem Thema.

Vielen Dank dafür. 8-)

Der hängt sich immernoch auf wenn ich auf einen falschen Port verbinde.
Habe die Änderungen vorgenommen wie vorgeschlagen:
Delphi-Quellcode:
form4.udp1.RemoteHost:= form4.edit1.Text;
  form4.udp1.RemotePort:= form4.edit2.Text;
  form4.udp1.Open;

  if (form4.udp1.Connected) then
  begin
  form4.Udp1.Send....
end;
Ich weiss ich werde für die folgende Frage bestimmt gesteinigt. Aber warum kommt da eine negative Zahl bei der ID raus? kommt zumindest wenn ich wie folgt aufrufe:
Delphi-Quellcode:
IntToStr(response.ID)
Liegt das wieder an der 8A84 die falschrum sind?

BadenPower 24. Feb 2015 19:28

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291355)
Der hängt sich immernoch auf wenn ich auf einen falschen Port verbinde.
Habe die Änderungen vorgenommen wie vorgeschlagen:

Delphi-Quellcode:
form4.udp1.RemoteHost:= form4.edit1.Text;
  form4.udp1.RemotePort:= form4.edit2.Text;
  form4.udp1.Open;

  if (form4.udp1.Connected) then
  begin
  form4.Udp1.Send....
end;

Nicht das END hinter SendBuf() sondern ganz ans Ende.

Delphi-Quellcode:

begin
  request.RequestHeader := 'ÿÿÿÿ';
  request.PacketHeader := 'T';
  request.Payload := 'Source Engine Query'; // Von mir aus auch mit einer Konstante oder einem Ressourcestring
  request.Payload[24] := #00;

  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.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));
    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);
    //form4.edit1.Text := response.Name;

  end; //hier hin

end;

Flodding 24. Feb 2015 19:32

AW: Query an Gameserver
 
So habe ich es gemacht. Das kopierte Stückchen war wohl etwas unklar.
Delphi-Quellcode:
procedure Get_A2S_INFO;
var
  request: TInfoRequest;
  response: TInfoResponse;
  buffer: TBufferArray;
  i: Integer;
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.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.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));
  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);
  end;
end;

BadenPower 24. Feb 2015 20:58

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291355)
Ich weiss ich werde für die folgende Frage bestimmt gesteinigt. Aber warum kommt da eine negative Zahl bei der ID raus? kommt zumindest wenn ich wie folgt aufrufe:
Delphi-Quellcode:
IntToStr(response.ID)
Liegt das wieder an der 8A84 die falschrum sind?

Nein, dass liegt daran, dass der Typ von ID im Record TInfoResponse falsch deklariert ist.

Statt "SmallInt" muss der Typ von Id "Word" sein.

Dann ist nicht nur die Zahl positiv, sondern der Wert stimmt auch und ist dann 33930.

Flodding 24. Feb 2015 21:10

AW: Query an Gameserver
 
Vielen Dank , das hat auch super geklappt.

Hab jetzt mal rumgespielt und versucht die A2S_PLAYER Daten zu bekommen. Das Funktionierte vorher ja auch schon soweit, dass die aktuelle Spielerzahl ausgegeben wurde.
an dem selben Punkt bin ich jetzt mit der neuen Funktion die ich etwas umgebaut habe.
Delphi-Quellcode:
TPlayerResponse = record
  ResponseHeader: Integer;
  PacketHeader: Byte;
  Challenge: Integer;
  PlayerCount: Byte;
  PlayerIndex: Byte;
  PlayerName: String;
  PlayerScore: Integer;
  PlayerDuration: Integer;
end;
Delphi-Quellcode:
procedure Get_PLAYER_INFO;
var
  request: TInfoRequest;
  response: TPlayerResponse;
  buffer: TBufferArray;
  i: Integer;
  y: integer;
begin
  request.RequestHeader := -1;
  request.PacketHeader := 'U';
  request.Payload := 'FFFFFFFF'; // Von mir aus auch mit einer Konstante oder einem Ressourcestring

  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.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.Challenge, SizeOf(response.Challenge)); inc(i, SizeOf(response.Challenge));

  i := 0;

  request.Payload[0] := chr(buffer[5]);
  request.Payload[1] := chr(buffer[6]);
  request.Payload[2] := chr(buffer[7]);
  request.Payload[3] := chr(buffer[8]);
  form4.Udp1.SendBuf(request, SizeOf(TInfoRequest));
  form4.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));

  Move(buffer[i], response.PlayerCount, SizeOf(response.PlayerCount)); inc(i, SizeOf(response.PlayerCount));

  for y := 0 to response.PlayerCount do
    begin
    Move(buffer[i], response.PlayerIndex, SizeOf(response.PlayerIndex)); inc(i, SizeOf(response.PlayerIndex));
    Move(buffer[i], response.PlayerName, SizeOf(response.PlayerName)); inc(i, SizeOf(response.PlayerName));
    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));
    end;

  form4.lblServerHeader.Caption := chr(response.PacketHeader);  // D = Antwort -> Playerinfos kommen

  end;
end;
Ich bekomme sogar das D zurückgeliefert. Hatte echt Schwierigkeiten das Challenge in den Payload zu bekommen, aber am Ende hat es dann doch geklappt und die Spielerzahl wird wieder ausgegeben.
Jetzt wollt ich natürlich weil ich einfach musste noch die Spielerdaten haben.
Das schien mir auf den ersten Blick auch ganz einfach. Nimmste einfach ne Schleife und lässt ihn durch laufen und jedes Mal die Daten weiter Lesen.
Hab mir ne Listbox vorne mit aufs Form gelegt und dann wollte ich die Listbox mit den SpielerNAMEN füllen.
Delphi-Quellcode:
form4.ListBox1.Items.Add(response.PlayerName)
Jedes Mal wenn ich auslesen möchte kommt ein Fehler.

EDIT: Das mit dem TimeOut funktioniert immernoch nicht richtig in der anderen Funktion.

Medium 24. Feb 2015 21:14

AW: Query an Gameserver
 
@BadenPower
Dann ist der auf der Valve Seite falsch deklariert. Dort ist ID als "short" gelistet, und ganz oben steht in den Typkonventionen: short = 16 bit signed integer
Ein 16 Bit ohne Vorzeichen kommt dort nichtmals vor.

@Flodding
Ich hoffe, dass abgesehen vom nacken funktionieren jetzt auch deutlich wurde, wo du deine Gedankenverknotungen hattest, und wie man prinzipiell mit solchen Dingen umgeht. Was das Ganze hier etwas gemein gemacht hat war, dass die Strings von variabler Länge sind. Wären sie mit festen Längen definiert, könnte man das ganze Geraffel mit dem Move() weg lassen, und das RecieveBuffer() direkt eine TInfoResponse Variable füllen lassen, da die Antwort dann "binär" 1:1 zu der Recordstruktur passen würde (bzw. umgekehrt). Dann wäre das nen Einzeiler.

Edit: Okay, du braucht mehr Grundlagen!!! 0xFFFFFFFF ist nicht 'FFFFFFFF'! Das erste ist eine 32 Bit Zahl in Hex-Darstellung, deins ist ein String. Dein String wäre in Hex 0x4646464646464646, also zu lang und völlig falsch. Du solltest dich bevor du mit Protokollen überhaupt anfängst dringend mit Datentypen und -darstellung befassen.

Flodding 24. Feb 2015 21:44

AW: Query an Gameserver
 
Hab den Fehler gefunden.
Delphi-Quellcode:
Move(buffer[i], response.PlayerName, SizeOf(response.PlayerName)); inc(i, SizeOf(response.PlayerName));
kann ja nicht gehen... wofür hab ich denn EXTRA ne GETSTRING Funktion geschenkt bekommen?
Delphi-Quellcode:
response.PlayerName := GetString(buffer, i);
Muss es natürlich heissen.

Die Abfrage mit den Spielernamen funktioniert nun auch:
Delphi-Quellcode:
procedure Get_PLAYER_INFO;
var
  request: TInfoRequest;
  response: TPlayerResponse;
  buffer: TBufferArray;
  i: Integer;
  y: integer;
begin
  request.RequestHeader := -1;
  request.PacketHeader := 'U';
  request.Payload := 'FFFFFFFF'; // Von mir aus auch mit einer Konstante oder einem Ressourcestring

  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.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.Challenge, SizeOf(response.Challenge)); inc(i, SizeOf(response.Challenge));

  i := 0;

  request.Payload[0] := chr(buffer[5]);
  request.Payload[1] := chr(buffer[6]);
  request.Payload[2] := chr(buffer[7]);
  request.Payload[3] := chr(buffer[8]);
  form4.Udp1.SendBuf(request, SizeOf(TInfoRequest));
  form4.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));
  Move(buffer[i], response.PlayerCount, SizeOf(response.PlayerCount)); inc(i, SizeOf(response.PlayerCount));

  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));
    form4.ListBox1.Items.Add(response.PlayerName);
    end;

  form4.lblServerHeader.Caption := chr(response.PacketHeader);  // D = Antwort -> Playerinfos kommen

  end;
end;
Ja mir fehlen viele Grundlagen was dieses Thema angeht. Ich hatte ehrlich gesagt auch nicht damit gerechnet vor solch Problemen (aus meiner Sicht jetzt) zu stehen als ich meinen kleinen CommunityLauncher angefangen habe zu basteln. Grundsätzlich wollte ich auch NUR die aktuelle Anzahl der Spieler anzeigen lassen, aber es taten sich mit einmal alle Möglichkeiten auf und dadurch ist es erst so eskaliert (wenn dies dann das richtige Wort ist)

Bis jetzt habe ich immer nur kleinere Tools gebastelt die mit dann im Alltag Kleinigkeiten abnehmen oder Dateieinhalte ändern und sowas. Da brauchte ich solch Teufelszeug noch nie und dementsprechend gering sind meine Erfahrungen damit. Wobei ich sagen muss, dass ich in der Vergangenheit wohl auch eher umständlich Programmiert habe als effizient.
Ich habe es auch schon vorher erwähnt. Ich bin kein Professioneller Programmierer und werds leider auch niemals werden. Aber genau dafür gibt es solche Foren, wo Menschen die Wissen haben, es auch teilen können mit denen die es nicht haben oder noch nicht genug.

Trotzdem möchte ich mich hier nochmal bei jedem bedanken der an diesem Thema seinen Beitrag geleistet hat und hoffe, dass zukünftige Forumbesucher mit der selben Problematik es hierdurch leichter haben.

Am Ende bleibt ein Problem übrig...

Zitat:

Wenn der Server nicht erreichbar ist oder der falsche Port angegeben wird, hängt sich das Programm auf.
Wer dafür noch eine Lösung parat hat möge diese doch bitte mit uns teilen :oops:

BadenPower 24. Feb 2015 21:56

AW: Query an Gameserver
 
Zitat:

Zitat von Medium (Beitrag 1291362)
@BadenPower
Dann ist der auf der Valve Seite falsch deklariert. Dort ist ID als "short" gelistet, und ganz oben steht in den Typkonventionen: short = 16 bit signed integer
Ein 16 Bit ohne Vorzeichen kommt dort nichtmals vor.

Das habe ich auch gesehen und mich eigentlich gewundert.

Aber ich habe auch die Ausgabe von dem folgenden Link angeschaut:

http://last-templers.de/a2epoch/query/query.php

Dort wird die ID auch positiv als 33930 dargestellt.
Und eine negative ID macht in meinen Augen doch auch keinen Sinn. Daher bin ich eigentlich der Meinung, dass es ein "Word" sein müsste.

Sir Rufo 24. Feb 2015 22:20

AW: Query an Gameserver
 
Nein, was es ist ist eindeutig von Valve festgelegt: 16 bit signed integer

Was du daraus interpretierst ist und bleibt deine Sache. Du kannst ja auch die ID als HEX-Wert ausgeben, oder daraus ein Bild erzeugen, oder oder oder.
Es ist einfach eine eindeutige ID und das wichtigste ist, dass beim Austausch mit dem Rest der Welt, die korrekte Bytefolge zu dieser ID wieder zurückgegeben wird.

In der Schnittstelle würde ich das immer so belassen, wie es vorgegeben ist ...

BadenPower 25. Feb 2015 09:04

AW: Query an Gameserver
 
Zitat:

Zitat von Sir Rufo (Beitrag 1291368)
Nein, was es ist ist eindeutig von Valve festgelegt: 16 bit signed integer

Es ist richtig, dass es Valve so hinterlegt hat.

Ist es aber auch richtig?

Ich wage daran zu zweifeln, da dort die "Steam Application ID" ausgegeben werden soll und diese beginnen bei 0. Und bei diesem Gameserver mit diesem Port, den uns Flodding genannt hat ist die AppId laut Steamdb.info nun mal 33930 und nicht -31606.

DeddyH 25. Feb 2015 09:17

AW: Query an Gameserver
 
Das ist doch lediglich eine Frage der Interpretation, 2 Byte bleiben 2 Byte.

BadenPower 25. Feb 2015 10:19

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291366)
Am Ende bleibt ein Problem übrig...

Zitat:

Wenn der Server nicht erreichbar ist oder der falsche Port angegeben wird, hängt sich das Programm auf.
Wer dafür noch eine Lösung parat hat möge diese doch bitte mit uns teilen :oops:

Ach da war ja noch etwas.

Delphi-Quellcode:
procedure TForm4.Get_A2S_INFO;
var
  Request: TInfoRequest;
  Response: TInfoResponse;
  Buffer: TBufferArray;
  I: Integer;
  CheckTime: TDateTime;
begin
  Request.RequestHeader := 'ÿÿÿÿ';
  Request.PacketHeader := 'T';
  Request.Payload := 'Source Engine Query';
  Request.Payload[19] := #0;

  Udp1.RemoteHost:= Edit1.Text;
  Udp1.RemotePort:= Edit2.Text;

  Udp1.Open;
  if (Udp1.Connected) then
   begin
    Udp1.SendBuf(Request, SizeOf(TInfoRequest));
    CheckTime := Now();
    Udp1.WaitForData(5000);
    if (SecondsBetween(Now(),CheckTime) <= 1) then
     begin
      Udp1.ReceiveBuf(Buffer, SizeOf(Buffer));

      I := 0;
      Move(Buffer[I], Response.ResponseHeader, SizeOf(Response.ResponseHeader));
      Inc(I, SizeOf(Response.ResponseHeader));

      //...

     end;

   end;

end;
Normalerweise sollte die Funktion WaitForData() true zurückgeben wenn der Server bereit ist. Da bei mir mit D2007 aber immer false geliefert wird, mache das wie oben gepostet.

Kann das einmal jemand prüfen, ob bei höheren Delphi-Versionen True zurückgegeben wird?

Wenn ja dann könnte man das Workaround in höheren Versionen weglassen.

Flodding 25. Feb 2015 10:20

AW: Query an Gameserver
 
EDIT: Frage nach der Antwort gepostet. :oops:

Hallo!

Immernoch die "nicht erreichbar" Problematik.

Mein aktueller Code um die Verbindung aufzubauen:
Delphi-Quellcode:
  form4.udp1.RemoteHost:= '5.45.97.44';
  form4.udp1.RemotePort:= '2301';
  form4.udp1.Open;

  if form4.udp1.Connected then
  begin

  form4.Udp1.SendBuf(request, SizeOf(TInfoRequest));
  form4.Udp1.ReceiveBuf(buffer, SizeOf(buffer));

  form4.udp1.WaitForData(1000);
  if Length(buffer)<1 then
  begin
   form4.udp1.Close;
   exit;
  end;
Wenn der Port korrekt ist, wird 1 Sekunde gewartet und dann der "buffer" gelesen.

Ist der Port aber kein QueryPort:
Delphi-Quellcode:
  form4.udp1.RemoteHost:= '5.45.97.44';
  form4.udp1.RemotePort:= '1111'; // Port geändert
  form4.udp1.Open;

  if form4.udp1.Connected then
  begin

  form4.Udp1.SendBuf(request, SizeOf(TInfoRequest));
  form4.Udp1.ReceiveBuf(buffer, SizeOf(buffer));

  form4.udp1.WaitForData(1000);
  if Length(buffer)<1 then
  begin
   form4.udp1.Close;
   exit;
  end;
Das Programm hängt sich auf.
Ich hab schon nachgelesen und scheinbar hängt es sich nicht wirklich auf, sondern lauscht weiterhin und wartet auf Antwort.

Ich bin auf diese Option gestoßen:
Delphi-Quellcode:
form4.udp1.BlockMode := bmNonBlocking
Damit soll das angeblich funktionieren, jedoch bekomme ich dann immer die Meldung vom "OnError"-Event, dass keine Verbindung aufgebaut werden konnte.
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;
Irgendwelche Ideen?

Flodding 25. Feb 2015 10:38

AW: Query an Gameserver
 
Ich habe das OnError Event erstmal deaktiviert, weil der immer ausgelöst wurde wenn WaitForData zu lange gedauert hat.

Habs so ausprobiert jetzt:
Delphi-Quellcode:
  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));
  CheckTime := Now();
  form4.udp1.WaitForData(1000);

  if (SecondsBetween(Now(),CheckTime) <= 1) then
  begin
  form4.Udp1.ReceiveBuf(buffer, SizeOf(buffer));
  i := 0;
  ...
  ...
Bleibt immernoch hängen und wartet nicht nur 1 Sekunde.

BUG 25. Feb 2015 10:44

AW: Query an Gameserver
 
Da es mir Schmerzen verursacht, es immer wieder zu lesen: Es gibt keine UDP-Verbindung! UDP ist ein verbindungsloses Protokoll. Die Verbindung gibt es auf Anwendungsebene ... also das was du gerade programmierst.
Bezüglich des Fehlers: Guck dir mal den Errorcode an ... eventuell steht da nur so WSAEWOULDBLOCK drin.

BadenPower 25. Feb 2015 10:51

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291427)
Ich habe das OnError Event erstmal deaktiviert, weil der immer ausgelöst wurde wenn WaitForData zu lange gedauert hat.

Habs so ausprobiert jetzt:
Delphi-Quellcode:
form4.udp1.WaitForData(1000);

  if (SecondsBetween(Now(),CheckTime) <= 1) then
  begin
  ...
Bleibt immernoch hängen und wartet nicht nur 1 Sekunde.

Warum hast Du nicht meine Werte übernommen.

Also

Delphi-Quellcode:
form4.udp1.WaitForData(5000);

  if (SecondsBetween(Now(),CheckTime) <= 1) then
  begin
  ...
Weil wenn der TimeOut nur 1 Sekunde (Wert 1000) sein soll, dann ist der Unterschied zwischen CheckTime und Now() in der If-Anweiung IMMER kleiner oder gleich 1 Sekunde.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:10 Uhr.
Seite 2 von 3     12 3      

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