• Welcome to Valhalla Legends Archive.
 

BNet Chat bot?

Started by Ozzapoo, November 05, 2008, 02:35 AM

Previous topic - Next topic

MyndFyre

#30
Quote from: Ozzapoo on November 12, 2008, 01:31 AM
Arlight....Well I think I got the basics right, but now when I connect it gives me the old product version error -.-
Um... update your game files and verbyte?  :P  Old version != invalid version!  Old version is very specific.

Quote from: Ozzapoo on November 12, 2008, 01:18 AM
QuoteThe data that should be hashed for 'Hashed Key Data' is:
Client Token
Server Token
Key Product (from decoded CD key)
Key Public (from decoded CD key)
(DWORD) 0
Key Private (from decoded CD key)
Then why are there six values to hash?
These are the values that get fed into the hashing algorithm.  The hashing algorithm produces a 20-byte (5 DWORD) value that is inserted into the outgoing data buffer.

If you're using MBNCSUtil, the CdKey.GetHash(clientToken, serverToken) method handles doing all that legwork for you - you just need to provide the client and server tokens.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Ozzapoo

#31
>.< I forgot to do all this stuff...Because I must have thought the GetHash() thing included it >.<

QuoteFor Each Key:
(DWORD) Key Length
(DWORD) CD-key's product value
(DWORD) CD-key's public value
(DWORD) Unknown (0)

But yeah....Then I thought I fixed it but I got Invalid Cd Key instead -.-"
I think it's because I stuffed up again and forgot t include the Unknown value... Well I'm going to try again.

EDIT: I think it's working now! (At least 'CD Key in use' is working...) I'm going to test it a bit more.
EDIT: Yeah, it definitely works. Time to go onto SID_AUTH_ACCOUNTLOGON! :D
EDIT: W00T!!!!!! It's entered chat! =D

EDIT: Uh oh...Problem.

Right now, I have it set up using a System.Net.Sockets.TcpListener object and a NetworkStream object. And it works like this:
Stream.Write(bnetpacket,0,bnetpacket.Length)
Stream.Read(<some variable>,0,<something>)

But in this, it expects a response to everything. However, I'm stuck on how I'm supposed to make my application respond to every packet that Bnet sends me... I'm not sure how I can detect a packet when Bnet sends it and respond to it. Is there something else that I need to do? Please help >.<

MyndFyre

The way that BN# does it is to have a single thread that simply sits on a Read() loop (the thread will block as long as Read() is waiting).  Writes are always done on-demand by another thread.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Ozzapoo

#33
Alright...So will a BackgroundWorker Object do the job?
Aand...I don't quite understand what the 'padding' parameter is in ReadDwordString()..

MyndFyre

Quote from: Ozzapoo on November 12, 2008, 01:16 PM
Alright...So will a BackgroundWorker Object do the job?
Aand...I don't quite understand what the 'padding' parameter is in ReadDwordString()..
BackgroundWorker will work fine.

The Padding parameter is a character to strip out in the event that the value isn't four bytes long.  For example, clan tags are written as integers that might not have four characters.  There was another situation in the protocol, I don't remember where, that used 0x0d as a padding character.

Generally using 0 as the parameter is adequate.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Ozzapoo

Alright I've pretty much got it. Just a small problem now...The background worker doesn't work quick enough to detect all packets when you do something like '/f list'...Which can send up to 26 packets at once.

