Delphi-PRAXiS
Seite 4 von 12   « Erste     234 56     Letzte »    

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)

Flodding 22. Feb 2015 12:18

AW: Query an Gameserver
 
ja das habe ich natürlich probiert...

von SIGNED INT to HEX funktionierts ja auch.

aber von HEX to SIGNED INT häng ich. ich bekomms nur in INT gewandelt und das gibt dann den falschen wert.

Sir Rufo 22. Feb 2015 13:17

AW: Query an Gameserver
 
Es ist erheblich einfacher als du denkst, aber du musst eben etwas umdenken :)

Zunächst einmal schaust du dir die Datentypen an, die Valve da vorgibt und suchst dir die passenden Delphi-Typen dazu heraus
http://docwiki.embarcadero.com/RADSt...Der_Typ_Single

Dann könnte man das hier bauen
Delphi-Quellcode:
type
  TValveByte    = Byte;    {8 bit character or unsigned integer}
  TValveShort   = SmallInt; {16 bit signed integer}
  TValveLong    = Integer; {32 bit signed integer}
  TValveFloat   = Single;  {32 bit floating point}
  TValveLongLong = Cardinal; {64 bit unsigned integer}
Jetzt gibt es in Delphi auch so nette Sachen wie Delphi-Referenz durchsuchenTStream und der kann Delphi-Referenz durchsuchenTStream.WriteData und (viel Spanier hier) Delphi-Referenz durchsuchenTStream.ReadData.

Du bekommst ja eine Handvoll Bytes und die kann man in einen Delphi-Referenz durchsuchenTBytesStream packen und dann liest man ganz gemütlich die Daten heraus.

Hier mal ein kleines Beispiel zum Starten:
Delphi-Quellcode:
const
  SIMPLE_RESPONSE_HEADER : TValveLong = $FFFFFFFF;
  MULTIPACKET_RESPONSE_HEADER : TValveLong = $FFFFFFFE;

procedure Foo( AResponse : TBytes );
var
  LResponseStream : TStream;
  LHeader : TValveLong;
begin
  LResponseStream := TBytesStream.Create( AResponse );
  try
    LResponseStream.ReadData( LHeader ); // Wir lesen den 4-Byte Header
    case LHeader of
      SIMPLE_RESPONSE_HEADER :
        WorkOnSimpleResponse( LResponseStream );
      MULTIPACKET_RESPONSE_HEADER :
        WorkOnMultiPacketResponse( LResponseStream );
    else
      raise Exception.CreateFmt( 'Unknown Header Value %8.8x', [LHeader] );
    end;
  finally
    LResponseStream.Free;
  end;
end;
Wie du sehen kannst, vermeide ich auf Teufel komm raus, irgendwo im Quelltext mit Magic Values zu arbeiten.

Wenn irgendein Wert eine bestimmte Bedeutung hat, dann definiert man sich einen Konstante und verwendet diese Konstante im Quelltext. Dann bleibt das auch immer schön lesbar.

Sir Rufo 22. Feb 2015 13:35

AW: Query an Gameserver
 
Bist du dir auch sicher, dass
Delphi-Quellcode:
[$8A, $84]
auch wirklich
Delphi-Quellcode:
$8A84
bedeuten oder evtl. eher
Delphi-Quellcode:
$848A
?

In der Valve-Dokumentation wird ganz eindeutig von All types are little endian gesprochen, was wiederum bedeutet, dass du dir diese Seite anschauen solltest
http://de.wikipedia.org/wiki/Byte-Re...-Endian-Format

und dann bedeutet diese Bytefolge
Delphi-Quellcode:
[$8A, $84]
eben genau
Delphi-Quellcode:
$848A
entspricht was dezimal dann tatsächlich
Delphi-Quellcode:
33930
entspricht. Nur im Speicher sind die Bytes eben in umgekehrter Reihenfolge abgelegt.

