Avatar billede compilos Nybegynder
31. maj 2001 - 19:46 Der er 11 kommentarer og
1 løsning

\'Gamespy\'

Jeg har tænkt mig at lave et lille program der finder oplysninger på nogle CounterStrike server. Men i første omgang vil jeg bare \'pinge\' serveren - den skulle så resultere et \"j\". men jeg kan ikke finde ud af at få sendt en streng afsted - Jeg vedligger SDK´et fra HL.

Game servers will answer the following messages:
Messages are sent to the server by sending 4 consecutive bytes of 255 (32-bit integer -1)
and then the string command followed by a zero byte to terminate it

\"ping\"
    Server responds with a single byte code ASCII \'j\'

\"info\"
    Server responds with the following packet:
    (int32)        -1
    (byte)        ASCII \'C\' (info response, S2A_INFO)
    (string)        net address of server
    (string)        name of the host / server
    (string)        name of the map
    (string)        game directory (i.e. valve/)
    (string)        Game description (e.g. \"half-life multiplay\")
    (byte)        active client count
    (byte)        maximum clients allowed
    (byte)        protocol version (currently 7)

\"players\"
    Server responds with the following packet:
    (int32)        -1
    (byte)        ASCII \'D\' (players response, S2A_PLAYER)
    (byte)        active client count

    for each active client
        (byte)        client number / index
        (string)        player name
        (int32)        client\'s frag total
        (float32)        client\'s total time in-game

\"rules\"
    Server responds with the following packet:
    (int32)        -1
    (byte)        ASCII \'E\' (rules response, S2A_RULES)
    (int16)        number of rules

    for each rule
        (string)        rule name
        (string)        rule value


-------------------

Master server query protocol:

Sent to master:

(byte)    ASCII \'c\' ( A2M_GET_SERVERS )

Response from master:

(int32)  -1
(byte)  ASCII \'d\' ( M2A_SERVERS )
(byte)  unused

// This is followed by as many 6 byte ip addresses as will fit in the message. 
The master currently feeds about 2K worth of IP address ( 300+ or so ),
but we may up that # significantly in the near future.

(4 x byte) ip address
(int16)  port #



The old protocol is still valid, but there is a new, extended protocol:

Here are both the old and new protocols ( the new one is the \"details\" message ):

\"info\"
    Server responds with the following packet:
    (int32)        -1
    (byte)        ASCII \'C\' (info response, S2A_INFO)
    (string)        net address of server
    (string)        name of the host / server
    (string)        name of the map
    (string)        game directory (i.e. valve/)
    (string)        Game description (e.g. \"half-life multiplay\")
    (byte)        active client count
    (byte)        maximum clients allowed
    (byte)        protocol version (currently 37)

\"details\"
    (int32)            -1
    (byte)        ASCII \'m\' ( S2A_INFO_DETAILED )
    (string)        net address of server
    (string)        name of the host / server
    (string)        name of the map
    (string)        game directory (i.e. valve/)
    (string)        Game description (e.g. \"half-life multiplay\")
    (byte)        active client count
    (byte)        maximum clients allowed
    (byte)        protocol version (currently 37)
    (byte)        type of server == \'l\' for listen or \'d\' for dedicated
    (byte)        os of server == \'w\' for win32 or \'l\' for linux
    (byte)        password on server == 1 or yes, 0, for no
    (byte)        is server running a mod? == 1 for yes, 0 for no

    IFF the server is running mod byte was 1:

    (string)        URL for mod\'s \"info\" website
    (string)        URL for mod\'s download ftp server
    (int32)        mod version #
    (int32)        mod download size ( in bytes, approx. )
    (byte)        is the mod a server side only mod?  1 == yes, 0 == no
    (byte)        does this server require you to have a custom client side .dll ( client.dll )?  1 == yes, 0 == no.




Here is some code that uses the new protocol. 
The first function starts the protocol and the second services the message and requests more ip addresses:

/*
==================
Host_GetBatchServerList_f

  Request full server list from HL master server.
==================
*/
void Host_GetBatchServerList_f( void )
{
    unsigned char c[10];
    adrlist_t *p;
    int i = 0;

    // Request a server list from the master servers.
    NET_Config( true ); // Initialize networking

    if ( gfNoMasterServer )
        return;

    if ( !valvemaster_adr )
        return;

    c[0] = A2M_GET_SERVERS_BATCH;  // ascii \'e\'
    i++;

    *(int *)&c[1] = 0; // Request first batch.
    i += sizeof( int );

    p = valvemaster_adr;

    while ( p )
    {
        // send to valve master
        Con_Printf (\"Requesting batch server list from %s\\n\", NET_AdrToString ( p->adr) );
        NET_SendPacket (NS_CLIENT, i, c, p->adr );
        p = p->next;
    }
}

// Upon receiving ( 5 bytes, 4 for the -1 and 1 byte for the \'f\' character ):
int32  -1
M2A_SERVER_BATCH              // Ascii \'f\', the response to the above

void CL_ParseBatchServerList( void )
{
    char szAddress[128] = \"\";
    unsigned char cIP[4];
    int i;
    unsigned short iIPPort;
    int nNumAddresses;
    int count = 1;
    int unique = 0;

    MSG_ReadByte(); // Skip \\r

    unique = MSG_ReadLong();

    // So far we have read 6 chars.  Remainder of message length is iBytesRead - 6
    nNumAddresses = net_message.cursize - sizeof(int) - sizeof(unsigned char) - sizeof(byte);
   
    // Each address is 6 bytes long
    //
    nNumAddresses /= 6;

    while (nNumAddresses-- > 0)
    {
        memset(szAddress, 0, 128);

        for (i = 0; i < 4; i++)
            cIP[i] = MSG_ReadByte();

        sprintf( szAddress, \"%i.%i.%i.%i\"
            , (int)cIP[0]
            , (int)cIP[1]
            , (int)cIP[2]
            , (int)cIP[3]
        );

        iIPPort = BigShort((unsigned short)MSG_ReadShort());
       
        //if ( count <= 100 )
        //    Con_Printf( \"%4i:  %s:%i\\n\", count, szAddress, iIPPort );
       
        count++;
    }

    Con_Printf( \"%i servers\\n\", count );

    if ( unique != 0 ) // More servers left, send another request to master
    {
        unsigned char c[10];
        int i = 0;

        // Request a server list from the master servers.
        NET_Config( true ); // Initialize networking

        c[0] = A2M_GET_SERVERS_BATCH;
        i++;

        *(int *)&c[1] = unique; // Request servers starting after this unique id.
        i += sizeof( int );

        // send to valve master
        Con_DPrintf (\"Requesting next batch ( %i ) server list from %s\\n\", unique, NET_AdrToString ( net_from ) );
        NET_SendPacket (NS_CLIENT, i, c, net_from );
    }
    else
        Con_Printf( \"Done.\\n\" );
}

Avatar billede dj Nybegynder
31. maj 2001 - 19:55 #1
Du skal sende beskeden via en UDP Client da CS serveren benytter UDP protokollen.
Du kan finde en god UDP komponent i INDY pakken http://www.nevrona.com/indy

Derefter skal du bare sende strengen som: chr(255)+chr(255)+chr(255)+chr(255)+\'details\'+chr(0)
Så får du detaljer om serveren sendt tilbage.

Det kan hjælpe dig lige og kigge på det UDP Client/server eksempel der følger med INDY.

Ellers så bare spørg, jeg har selv lavet et lign. projekt nemlig, så kender efterhånden en del til hvordan det fungerer :)

mvh. _DJ_
Avatar billede dj Nybegynder
31. maj 2001 - 19:57 #2
Btw. drop at glo alt for meget på den halfLife SDK .. den er beregnet på MOD programmører, og gør dig sikkert bare mere forvirret end den gavner, for det er slet ikke så svært at kommunikere med serveren.
Avatar billede dj Nybegynder
31. maj 2001 - 19:58 #3
Her er et lille Delphi eksempel der anvender INDY komponenterne:

----------------------

unit UDPClientMain;

interface

uses
  {$IFDEF Linux}
  QGraphics, QControls, QForms, QDialogs, QStdCtrls,
  {$ELSE}
  Windows, Messages, Graphics, Controls, Forms, Dialogs, IdWinsock, StdCtrls,
  {$ENDIF}
  SysUtils, Classes, IdBaseComponent, IdAntiFreezeBase, IdAntiFreeze,
  IdComponent, IdUDPBase, IdUDPClient, IdStack;

type
  TUDPMainForm = class(TForm)
    SourceGroupBox: TGroupBox;
    HostNameLabel: TLabel;
    HostAddressLabel: TLabel;
    HostName: TLabel;
    HostAddress: TLabel;
    UDPAntiFreeze: TIdAntiFreeze;
    PortLabel: TLabel;
    Port: TLabel;
    DestinationLabel: TLabel;
    DestinationAddress: TLabel;
    BufferSizeLabel: TLabel;
    BufferSize: TLabel;
    UDPMemo: TMemo;
    SendButton: TButton;
    UDPClient: TIdUDPClient;
    procedure FormCreate(Sender: TObject);
    procedure SendButtonClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  UDPMainForm: TUDPMainForm;

implementation

const
  HOSTNAMELENGTH = 80;
  RECIEVETIMEOUT = 10000; // milliseconds

{$IFDEF Linux}{$R *.xfm}{$ELSE}{$R *.DFM}{$ENDIF}

procedure TUDPMainForm.FormCreate(Sender: TObject);
begin
  HostName.Caption := UDPClient.LocalName;
  HostAddress.Caption := GStack.LocalAddress;
  Port.Caption := IntToStr(UDPClient.Port);
  DestinationAddress.Caption := UDPClient.Host;
  BufferSize.Caption := IntToStr(UDPClient.BufferSize);
  UDPClient.ReceiveTimeout := RECIEVETIMEOUT;
end;

procedure TUDPMainForm.SendButtonClick(Sender: TObject);
var
  MessageID: Integer;
  ThisMessage: String;
  ReceivedString: String;
begin
  MessageID := Random(MAXINT);
  ThisMessage := chr(255) + chr(255) + chr(255) + chr(255) + \'challenge rcon\'+ chr(0);
  UDPMemo.Lines.Add(\'Sending \' + ThisMessage);
  UDPClient.Send(ThisMessage);
  ReceivedString := UDPClient.ReceiveString();
  if ReceivedString = \'\' then
    UDPMemo.Lines.Add(\'No response received from the server after \' + IntToStr(UDPClient.ReceiveTimeout) + \' millseconds.\')
  else
    UDPMemo.Lines.Add(\'Received: \' + ReceivedString)
end;

end.
Avatar billede dj Nybegynder
02. juni 2001 - 00:26 #4
uhm.. er du der ?
Avatar billede compilos Nybegynder
02. juni 2001 - 16:29 #5
Ja ja - det var strengen jeg ikke kunne finde ud af: ThisMessage := chr(255) + chr(255) + chr(255) + chr(255) + \'challenge rcon\'+ chr(0);

Men jeg godkender ikke endnu - der kommer nok lidt mere !! Ha´ tålmodighed :)
Avatar billede dj Nybegynder
02. juni 2001 - 19:32 #6
ok :)
Avatar billede compilos Nybegynder
09. juni 2001 - 12:55 #7
Er tilbage igen DJ.
Når jeg nu modtager en Streng, så er den 6 værdi antal spiller der er logget på serveren.Det skulle være en byte, men for mig vises den som en firkant - Jeg kan sgu ikke finde ud af at konverter den til et tal - hvordan gør jeg det.

Avatar billede dj Nybegynder
09. juni 2001 - 18:02 #8
uhm.. må nok indrømme at jeg ikke lige er klar over det, har ikke selv haft brug for det.
(det har ikke været en gamespy jeg har lavet :)
Avatar billede compilos Nybegynder
09. juni 2001 - 18:18 #9
OK dj, Det er iorden.
Nu får du sgu´ pointene -lidt billig. Men oK
Jeg takker for hjælpen
Avatar billede cms Nybegynder
22. juni 2001 - 11:05 #10
var streng: string;
var tal: byte; //eller integer, eller cardinal, eller ethvilketsomhelst tal...
begin
  tal := ord(streng[6]); //returnerer tallet (byte\'n) på strengens 6. plads
end;

-cms
Avatar billede compilos Nybegynder
22. juni 2001 - 11:28 #11
Hej CMS. Det er pænt af dig men jeg har fundet ud af det.

Ellers TAK
Avatar billede cms Nybegynder
22. juni 2001 - 18:19 #12
o.k. :-) håbede jeg også *gg*
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester