And I'm falling at the first hurdle.
My code:
[code]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace Minerbot
{
class Program
{
static void Main(string[] args)
{
TcpClient connection = new TcpClient("127.0.0.1", 27015);
NetworkStream stream = connection.GetStream();
stream.Flush();
// Player information
byte PacketID = 0x00;
byte ProtocolVersion = 0x07;
string Username = "NAME"; // Cut this out so you don't steal my bot's account >:(
string VerificationKey = "PASSWORD"; // Same as above
byte unused = 0x00; // So it's not needed... shoot me
// Fill up some byte arrays containing username and verification key
byte[] bUsername = new byte[64];
for (int i = 0; i < Username.Length; i++)
{
bUsername[i] = Encoding.ASCII.GetBytes(Username)[i];
}
for (int i = Username.Length; i < 64; i++)
{
bUsername[i] = 0x20;
}
byte[] bVerKey = new byte[64];
for (int i = 0; i < VerificationKey.Length; i++)
{
bVerKey[i] = Encoding.ASCII.GetBytes(VerificationKey)[i];
}
for (int i = VerificationKey.Length; i < 64; i++)
{
bVerKey[i] = 0x20;
}
// Put it all into one line
string sData = String.Format("{0}{1}{2}{3}{4}\n", PacketID, ProtocolVersion, Username, VerificationKey, unused);
// Write it into a byte array
byte[] buffer = Encoding.ASCII.GetBytes(sData);
// Send it to the server
stream.Write(buffer, 0, buffer.Length);
// Wait a bit
while (true)
{
}
}
}
}[/code]
The protocol can be found here:
[url]http://www.minecraftwiki.net/wiki/Development_Resources#Packet_Protocol[/url]
I'm using the first Client -> Server packet; the player identification.
The server recognises the connection, but doesn't seem give a name to the "player".
Anyone see the problem?
It uses a binary protocol, while you're sending everything put together as text followed by a newline.
The length of each type is specified at the top of the Packet Protocol section, their order is defined below.
Did you even read it? Anyways, right now you are just sending 1 giant string. I recommend looking into BinaryWriter.
Edit:
Ninjad!
I'm putting the string into a byte array, after converting each character to a hex digit.
[editline]Edited:[/editline]
Those for loops are filling the rest of the 64 long byte array with 0x20 spaces
[QUOTE=Chris220;21350678]I'm putting the string into a byte array, after converting each character to a hex digit.
[editline]Edited:[/editline]
Those for loops are filling the rest of the 64 long byte array with 0x20 spaces[/QUOTE]
Yet then still you're still throwing it as a string :D.
[editline]Edited:[/editline]
I think :(
[code]// Put it all into one line
string sData = String.Format("{0}{1}{2}{3}{4}\n", PacketID, ProtocolVersion, Username, VerificationKey, unused);
// Write it into a byte array
byte[] buffer = Encoding.ASCII.GetBytes(sData);
// Send it to the server
stream.Write(buffer, 0, buffer.Length);[/code]
I'm writing the byte array to the NetworkStream. That's what I did for my IRC client and bot, so shouldn't it work similar/the same with this?
[QUOTE=Chris220;21350678]I'm putting the string into a byte array, after converting each character to a hex digit.
[editline]Edited:[/editline]
Those for loops are filling the rest of the 64 long byte array with 0x20 spaces[/QUOTE]
I skipped over that code since it's dead code, it doesn't have any side effects. You're not actually doing anything with bUsername.
Now that I look at it though, you still have the wrong idea. Completely. I'm not sure what more to say because I'm not even sure what parts of this code you wrote yourself and what parts you've just copy-pasted around to make things do something. Either way, the only thing your program actually does is write the text "07NAMEPASSWORD0[LF]" to the socket stream.
[QUOTE=Chris220;21350784][code]// Put it all into one line
string sData = String.Format("{0}{1}{2}{3}{4}\n", PacketID, ProtocolVersion, Username, VerificationKey, unused);
// Write it into a byte array
byte[] buffer = Encoding.ASCII.GetBytes(sData);
// Send it to the server
stream.Write(buffer, 0, buffer.Length);[/code]
I'm writing the byte array to the NetworkStream. That's what I did for my IRC client and bot, so shouldn't it work similar/the same with this?[/QUOTE]
IRC is a text based protocol using CRLF (carriage-return, line-feed) as the message separator. This protocol is binary and the only information that will appear as ASCII encoded text is actual text - called "String" in the format described at the link you provided (with a static, and thus maximum, size of 64 bytes - which means 64 characters with the ASCII encoding).
0x00, 0x07 and so on should not be converted to '0' and '7' (characters), but rather stay that way in binary (whatever their character representation might be).
String.Format however does convert those numbers into the corresponsing characters, while instead you actually want to put them into the buffer (without conversion), like buffer[0] = PacketID; and buffer[1] = ProtocolVersion;.
Urgh, ok. I thought this was manageable for me...
From what you're all saying, I should just give up. Obviously this is far above my ability.
never give up
[QUOTE=Chris220;21353286]Urgh, ok. I thought this was manageable for me...
From what you're all saying, I should just give up. Obviously this is far above my ability.[/QUOTE]
It's not what I'm saying, I just don't know how to really help you as I don't know how much you understand. Maybe start by seeing how bUsername isn't actually used, understand how that snippet of code isn't doing anything. Then you should rewrite the packet writer using a helpful stream wrapper like BinaryWriter. But even then some manual labour is required because all integers are expected to be in network order, which your machine most likely isn't natively (which means you need to switch endianness; I think the BitConverter class can help unless BinaryWriter has functionality for it).
Ok, sorry. I was feeling a bit irritable earlier; but I've had a nice warm bath and I'm feeling much better :)
I will take a look at both BinaryWriter, and BitConverter.
I THINK I understand why converting the string into its bytes isn't doing anything, is it because that's all a string is, essentially. It's just displayed as characters for easy reading?
Name field must be padded to 64bytes, auth token to 32.
How'd you work that one out?
They're both "String", which is "US-ASCII/ISO646-US encoded string padded with spaces (0x20) ; Size: 64 bytes"
Please explain
I had a crack and writing it using a binary stream, the server says that the name cannot be verified (it's correct just omitted from the source). Here's the code: [I]I'm a c# newb so maybe you can see where I'm going wrong[/I]
[code]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
namespace MinecraftBot
{
class Program
{
static void Main()
{
Program self = new Program();
TcpClient Client = new TcpClient("localhost", 25565);
NetworkStream NStream = Client.GetStream();
NStream.Flush();
//Player Info
byte PacketID = 0x00;
byte ProtocalVersion = 0x07;
string Username = self.PadString("name", 64);
string Password = self.PadString("password", 64);
byte Unused = 0x00;
BinaryWriter BWrite = new BinaryWriter(NStream);
BWrite.Write(PacketID);
BWrite.Write(ProtocalVersion);
BWrite.Write(Username);
BWrite.Write(Password);
BWrite.Write(Unused);
while (true) { };
}
string PadString(String str, int Length)
{
String PaddedString = str;
PaddedString = PaddedString.PadRight(64, ' ');
return PaddedString;
}
}
}
[/code]
[b]Edit:[/b]
Fixed by turning verify-names to false.
[QUOTE=Chris220;21354134]
I THINK I understand why converting the string into its bytes isn't doing anything, is it because that's all a string is, essentially. It's just displayed as characters for easy reading?[/QUOTE]
Exactly. When the protocol documentation says it expects ASCII encoding, that means you should format your string according to [url=http://www.asciitable.com/]this[/url] schematic. C# string literals are UTF-8 (I think it can also use UTF-16 if your string contains characters requiring multiple bytes) encoded, and UTF-8 is backwards compatible with ASCII.
[QUOTE=iPope;21366809]I had a crack and writing it using a binary stream, the server says that the name cannot be verified (it's correct just omitted from the source). Here's the code: [I]I'm a c# newb so maybe you can see where I'm going wrong[/I]
[code]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
namespace MinecraftBot
{
class Program
{
static void Main()
{
Program self = new Program();
TcpClient Client = new TcpClient("localhost", 25565);
NetworkStream NStream = Client.GetStream();
NStream.Flush();
//Player Info
byte PacketID = 0x00;
byte ProtocalVersion = 0x07;
string Username = self.PadString("name", 64);
string Password = self.PadString("password", 64);
byte Unused = 0x00;
BinaryWriter BWrite = new BinaryWriter(NStream);
BWrite.Write(PacketID);
BWrite.Write(ProtocalVersion);
BWrite.Write(Username);
BWrite.Write(Password);
BWrite.Write(Unused);
while (true) { };
}
string PadString(String str, int Length)
{
String PaddedString = str;
PaddedString = PaddedString.PadRight(64, ' ');
return PaddedString;
}
}
}
[/code]
[b]Edit:[/b]
Fixed by turning verify-names to false.[/QUOTE]
PadString doesn't use the Program object (this object), while at the same time PadString is the only reason you create a Program to begin with. You should just make PadString a static function and call it from Main like so:
[code]
PadString("name", 64);
//Or the less ambiguous form:
Program.PadString("name", 64);
[/code]
Ok, so there's an easier way to pad strings...
I'll change my program to work a bit more like yours.
Also, didn't you have to change the "Endian-ness" of your numbers?
[I]No, maybe that is my problem.[/I] No it's not because you only need to change if it's larger than 8 bits.
Also Ja_Cop I've just removed that function because it was sort of redundant. Instead I just used PadRight().
[QUOTE=Chris220;21367731]Ok, so there's an easier way to pad strings...
I'll change my program to work a bit more like yours.
Also, didn't you have to change the "Endian-ness" of your numbers?[/QUOTE]
You only have to change the endian-ness when there are more than 8 bits in your number. The protocol contains some 16 bit numbers (the Short type), but you don't need them yet.
Got it. And I understand why that is as well, which is good :V
[editline]Edited:[/editline]
What about the strings? Why don't they need to be changed?
This thread helped me a lot, but I keep getting "the name wasn't verified by minecraft.net! errors :saddowns:
[QUOTE=Chris220;21367902]Got it. And I understand why that is as well, which is good :V
[editline]Edited:[/editline]
What about the strings? Why don't they need to be changed?[/QUOTE]
Because the characters are 8-bit each.
And it expects them "backwards" so to speak?
Dlaor: This might sound stupid, but did you register an account on minecraft.net for your bot? :P
[QUOTE=Chris220;21368661]
Dlaor: This might sound stupid, but did you register an account on minecraft.net for your bot? :P[/QUOTE]
Of course.
[editline]07:55PM[/editline]
Hmm, the MC wiki page about the protocol says that the 4th string isn't a password but a verification string. What is this?
That's what I thought. I assumed it was the password. I guess it's some sort of code that the client needs to generate, and it's used to make sure the user is not posing as someone else (if verify-names is true)
Here's my code now:
[code]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.IO;
namespace Minerbot
{
class Program
{
static void Main(string[] args)
{
TcpClient connection = new TcpClient("localhost", 27015);
NetworkStream stream = connection.GetStream();
stream.Flush();
BinaryWriter netWriter = new BinaryWriter(stream);
// Player information
byte PacketID = 0x00;
byte ProtocolVersion = 0x07;
string Username = "Minerbot";
Username = Username.PadRight(64, ' ');
string VerificationKey = "PASSWORD_HERE";
VerificationKey = VerificationKey.PadRight(64, ' ');
byte unused = 0x00; // So it's not needed... shoot me
// Write the data
netWriter.Write(PacketID);
netWriter.Write(ProtocolVersion);
netWriter.Write(Username);
netWriter.Write(VerificationKey);
netWriter.Write(unused);
// Wait for 10 seconds
System.Threading.Thread.Sleep(10000);
}
}
}[/code]
It just about works, except when it's running, it "pauses" my own connection to the server. Meaning I can't send/recieve chat or anything. After the 10 seconds pause, I recieve all chat in one big block.
Also, the name shows as @Minerbot, instead of just Minerbot.
The verification ID is generated by the minecraft.net website on either login or joining of a server (not sure), you can find the verification ID by logging in on minecraft.net then joining a server, viewing the page source and searching for "mppass".
I recommend using a HTML library to find the "mppass" when trying to join a server, as this is what the World of Minecraft hacked client does.
I know this from thorough work with custom minecraft servers including JTE and Myne.
Wow, what a useful first post! Thanks man, that's brilliant.
So, can I just login once, and use the same Verification Key over and over? Or does it have to be different every time?
A new one is generated per joining of a server. So your going to have to find a way to retrieve the "mppass" from the server page on minecraft.net somehow.
And by doing that, it won't only be able to connect to servers with verify-names set to false, right?
So, any ideas as to why it lags out my connection until it closes, why its name has a @ at the start of it, and why its player model stays on the server, even when the bot isn't running anymore?
You need to retrieve the "mppass" to be able to login to a "verify-names=true" server. As for the other questions I have little knowledge. I recommend taking a look at "[url="http://copy.zapto.org/obsidian/"]obsidian[/url]" made by copyboy, it is a minecraft server written in C# and may help you with your bot, that link also has the IRC server and channel copyboy resides in if you would like to ask him any questions.
Sorry, you need to Log In to post a reply to this thread.