Darauf achten musst du nicht, wenn du diese Werte (wie in meinem Beitrag zuvor gezeigt) direkt aus dem Stream liest (lese einfach eine
Delphi-Quellcode:
SmallInt
, bzw.
Delphi-Quellcode:
Int16
)

BadenPower 22. Feb 2015 14:27

AW: Query an Gameserver
 
Zitat:

Zitat von BadenPower (Beitrag 1290960)
Zitat:

Zitat von Flodding (Beitrag 1290958)
Die ID : 8A84 sollte umgewandelt 33930 ergeben. Tut es aber nicht egal in was ich umwandel. HextoStr gibt Kryptisches, HextoInt gibt eine falsche Zahl: 35460.

Das sagt mir, dass Du nie versucht hast 33930 in ein Hex umzuwandeln, denn dann hättest Du gesehen , dass 33930 ToHex-> 848A ist.

Na, fällt Dir etwas auf?


Zitat:

Zitat von Sir Rufo (Beitrag 1290969)
und dann bedeutet diese Bytefolge
Delphi-Quellcode:
[$8A, $84]
eben genau
Delphi-Quellcode:
$848A
entspricht was dezimal dann tatsächlich
Delphi-Quellcode:
33930
entspricht. Nur im Speicher sind die Bytes eben in umgekehrter Reihenfolge abgelegt.

Vielleicht fällt es ihm jetzt auf, wenn er das 2. mal mit der Nase darauf gestoßen wird.

Flodding 22. Feb 2015 18:39

AW: Query an Gameserver
 
Zitat:

Zitat von BadenPower (Beitrag 1290975)
Vielleicht fällt es ihm jetzt auf, wenn er das 2. mal mit der Nase darauf gestoßen wird.

Ja ist es jetzt.
Aber ich muss dazu sagen, dass es kaum möglich ist, diskreter darauf hinzuweisen.

Man schaue sich "8A84" und "848A" nur mal an.
Ich möchte nicht unhöflich klingen, aber man hätte mich einfach direkt drauf hinweisen können OHNE zu warten und sich dann lustig drüber zu machen.
Ich bin sehr dankbar für die Hilfe die mir hier angeboten wird und interpretiere sie auch nicht als lästiges Rumgedruckse oder Ähnliches. Indirekt / eloquent jemanden zu beleidigen ist trotzdem nicht die feine Art und ich bitte dies in Zukunft zu unterlassen. Sicher hätte ich dem preventieren können wenn ich wie der Fuchs aufgepasst hätte. Wir stempeln das als meinen Fehler ab :thumb:

Soviel zum Offtopic!

Delphi kennt TBytes bei mir nicht.
Delphi-Quellcode:
procedure Foo( AResponse : TBytes );
Des Weiteren verstehe ich am Beispiel noch nicht so ganz, wie ich unbekannten Inhalt erkennen soll. Das mit dem Header war ja nun leicht weil er bekannt ist.

BadenPower 22. Feb 2015 19:19

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291007)
Man schaue sich "8A84" und "848A" nur mal an.

Ich ICH ich

Man sieht sofort den Unterschied, da es in der Muttersprache geschrieben steht.

"8A84" und "848A"

Man sieht sofort den Unterschied, wenn man sich mit der Sprache beschäftigt, also hier sich die hexadezimale Schreibweise zu Eigen gemacht hat.

Und diese Schreibweise kommt in der Computerwelt an jeder Stelle um die Ecke.


Zitat:

Zitat von Flodding (Beitrag 1291007)
Man schaue sich "8A84" und "848A" nur mal an.
Ich möchte nicht unhöflich klingen, aber man hätte mich einfach direkt drauf hinweisen können OHNE zu warten und sich dann lustig drüber zu machen.

Das war nicht meine Absicht, zeigt mir aber, wie so oft, dass Antworten leider von den Fragestellern nicht richtig angeschaut werden.

Wir können Dir auch das Programm komplett schreiben, aber wo wäre da der Lerneffekt.

Wenn Du also das nächste mal mit einer Antwort etwas nicht anfangen kannst, dann frage doch nochmals nach, dann sehen wir auch, ob Du es verstanden hast oder nicht.

Flodding 22. Feb 2015 19:47

AW: Query an Gameserver
 
Schnipsel abgeändert:
Delphi-Quellcode:
type
  TBytes = Array of Byte;
  TValveByte = Byte; {8 bit character or unsigned integer}
  TValveShort = SmallInt; {16 bit signed integer}
  TValveLong = Integer; {32 bit signed integer}
  TValveFloat = Single; {32 bit floating point}
  TValveLongLong = Cardinal; {64 bit unsigned integer}

const
  SIMPLE_RESPONSE_HEADER : TValveLong = $FFFFFFFF;
  MULTIPACKET_RESPONSE_HEADER : TValveLong = $FFFFFFFE;

procedure Foo(AResponse : Array of Byte);
var
  LResponseStream : TStream;
  LHeader : TValveLong;
begin
  LResponseStream := TMemoryStream.Create();
  LResponseStream.Write(AResponse, Sizeof(AResponse));
  try
    LResponseStream.Read( LHeader, sizeof(LHeader) ); // Wir lesen den 4-Byte Header
    case LHeader of
      SIMPLE_RESPONSE_HEADER : ShowMessage('Simple Header');  <--- Fehler 1
//        WorkOnSimpleResponse( LResponseStream );  <--- Fehler 2
      MULTIPACKET_RESPONSE_HEADER : ShowMessage('Multi Header');  <--- Fehler 1
//        WorkOnMultiPacketResponse( LResponseStream );  <--- Fehler 2
    else
      raise Exception.CreateFmt( 'Unknown Header Value %8.8x', [LHeader] );
    end;
  finally
    LResponseStream.Free;
  end;
end;
1.) [Pascal Fehler] Unit4.pas(125): E2026 Konstantenausdruck erwartet
2.) Nicht deklarierter Bezeichner 'WorkOnSimpleResponse' / 'WorkOnMultiPacketResponse'

Zitat:

Man sieht sofort den Unterschied, da es in der Muttersprache geschrieben steht.
Entschuldige, dass ich Delphi nicht wie meine Muttersprache beherrsche.

Zitat:

Wir können Dir auch das Programm komplett schreiben, aber wo wäre da der Lerneffekt.
@ BadenPower

War das ein Angebot, wenn ich auf den Lerneffekt verzichte?
Im Ernst jetzt mal... ich weis, dass ihr oft mit Kindern zu tun habt, die einfach nur schnell alles fertig haben wollen und sich nicht für den sogenannten Lerneffekt interessieren.
Ich möchte mir verbieten, dass du mich mit jenen auf eine Stufe stellst, denn ich habe schon in einem der ersten Posts erwähnt, dass ich nichts fertiges möchte.
Andererseits möchte ich auch kein 3 Jahres-Kurs belegen müssen um noch dieses Jahr an mein Ziel zu kommen.
Ich erwarte von niemandem, dass er mir fertigen Code generiert, den ich nur noch CopyPasten muss um dann so zu tun als wenn ich der tollste bin weil es ja irgendwie läuft. Da habe ich doch nicht im Geringsten etwas von, wenn ich einmal etwas ändern muss.
Ich kam hierher in der Hoffnung, dass mir auf einfache Art erklärt wird, was ich tun muss um ein paar Informationen von einem Gameserver zu bekommen. Und ich habe nicht ansatzweise damit gerechnet, auch nur diesen MONAT damit fertig zu werden.
Das ich alleine mit dem WORT "Gameserver" in eine Schublade gesteckt werden würde, war mir schon VOR der Thread-Erstellung klar.

Ich bitte dich nun, dich diesem Thema fernzuhalten, wenn du keine produktiven weiterführenden Informationen zur Verfügung stellen möchtest oder kannst. Ich werde dir nicht Mehr Offtopic antworten :thumb:

MFG

BUG 22. Feb 2015 23:55

AW: Query an Gameserver
 
Zitat:

Zitat von Flodding (Beitrag 1291023)
Entschuldige, dass ich Delphi nicht wie meine Muttersprache beherrsche.

Das ist auch nicht schlimm ... Sprachen und Bibliotheken kommen und gehen. Aber als Entwickler/Programmierer ist man zu einem großem Teil Problemlöser. Deine Fragen deuten darauf hin, dass in deinem Entwickler-Werkzeugkasten noch ein paar wichtige Werkzeuge fehlen. Daher also der ganze "Belehrungskram" :wink:

Zu den Fehlern:
  1. Ich würde mutmaßen, dass deine Delphiversion nicht mit den typisierten Konstanten im Case zurechtkommt. Probiere es mal ohne die Typen oder benutze stattdessen if-then-else-if...
  2. Diese beiden Funktionen bekommen den "Rest" des Streams und sollten von dir selbst geschrieben werden.
Der Code von Sir Rufo ist eben nur ein Beispiel wie man so etwas angehen kann.

Flodding 24. Feb 2015 11:34

AW: Query an Gameserver
 
Ich habe es jetzt gelöst bekommen, dass alles ausgelesen wird, auch wenn noch keine Map geladen ist oder keine Spieler vorhanden sind. Problem war ja dass dann "00" ausgegeben wird und sich das Array dann verschiebt. Sicherlich ist es unschön, aber es funktioniert. Für Verbesserungsvorschläge bin ich gerne offen.

Einziges Problem ist jetzt folgendes:
Der Server startet 4 Mal am Tag neu. um 06:00, 12:00, 18:00 und 00:00 Uhr.
Wenn man zu diesen Zeitpunkten den Query ausführt, hängt sich das Programm auf.

Hier der Code:
Delphi-Quellcode:
procedure TForm4.Button1Click(Sender: TObject);
var
A: TStringList;
udp: TUdpSocket;
x: array[0..25] of byte;
y: array[0..1400] of byte;
i: integer;
buff_delemitted: string;
startbit: integer;
endbitbit: integer;
stringcounter: integer;
begin
memo1.Clear;
udp := TUdpSocket.Create(Self);
udp.RemoteHost:= edit1.Text;
udp.RemotePort:= edit2.Text;
udp.Active:= true;

x[0]:= $FF;
x[1]:= $FF;
x[2]:= $FF;
x[3]:= $FF;
x[4]:= $54;
x[5]:= $53;
x[6]:= $6F;
x[7]:= $75;
x[8]:= $72;
x[9]:= $63;
x[10]:= $65;
x[11]:= $20;
x[12]:= $45;
x[13]:= $6E;
x[14]:= $67;
x[15]:= $69;
x[16]:= $6E;
x[17]:= $65;
x[18]:= $20;
x[19]:= $51;
x[20]:= $75;
x[21]:= $65;
x[22]:= $72;
x[23]:= $79;
x[24]:= $00;

udp.SendBuf(x,sizeof(x));

udp.ReceiveBuf(y,sizeof(y));

udp.Active := false;

for i := 4 to sizeof(y) - 1 do begin

// Header Lesen
  if (i = 3) then
  begin
    if IntToHex(y[0], 2) + IntToHex(y[0], 1) + IntToHex(y[2], 2) + IntToHex(y[3], 2) = 'FFFFFFFF' then
      begin
       buff_delemitted := buff_delemitted + 'FFFFFFFF;';
      end;
    if IntToHex(y[0], 2) + IntToHex(y[0], 1) + IntToHex(y[2], 2) + IntToHex(y[3], 2) = 'FFFFFFFE' then
      begin
       buff_delemitted := buff_delemitted + 'FFFFFFFE;';
      end;
  end
// Antwort
  else
  if (IntToHex(y[i], 2) = '49') then
  begin
    buff_delemitted := buff_delemitted + IntToHex(y[i], 2) + ';'
  end
// Protokoll
  else
  if i = 5 then
  begin
    buff_delemitted := buff_delemitted + IntToHex(y[i], 2) + ';'
  end