My current code for the Sub is as follows:
    Sub DetectIncoming()
        Dim rec(bnetClient.ReceiveBufferSize) As Byte
        Dim bnetStream As NetworkStream = bnetClient.GetStream()
        Do
            ReDim rec(bnetClient.ReceiveBufferSize)
            bnetStream.Read(rec, 0, rec.Length)
            If rec(1) = &HF Then
                Dim packetreader As New BncsReader(rec)
                Dim eventid As Int32 = packetreader.ReadInt32()
                Dim userflags As Int32 = packetreader.ReadInt32()
                Dim ping As Int32 = packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                Dim username As String = packetreader.ReadCString()
                Dim text As String = packetreader.ReadCString()
                Select Case eventid
                    Case &H2
                        Console.WriteLine("-INFO- User " + username + " has joined the channel.")
                    Case &H3
                        Console.WriteLine("-INFO- User " + username + " has left the channel.")
                    Case &H4
                        Console.WriteLine("<" + username + "> has whispered: " + text)
                    Case &H5
                        Console.WriteLine("<" + username + "> " + text)
                    Case &H6
                        Console.WriteLine("-BROADCAST- " + text)
                    Case &H7
                        Console.WriteLine("-JOINED CHANNEL- " + text)
                    Case &H9
                        Console.WriteLine("User Flags Update: " + text)
                    Case &HA
                        Console.WriteLine("-WHISPER SENT-")
                    Case &HD
                        Console.WriteLine("Error! Channel Full!")
                    Case &HE
                        Console.WriteLine("Error! Channel does not exist!")
                    Case &HF
                        Console.WriteLine("Error! Channel is restricted!")
                    Case &H12
                        Console.WriteLine("-INFORMATION- " + text)
                    Case &H13
                        Console.WriteLine("Error! " + text)
                    Case &H17
                        Console.WriteLine("-INFO- Emote Used by " + username)
                End Select
            ElseIf rec(1) = &H0 Then
                SendNull(bnetStream)
            End If
        Loop
    End Sub

What should I do to fix it?

Hdx

#36
Why are you not splitting the packets based on length? {Remember the BNCS Header 0xFF ID (word)Length}
The problem you're getting multiple packets at once when you do recv.
Also, switch ftw

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Ozzapoo

