Valhalla Legends Forums Archive | Battle.net Bot Development | Problem with Userlist

AuthorMessageTime
ThePro
Hi!
Finally my Bot connects to bnet as Starcraft client. :)
I can chat with other ppl now, everything works, but there is one problem.

When I join a Channel, I get some EID_SHOWUSER (0x1) Messages from bnet, which contains the names of the users, which are in The channel I joined. The problem is, that I only get the first 17 Users. I used a Packet sniffer and counted the 0x1 Packets I received. They are excatly 17 everytime I join a new channel even when there are e.g 28 Users. :( (I checked with Diablo2 in the same channel)

Does anybody have the same problem?
November 22, 2005, 8:33 PM
Myndfyr
I'm sure you're getting more than one packet, or there are multiple packets stuck together.  Post them!
November 22, 2005, 8:42 PM
ThePro
Oh, you were right. :)
I was saving the log of the sniffed data and started to post the packets here, but suddendly I noticed, that there is a 536Byte (!) packet received, after I got the 17th 0x1 MSG. After that I received an another 342Byte packet. It seems I have to write a parse function, which checks if there are more bnet commands in a MSG and parses them or put them together.

Thanks for getting me on the right way man :)


Here is that "Supersize" Packet, which is always sent by bnet after the 17th user. ;)

[code]
43 (18th User) Hide  Hide  536  Recv 
0000  FF 0F 42 00 01 00 00 00 00 00 00 00 5E 00 00 00    ..B.........^...
0010  00 00 00 00 0D F0 AD BA 0D F0 AD BA 6C 5D 54 6F    ............l]To
0020  44 79 5B 6C 00 52 41 54 53 20 30 20 30 20 31 34    Dy[l.RATS 0 0 14
0030  34 35 20 30 20 30 20 30 20 30 20 30 20 52 41 54    45 0 0 0 0 0 RAT
0040  53 00 FF 0F 3F 00 01 00 00 00 00 00 00 00 2F 00    S...?........./.
0050  00 00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 69 67    ..............ig
0060  6F 5B 68 62 5D 00 52 41 54 53 20 30 20 30 20 39    o[hb].RATS 0 0 9
0070  38 20 30 20 30 20 30 20 30 20 30 20 52 41 54 53    8 0 0 0 0 0 RATS
0080  00 FF 0F 41 00 01 00 00 00 00 00 00 00 2F 00 00    ...A........./..
0090  00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 46 6C 61    .............Fla
00A0  54 54 65 52 28 00 52 41 54 53 20 30 20 30 20 38    TTeR(.RATS 0 0 8
00B0  36 33 20 30 20 30 20 30 20 30 20 30 20 52 41 54    63 0 0 0 0 0 RAT
00C0  53 00 FF 0F 46 00 01 00 00 00 00 00 00 00 5E 00    S...F.........^.
00D0  00 00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 53 2D    ..............S-
00E0  6F 2D 61 2D 44 5B 50 75 4E 6B 5D 00 52 41 54 53    o-a-D[PuNk].RATS
00F0  20 30 20 30 20 32 36 38 20 30 20 30 20 30 20 30    0 0 268 0 0 0 0
0100  20 30 20 52 41 54 53 00 FF 0F 43 00 01 00 00 00    0 RATS...C.....
0110  00 00 00 00 5D 00 00 00 00 00 00 00 0D F0 AD BA    ....]...........
0120  0D F0 AD BA 65 58 72 2E 77 61 52 52 69 6F 52 00    ....eXr.waRRioR.
0130  52 41 54 53 20 30 20 30 20 35 37 20 30 20 30 20    RATS 0 0 57 0 0
0140  30 20 30 20 30 20 52 41 54 53 00 FF 0F 47 00 01    0 0 0 RATS...G..
0150  00 00 00 00 00 00 00 4E 00 00 00 00 00 00 00 0D    .......N........
0160  F0 AD BA 0D F0 AD BA 4C 69 54 65 29 42 75 74 74    .......LiTe)Butt
0170  65 72 66 6C 79 00 52 41 54 53 20 30 20 30 20 38    erfly.RATS 0 0 8
0180  32 39 20 30 20 30 20 30 20 30 20 30 20 52 41 54    29 0 0 0 0 0 RAT
0190  53 00 FF 0F 44 00 01 00 00 00 00 00 00 00 5E 00    S...D.........^.
01A0  00 00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 6C 33    ..............l3
01B0  77 44 6C 2D 69 4E 6B 59 2D 00 52 41 54 53 20 30    wDl-iNkY-.RATS 0
01C0  20 30 20 32 37 33 20 30 20 30 20 30 20 30 20 30    0 273 0 0 0 0 0
01D0  20 52 41 54 53 00 FF 0F 4B 00 01 00 00 00 00 00    RATS...K.......
01E0  00 00 6D 00 00 00 00 00 00 00 0D F0 AD BA 0D F0    ..m.............
01F0  AD BA 53 70 41 63 59 2E 4D 68 7A 00 52 41 54 53    ..SpAcY.Mhz.RATS
0200  20 31 32 32 35 20 36 39 39 20 31 31 30 38 20 30    1225 699 1108 0
0210  20 30 20 31 32 32 35 20                            0 1225             
[/code]