// Strings aufteilen nach 00
  else
  if (IntToHex(y[i], 2) = '00') then
  begin
    stringcounter := stringcounter +1;
// Erste 4 Strings aufteilen
    if stringcounter < 5 then buff_delemitted := buff_delemitted + IntToHex(y[i], 2) + ';';
// Game ID Player und Max Player -> 0 Player keine Ausgabe "00" und würde Array verschieben
    if stringcounter = 5 then
    begin
      if IntToHex(y[i+2], 2) = '00' then
      buff_delemitted := buff_delemitted + IntToHex(y[i], 2)
      else
      buff_delemitted := buff_delemitted + IntToHex(y[i], 2) + ';';
    end;
// Restliche Strings werden korrekt getrennt
    if stringcounter > 5 then buff_delemitted := buff_delemitted + IntToHex(y[i], 2) + ';';
  end
  else
  begin
    buff_delemitted := buff_delemitted + IntToHex(y[i], 2)
  end;

  Application.ProcessMessages;
end;

// HEX in Memo anzeigen zur Kontrolle
Memo1.Text := buff_delemitted;

A := TStringList.Create;
try
Split(';', buff_delemitted, A) ;
  server_header        := HexStrToString(a[0]);
  server_protocol      := inttostr(hextoint(a[1]));
  server_protocol      := IntToStr(HexToInt(a[1]));
  server_name          := HexStrToString(a[2]);
  server_map           := HexStrToString(a[3]);
  server_folder        := HexStrToString(a[4]);
  server_game          := HexStrToString(a[5]);
  server_ID            := inttostr(hextoint(a[6][3] + a[6][4] + a[6][1] + a[6][2]));
  server_players       := inttostr(hextoint(a[6][5] + a[6][6]));
  server_max_players   := inttostr(hextoint(a[6][7] + a[6][8]));
  server_bots          := inttostr(hextoint(a[6][9] + a[6][10]));
  server_type          := HexStrToString(a[7][1] + a[7][2]);
  server_environment   := HexStrToString(a[7][3] + a[7][4]);
  server_visibility    := inttostr(hextoint(a[7][5] + a[7][6]));
  server_VAC           := inttostr(hextoint(a[8]));
  server_version       := inttostr(hextoint(a[11][3] + a[6][4] + a[6][1] + a[6][2]));
  server_ExtraDataFlag := '';
  server_EDF_port      := '';
  server_EDF_steamID   := '';
  server_EDF_keywords  := '';
  server_EDF_gameID    := '';

  lblServerHeader.Caption      := server_header;
  lblServerProtocol.Caption    := server_protocol;
  lblServerName.Caption        := server_name;
  lblServerMap.Caption         := server_map;
  lblServerFolder.Caption      := server_folder;
  lblServerGame.Caption        := server_game;
  lblServerID.Caption          := server_id;
  lblServerPlayers.Caption     := server_players;
  lblServerMaxPlayers.Caption  := server_max_players;
  lblServerBots.Caption        := server_bots;
  lblServerType.Caption        := server_type;
  lblServerEnvironment.Caption := server_environment;
  lblServerVisibility.Caption  := server_visibility;
  lblServerVAC.Caption         := server_VAC;
  lblServerVersion.Caption     := server_version;
finally
  A.Free;
end;

end;
Danke nochmal für die Hilfe bisher an alle die geholfen haben.

BadenPower 24. Feb 2015 12:36

AW: Query an Gameserver
 
Prüfe nach
Delphi-Quellcode:
udp.Active:= true;
(besser wäre
Delphi-Quellcode:
udp.Open;
), ob die Verbindung überhaupt hergestellt werden konnte.

Delphi-Quellcode:
udp.Open;

if (udp.Connected) then
 begin
  x[0]:= $FF;
  x[1]:= $FF;
  //...
  udp.SendBuf(x,sizeof(x));

  //...

 end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:40 Uhr.
Seite 4 von 12   « Erste     234 56     Letzte »    

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