Quote from: Hdx on November 13, 2008, 01:38 AM
Why are you not splitting the packets based on length? {Remember the BNCS Header 0xFF ID (word)Length}
The problem you're getting multiple packets at once when you do recv.
Also, switch ftw
Is the length always static?
Any suggestions on how I can fix it :(?
What's "switch"?

Hdx

err its select case in vb
No the length is not always static, hence why its part of the header....
{AE read the 1st byte if its not oxff its not a real bncs packet, read the next one, thats the id, read the next two, thats the length, read the next X where X was the previous word}

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Ozzapoo

#39
Wait, are you saying I should only use the stream to read the first 4 bytes (the header) and then read however much is left? Will it reduce the amount of time needed, as right now it's the ReceivedBufferSize property or something and there are LOTS of null bytes in the output.

QuoteThe problem you're getting multiple packets at once when you do recv.
Wait...You mean if I read too much at a time I might read two packets at once?

EDIT: Had a go at making some changes...But it still screws up and now I have no idea what's wrong.

    Sub DetectIncoming()
        Dim rec1() As Byte
        Dim rec(bnetClient.ReceiveBufferSize) As Byte
        Dim header(3) As Byte
        Dim bnetStream As NetworkStream = bnetClient.GetStream()
        Do

            ReDim header(3)
            Dim packetsize As Integer
            bnetStream.Read(header, 0, 4)
            If header(0) = &HFF Then

                packetsize = BitConverter.ToInt16(header, 2)

            Else
                Continue Do
            End If
            ReDim rec1(packetsize - 4) 'Error: Arithmetic operation resulted in an overflow. <----------------------------ERROR!!
            bnetStream.Read(rec1, 0, rec1.Length)
            ReDim rec(packetsize)
            rec = ConcatenateByteArray(header, rec1)

            If rec(1) = &HF Then
                Dim packetreader As New BncsReader(rec)
                Dim eventid As Int32 = packetreader.ReadInt32()
                Dim userflags As Int32 = packetreader.ReadInt32()
                Dim ping As Int32 = packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                Dim username As String = packetreader.ReadCString()
                Dim text As String = packetreader.ReadCString()
                Select Case eventid
                    Case &H2
                        Console.WriteLine("-INFO- User " + username + " has joined the channel.")
                    Case &H3
                        Console.WriteLine("-INFO- User " + username + " has left the channel.")
                    Case &H4
                        Console.WriteLine("<" + username + "> has whispered: " + text)
                    Case &H5
                        Console.WriteLine("<" + username + "> " + text)
                    Case &H6
                        Console.WriteLine("-BROADCAST- " + text)
                    Case &H7
                        Console.WriteLine("-JOINED CHANNEL- " + text)
                    Case &H9
                        Console.WriteLine("User Flags Update: " + text)
                    Case &HA
                        Console.WriteLine("-WHISPER SENT-")
                    Case &HD
                        Console.WriteLine("Error! Channel Full!")
                    Case &HE
                        Console.WriteLine("Error! Channel does not exist!")
                    Case &HF
                        Console.WriteLine("Error! Channel is restricted!")
                    Case &H12
                        Console.WriteLine("-INFORMATION- " + text)
                    Case &H13
                        Console.WriteLine("Error! " + text)
                    Case &H17
                        Console.WriteLine("-INFO- Emote Used by " + username)
                End Select
            ElseIf rec(1) = &H0 Then
                SendNull(bnetStream)
            End If
        Loop
    End Sub

I made it:
1. Only read the first 4 bytes.
2. If the first byte is no &HFF, then skip the rest of the actions in the loop and go from the start. If it IS &HFF, then it will use BitConverter to get the header size.
3. It will ReDim the 'rec1' array to be PacketSize - 4.
4. It will receive the rest of the packet data.
5. It will concatenate the header and 'rec1', so it should become an entire packet, into 'rec'.
6. It will continue to do the rest, as it did before.

Pretty much, if what Hdx said is true, I should have eliminated those problems, but almost every time I try to do '/f list', I get an error saying 'Arithmetic operation resulted in an overflow.' at around the sixth packet (Refer to the comment in the code). And even when I don't (rarely), it starts off displaying the messages  in order, but then it just skips and finishes..... Any help?

The 'packetsize' variable is 0 when the error occurs, which leads me to believe that it isn't set, maybe because the packet header isn't 'read' properly...

EDIT:     Sub DetectIncoming()
        Dim rec1() As Byte
        Dim rec(bnetClient.ReceiveBufferSize) As Byte
        Dim header(3) As Byte
        Dim bnetStream As NetworkStream = bnetClient.GetStream()
        Do

            ReDim header(3)
            Dim packetsize As Integer
            Dim startbyte As Byte = bnetStream.ReadByte()
            Dim header2(2) As Byte
            If startbyte = &HFF Then
                bnetStream.Read(header2, 0, 3)
                header(0) = startbyte
                header(1) = header2(0)
                header(2) = header2(1)
                header(3) = header2(2)
                packetsize = BitConverter.ToInt16(header, 2)

            Else
                Continue Do
            End If
            ReDim rec1(packetsize - 4)
            bnetStream.Read(rec1, 0, rec1.Length)
            ReDim rec(packetsize)
            rec = ConcatenateByteArray(header, rec1)

            If rec(1) = &HF Then
                Dim packetreader As New BncsReader(rec)
                Dim eventid As Int32 = packetreader.ReadInt32()
                Dim userflags As Int32 = packetreader.ReadInt32()
                Dim ping As Int32 = packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                packetreader.ReadInt32()
                Dim username As String = packetreader.ReadCString()
                Dim text As String = packetreader.ReadCString()
                Select Case eventid
                    Case &H2
                        Console.WriteLine("-INFO- User " + username + " has joined the channel.")
                    Case &H3
                        Console.WriteLine("-INFO- User " + username + " has left the channel.")
                    Case &H4
                        Console.WriteLine("<" + username + "> has whispered: " + text)
                    Case &H5
                        Console.WriteLine("<" + username + "> " + text)
                    Case &H6
                        Console.WriteLine("-BROADCAST- " + text)
                    Case &H7
                        Console.WriteLine("-JOINED CHANNEL- " + text)
                    Case &H9
                        Console.WriteLine("User Flags Update: " + text)
                    Case &HA
                        Console.WriteLine("-WHISPER SENT-")
                    Case &HD
                        Console.WriteLine("Error! Channel Full!")
                    Case &HE
                        Console.WriteLine("Error! Channel does not exist!")
                    Case &HF
                        Console.WriteLine("Error! Channel is restricted!")
                    Case &H12
                        Console.WriteLine("-INFORMATION- " + text)
                    Case &H13
                        Console.WriteLine("Error! " + text)
                    Case &H17
                        Console.WriteLine("-INFO- Emote Used by " + username)
                End Select
            ElseIf rec(1) = &H0 Then
                SendNull(bnetStream)
            End If
        Loop
    End Sub

That has the error too, except now the 'packetsize' value is -1.

EDIT: Just added 'If packetsize < 1 Then Continue Do'.....But it still skips some packets. All that and I didn't get anywhere in the end -.-

EDIT: OK WTF. I made it say 'w00t' whenever it ran the IF that checked for &HFF and I found some revealing stuff .. -.-"
Quote
-JOINED CHANNEL- The Void
w00t
/f l
w00t
-INFORMATION- Your friends are:
w00t
-INFORMATION- 1: lfuzzyl, offline
w00t
-INFORMATION- 2: rts178, offline
w00t
-INFORMATION- 3: shamanno1, offline
w00t
-INFORMATION- 4: ace)of(clubs, offline
w00t
w00t
-INFORMATION- 6: water_knight, offline
w00t
w00t
-INFORMATION- 8: computer(hairy), offline
w00t
w00t
-INFORMATION- 10: carnifox, offline
w00t
w00t
-INFORMATION- 12: lordkintaro, using Warcraft III The Frozen Throne in a private
channel.
w00t
w00t
-INFORMATION- 14: caesio, offline
w00t
w00t
-INFORMATION- 16: tonton.vfr[1], offline
w00t
w00t
-INFORMATION- 18: tonton.vfr[3], offline
w00t
w00t
-INFORMATION- 20: tonton.vfr[5], offline
w00t
w00t
-INFORMATION- 22: FlipCirca, offline
w00t
w00t
-INFORMATION- 24: TonTonSNORT, offline
Anyone have any ideas? =X
Bedtime for me now =D

MyndFyre

My listen loop follows the principle the others have discussed.  Here's some adapted code that more pseudocode-ish:


                while (IsConnected)
                {
                    // I wrote Receive().  It guarantees a buffer filled with as many bytes as you request and blocks until it comes in,
                    // or else returns null.
                    byte[] hdr = Receive(header, 0, 4);
                    if (hdr == null) return; // disconnected.
                    byte[] result = null;
                    ushort length = BitConverter.ToUInt16(hdr, 2);
                    if (length > 4)
                    {
                        byte[] data = AllocateIncomingBuffer(length);
                        result = Receive(data, 0, unchecked((ushort)(length - 4)));
                        if (result == null) return; // disconnected.
                        length = unchecked((ushort)(length - 4));
                    }
                    else if (length == 4)
                    {
                        // no data to parse; length is just for header.
                        length = unchecked((ushort)(length - 4));
                        result = new byte[0];
                    }
                    else
                    {
                        throw new ProtocolViolationException(Strings.InvalidPacketSizeFromBnet);
                    }
                    ParseData parseData = new ParseData(hdr[1], length, result);
                    Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID);
                    ParsePacket(priority, parseData);
                }


QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

Hdx

Two things:

                        // no data to parse; length is just for header.
                        length = unchecked((ushort)(length - 4));
                        result = new byte[0];

                        // no data to parse; length is just for header.
                        length = 0;
                        result = null;
Neh?
And Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID); I'd like to see your DeterminePriority() function. {Just curious}

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

Ozzapoo

Quote from: MyndFyre[vL] on November 13, 2008, 10:36 AM
My listen loop follows the principle the others have discussed.  Here's some adapted code that more pseudocode-ish:


                while (IsConnected)
                {
                    // I wrote Receive().  It guarantees a buffer filled with as many bytes as you request and blocks until it comes in,
                    // or else returns null.
                    byte[] hdr = Receive(header, 0, 4);
                    if (hdr == null) return; // disconnected.
                    byte[] result = null;
                    ushort length = BitConverter.ToUInt16(hdr, 2);
                    if (length > 4)
                    {
                        byte[] data = AllocateIncomingBuffer(length);
                        result = Receive(data, 0, unchecked((ushort)(length - 4)));
                        if (result == null) return; // disconnected.
                        length = unchecked((ushort)(length - 4));
                    }
                    else if (length == 4)
                    {
                        // no data to parse; length is just for header.
                        length = unchecked((ushort)(length - 4));
                        result = new byte[0];
                    }
                    else
                    {
                        throw new ProtocolViolationException(Strings.InvalidPacketSizeFromBnet);
                    }
                    ParseData parseData = new ParseData(hdr[1], length, result);
                    Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID);
                    ParsePacket(priority, parseData);
                }