November 22, 2005, 9:15 PM
Myndfyr
Don't count on it always being there.  The recv (or if you're using VB, DataReceived) function should specify how long your packet was (how much data was received).  Always check that against the header-specified length to see whether you need to extract more data from the packet.
November 22, 2005, 9:36 PM
ThePro
I use C++ :)
Here is a Codesnippet of my RecvThread which Receives the data:

[code]
DWORD WINAPI RecvThreadFunc(LPVOID param1)
{
char cNachricht[1024];
while(rc!=SOCKET_ERROR)
{
ZeroMemory(cNachricht, 1024);
rc=recv( (SOCKET)param1, cNachricht, 1024,0);
cNachricht[rc]='\0';

//Nachrichten vom Server verarbeiten
switch(cNachricht[1])
{
case SID_CHATEVENT:
memcpy(&ChatEvent, cNachricht, sizeof ChatEvent); //ChatEvent is a STRUCT, where the Data will be stored.

...

}

}

}
return 0;
}
[/code]

I have to compare the size of rc with the size of the header right? So if rc is greater than the header I start a parse loop. :)

I'll do that tomorrow, since I'll go sleep now. :(
November 22, 2005, 9:55 PM
JoeTheOdd
ChatEvent can't be a constant length, because the Username and Text variables will be.. variable length.

Here's how I did it
November 23, 2005, 12:38 AM
Myndfyr
[quote author=Joe link=topic=13325.msg135072#msg135072 date=1132706304]
ChatEvent can't be a constant length, because the Username and Text variables will be.. variable length.

Here's how I did it
[/quote]

If the struct was defined with char* instead of char[], then it would be a constant size.  Sadly, then memcpy wouldn't work unless he managed to only get 4-byte strings!
November 23, 2005, 4:34 AM
ThePro
Hmm, I tried to write a parse function but it seems to be nearly impossible to get a working one. Sometimes the stupid bnet sends Messages with a bigger size than the size which is stored in the header. (63Bytes stored in header, 65Bytes real received data)

Thats why I wrote another function which checks the distance between the first ÿ(0xFF) and the last ÿ(0xFF). That works, but at the end I have to put the rest of the string together with the new string I receive from the battle.net.

Since the header sometimes isn't right and the function only works, if another 0xFF is in the string, I think it's impossible to write a workling parser.

I wonder how Starcraft handle that....
November 24, 2005, 2:51 PM
shout
[quote author=ThePro link=topic=13325.msg135041#msg135041 date=1132694101]
[code]
43 (18th User) Hide Hide 536 Recv
0000 FF 0F 42 00 01 00 00 00 00 00 00 00 5E 00 00 00 ..B.........^...
0010 00 00 00 00 0D F0 AD BA 0D F0 AD BA 6C 5D 54 6F ............l]To
0020 44 79 5B 6C 00 52 41 54 53 20 30 20 30 20 31 34 Dy[l.RATS 0 0 14
0030 34 35 20 30 20 30 20 30 20 30 20 30 20 52 41 54 45 0 0 0 0 0 RAT
0040 53 00
0040      FF 0F 3F 00 01 00 00 00 00 00 00 00 2F 00 S...?........./.
0050 00 00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 69 67 ..............ig
0060 6F 5B 68 62 5D 00 52 41 54 53 20 30 20 30 20 39 o[hb].RATS 0 0 9
0070 38 20 30 20 30 20 30 20 30 20 30 20 52 41 54 53 8 0 0 0 0 0 RATS
0080 00 FF 0F 41 00 01 00 00 00 00 00 00 00 2F 00 00 ...A........./..
0090 00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 46 6C 61 .............Fla
00A0 54 54 65 52 28 00 52 41 54 53 20 30 20 30 20 38 TTeR(.RATS 0 0 8
00B0 36 33 20 30 20 30 20 30 20 30 20 30 20 52 41 54 63 0 0 0 0 0 RAT
00C0 53 00 FF 0F 46 00 01 00 00 00 00 00 00 00 5E 00 S...F.........^.
00D0 00 00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 53 2D ..............S-
00E0 6F 2D 61 2D 44 5B 50 75 4E 6B 5D 00 52 41 54 53 o-a-D[PuNk].RATS
00F0 20 30 20 30 20 32 36 38 20 30 20 30 20 30 20 30 0 0 268 0 0 0 0
0100 20 30 20 52 41 54 53 00 FF 0F 43 00 01 00 00 00 0 RATS...C.....
0110 00 00 00 00 5D 00 00 00 00 00 00 00 0D F0 AD BA ....]...........
0120 0D F0 AD BA 65 58 72 2E 77 61 52 52 69 6F 52 00 ....eXr.waRRioR.
0130 52 41 54 53 20 30 20 30 20 35 37 20 30 20 30 20 RATS 0 0 57 0 0
0140 30 20 30 20 30 20 52 41 54 53 00 FF 0F 47 00 01 0 0 0 RATS...G..
0150 00 00 00 00 00 00 00 4E 00 00 00 00 00 00 00 0D .......N........
0160 F0 AD BA 0D F0 AD BA 4C 69 54 65 29 42 75 74 74 .......LiTe)Butt
0170 65 72 66 6C 79 00 52 41 54 53 20 30 20 30 20 38 erfly.RATS 0 0 8
0180 32 39 20 30 20 30 20 30 20 30 20 30 20 52 41 54 29 0 0 0 0 0 RAT
0190 53 00 FF 0F 44 00 01 00 00 00 00 00 00 00 5E 00 S...D.........^.
01A0 00 00 00 00 00 00 0D F0 AD BA 0D F0 AD BA 6C 33 ..............l3
01B0 77 44 6C 2D 69 4E 6B 59 2D 00 52 41 54 53 20 30 wDl-iNkY-.RATS 0
01C0 20 30 20 32 37 33 20 30 20 30 20 30 20 30 20 30 0 273 0 0 0 0 0
01D0 20 52 41 54 53 00 FF 0F 4B 00 01 00 00 00 00 00 RATS...K.......
01E0 00 00 6D 00 00 00 00 00 00 00 0D F0 AD BA 0D F0 ..m.............
01F0 AD BA 53 70 41 63 59 2E 4D 68 7A 00 52 41 54 53 ..SpAcY.Mhz.RATS
0200 20 31 32 32 35 20 36 39 39 20 31 31 30 38 20 30 1225 699 1108 0
0210 20 30 20 31 32 32 35 20 0 1225
[/code]
[/quote]

I count 66 or 0x42 in the seperated one.
November 24, 2005, 3:02 PM
ThePro
Sure, i could hardcode it. But what if the bnet sends a ping (0x25) between these stuff? Everything will ending up in a chaos. :/
November 24, 2005, 3:20 PM
HdxBmx27
The Packet lengeth is always correct.
The one stored in the header.
If you ever recive more then the packet header tells you, then expect that its multiple packets.
After parsing a packet and whats left dosent start with 0xFF drop it. and wait for more data from the server.

Heres some code I had lieing around. Modifyed for your names.
[code] int iBufLen = rc;  //Set the size of everything int he buffer.
while((int)iBufLen >= 4 && (unsigned char)cNachricht[0] == 0xff){ //See if we have a full header, and its a valid header
char bPacketId = (unsigned char)cNachricht[1];  //Grab the Packet ID
unsigned short uPacketLen = *(unsigned short *)(cNachricht + 2); //Grab the lengeth of the currect packet

switch (bPacketId){} //Parse crap here.

memmove(cNachricht, cNachricht + uPacketLen, iBufLen - uPacketLen); //Move the parsed packet out of the buffer.
iBufLen -= uPacketLen; //Lower the total lengeth fo the buffer
}[/code]

Been a while seince I worked with C++ but it should work.
~-~(HDX)~-~
November 24, 2005, 6:07 PM
ThePro
Thx, i'll try that tomorrow or later. First I'm going to make the bot understand the common SID_ Messages. And add some funny Chatfunctions. like date, time ect. ;)

I'm using memcpy to copy the buffers at the moment. Does memmove be the same?
November 24, 2005, 8:21 PM
Myndfyr
Are you familiar with streams at all?

You should (IMO) try to think of your incoming data like a stream.  Say you have the following sequence of bytes:
[code]
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
[/code]

The idea behind reading this as a stream is that you're dealing with discreet pieces of data within the full byte sequence.  This concept will be very clear if you understand how to use pointers, and in fact, it should be very easy to implement in C.

When you initialize your stream, the pointer or index into your byte array will be 0 (the start of the array).  For example (let's assume you're using C++, but this could be done in C, too):
[code]
class DataStream
{
public:
  DataStream(unsigned char *buffer, int bufferLength);
  ~DataStream();
  BOOL ReadByte(unsigned char&);
  BOOL ReadWord(unsigned short int&);
  BOOL ReadDword(unsigned long int&);
  BOOL ReadQword(unsigned __int64&);
  int GetNTStrLen();
  void ReadNTString(char *outBuf);
  int GetBufferLength();
  int GetCurrentPosition();
  int Seek(int relativePosition);

protected:
  int m_len;
  int m_pos;
  unsigned char* m_data;
}
[/code]
Having an m_pos variable is optional.  It's perfectly legitimate to modify m_data.  I prefer however to use m_pos as a relative offset from m_data.

Now, when you initialize your stream, you'll have something like this:
[code]
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
^  <-- Pointer/index
[/code]

When you call ReadByte():
[code]
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
    ^
[/code]
ReadByte() should have returned 0, GetCurrentPosition() should return 1.
ReadWord(): (after calling ReadByte())
[code]
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
      ^
[/code]
ReadWord() should have returned 0x0201, GetCurrentPosition() should return 3.
ReadDword():
[code]
00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f
                    ^
[/code]
ReadDword() should have returned 0x06050403, GetCurrentPosition should return 7.

The pointer should be dereferenced and incremented according to the size of the data you're reading.  Strings are of course of variable size, which is why you should have GetNTStrLen(): make the user allocate an appropriate string buffer.  The fewer pointers you allocate inside of your class, the fewer you need to clean up inside your class.

An example implementation of ReadDword():
[code]
BOOL DataStream::ReadDword(unsigned long int &result)
{
  BOOL okay = FALSE;
  if (m_pos + 4 < m_len)
  {
    result = *(unsigned int*)(m_data + m_pos);
    okay = TRUE;
  }
  return okay;
}
[/code]

Another potential alternative is to overload the shift operators (like in cin/cout), such that:
[code]
  unsigned long int myVal;
  myVal << myStream;
[/code]
The compiler decides which overloaded function to use based on the compile-time type of the value on the receiving end of the shift operator.  IMO this is cool-looking, but it's not as readable at the end of the day.

I can't say that this code will necessarily help you, but take a look at this.  It's C#, and implements reading a byte array with certain types (ReadDword(), ReadWord(), ReadByte(), ReadNTString(), etc).
November 25, 2005, 1:05 AM
ThePro
Big Thanks, it worked that way. :)))))) Thx!!!
November 29, 2005, 6:30 PM

Search