I still don't really get it...(partially because of some of the functions used)
Could you please explain what the your code does?

Hdx

               while (IsConnected)
                {
                    byte[] hdr = Receive(header, 0, 4); //Reterives 4 bytes from the socket, garentees it's 4 bytes or null
                    if (hdr == null) return; // The socket was closed
                    byte[] result = null; //var for the actuall data
                    ushort length = BitConverter.ToUInt16(hdr, 2); //Gets the length of the packet from the header {hdr[2] | hdr[3] << 8}
                    if (length > 4){ //If it actually has data
                        byte[] data = AllocateIncomingBuffer(length); //Allocates 'length' amount of bytes for the data
                        result = Receive(data, 0, unchecked((ushort)(length - 4))); //Reads length - 4 bytes from the socket
                        if (result == null) return; // read failed, socket closed
                        length = unchecked((ushort)(length - 4)); //Data length = length - 4 {length - size of header}
                    }else if (length == 4){ // packet contains only header {AE: SID_NULL}
                        length = unchecked((ushort)(length - 4)); //length = 0
                        result = new byte[0]; //No data
                    }else{
                        throw new ProtocolViolationException(Strings.InvalidPacketSizeFromBnet); //OMFG THIS SHOULDNT HAPPEN DONT HAX ME!
                    }
                    ParseData parseData = new ParseData(hdr[1], length, result); //Creates a new Incoming packet buffer using the data from above.
                    Priority priority = DeterminePriority((BncsPacketId)parseData.PacketID); //Gets the priority {So the bot knows which packets to handle first, you don't need to do this}
                    ParsePacket(priority, parseData); //Passes it off to the handeling sub
                }


The main thing you need to do is this:
               while (IsConnected)
                {
                    byte[] hdr = Receive(header, 0, 4); //receive 4 bytes
                    if (hdr == null) return; // disconnected.
                    byte[] data = null;
                    ushort length = hdr[2] | hdr[3] << 8;
                    if (length > 4){
                        data = Receive(data, 0, length - 4); //Read length - 4 bytes {The body of the packet}
                        if (data == null) return; // disconnected.
                    }
                    ParsePacket(hdr[1], data, length);
                }

An extreamly striped down version that should work {well, its psudo code cuz i havent tested but the base ideas are there}

Proud host of the JBLS server www.JBLS.org.
JBLS.org Status:
JBLS/BNLS Server Status

MyndFyre

Note that the synax hdr[2] | hdr[3] << 8 might not work in C# or Visual Basic (it would require expansion from byte to a larger data type to do the shift, plus it's just not really clear in the intent: you need to specifically look up operator precedence to be sure that shift operator takes precedence over the bitwise or | operator).  Use BitConverter.ToInt16 or BitConverter.ToUInt16 as I did - it's built-in to the system.
QuoteEvery generation of humans believed it had all the answers it needed, except for a few mysteries they assumed would be solved at any moment. And they all believed their ancestors were simplistic and deluded. What are the odds that you are the first generation of humans who will understand reality?

After 3 years, it's on the horizon.  The new JinxBot, and BN#, the managed Battle.net Client library.

Quote from: chyea on January 16, 2009, 05:05 PM
You've just located global warming.

|