mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Added MCC Source Code v1.5.2
Minecraft Console Client is now on GitHub!
This commit is contained in:
parent
bb02f5b76d
commit
e6f2ef4e4f
16 changed files with 3116 additions and 0 deletions
20
MinecraftClient.sln
Normal file
20
MinecraftClient.sln
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 11.00
|
||||
# Visual Studio 2010
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinecraftClient", "MinecraftClient\MinecraftClient.csproj", "{1E2FACE4-F5CA-4323-9641-740C6A551770}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{1E2FACE4-F5CA-4323-9641-740C6A551770}.Debug|x86.ActiveCfg = Debug|x86
|
||||
{1E2FACE4-F5CA-4323-9641-740C6A551770}.Debug|x86.Build.0 = Debug|x86
|
||||
{1E2FACE4-F5CA-4323-9641-740C6A551770}.Release|x86.ActiveCfg = Release|x86
|
||||
{1E2FACE4-F5CA-4323-9641-740C6A551770}.Release|x86.Build.0 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
845
MinecraftClient/Bots.cs
Normal file
845
MinecraftClient/Bots.cs
Normal file
|
|
@ -0,0 +1,845 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
///
|
||||
/// Welcome to the Bot API file !
|
||||
/// The virtual class "ChatBot" contains anything you need for creating chat bots
|
||||
/// Inherit from this class while adding your bot class to the namespace "Bots", below.
|
||||
/// Once your bot is created, simply edit the switch in Program.cs to add the corresponding command-line argument!
|
||||
///
|
||||
|
||||
/// <summary>
|
||||
/// The virtual class containing anything you need for creating chat bots.
|
||||
/// </summary>
|
||||
|
||||
public abstract class ChatBot
|
||||
{
|
||||
public enum DisconnectReason { InGameKick, LoginRejected, ConnectionLost };
|
||||
|
||||
#region MinecraftCom Handler for this bot
|
||||
|
||||
//Will be automatically set on bot loading, don't worry about this
|
||||
public void SetHandler(MinecraftCom handler) { this.handler = handler; }
|
||||
private MinecraftCom handler;
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Anything you want to initialize your bot, will be called on load by MinecraftCom
|
||||
/// </summary>
|
||||
|
||||
public virtual void Initialize() { }
|
||||
|
||||
/// <summary>
|
||||
/// Will be called every ~100ms (10fps) if loaded in MinecraftCom
|
||||
/// </summary>
|
||||
|
||||
public virtual void Update() { }
|
||||
|
||||
/// <summary>
|
||||
/// Any text sent by the server will be sent here by MinecraftCom
|
||||
/// </summary>
|
||||
/// <param name="text">Text from the server</param>
|
||||
|
||||
public virtual void GetText(string text) { }
|
||||
|
||||
/// <summary>
|
||||
/// Is called when the client has been disconnected fom the server
|
||||
/// </summary>
|
||||
/// <param name="reason">Disconnect Reason</param>
|
||||
/// <param name="message">Kick message, if any</param>
|
||||
/// <returns>Return TRUE if the client is about to restart</returns>
|
||||
|
||||
public virtual bool OnDisconnect(DisconnectReason reason, string message) { return false; }
|
||||
|
||||
#region ToolBox
|
||||
|
||||
/// <summary>
|
||||
/// Send text to the server. Can be anything such as chat messages or commands
|
||||
/// </summary>
|
||||
/// <param name="text">Text to send to the server</param>
|
||||
|
||||
protected void SendText(string text)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
ConsoleIO.WriteLine("BOT:" + text);
|
||||
handler.SendChatMessage(text);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove color codes ("§c") from a text message received from the server
|
||||
/// </summary>
|
||||
|
||||
protected static string getVerbatim(string text)
|
||||
{
|
||||
string verbatim = "";
|
||||
for (int i = 0; i < text.Length; i++)
|
||||
{
|
||||
if (text[i] == '§')
|
||||
{
|
||||
i++; //Will skip also the next char
|
||||
}
|
||||
else verbatim += text[i]; //Add the char
|
||||
}
|
||||
return verbatim;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verify that a string contains only a-z A-Z 0-9 and _ characters.
|
||||
/// </summary>
|
||||
|
||||
protected static bool isValidName(string username)
|
||||
{
|
||||
if (username == "") { return false; }
|
||||
string validchars =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
+ "1234567890_";
|
||||
|
||||
bool passe = false;
|
||||
bool ok = true;
|
||||
for (int i = 0; i < username.Length; i++)
|
||||
{
|
||||
passe = false;
|
||||
for (int j = 0; j < validchars.Length; j++)
|
||||
{
|
||||
if (username[i] == validchars[j])
|
||||
{
|
||||
passe = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!passe)
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true is the text passed is a private message sent to the bot
|
||||
/// </summary>
|
||||
/// <param name="text">text to test</param>
|
||||
/// <param name="message">if it's a private message, this will contain the message</param>
|
||||
/// <param name="sender">if it's a private message, this will contain the player name that sends the message</param>
|
||||
/// <returns>Returns true if the text is a private message</returns>
|
||||
|
||||
protected static bool isPrivateMessage(string text, ref string message, ref string sender)
|
||||
{
|
||||
if (text == "") { return false; }
|
||||
string[] tmp = text.Split(' ');
|
||||
|
||||
try
|
||||
{
|
||||
//Detect vanilla /tell messages
|
||||
//Someone whispers message
|
||||
if (tmp.Length > 2 && tmp[1] == "whispers")
|
||||
{
|
||||
message = text.Substring(tmp[0].Length + 10);
|
||||
sender = tmp[0];
|
||||
return isValidName(sender);
|
||||
}
|
||||
|
||||
//Detect Essentials (Bukkit) /m messages
|
||||
//[Someone -> me] message
|
||||
else if (text[0] == '[' && tmp.Length > 3 && tmp[1] == "->"
|
||||
&& (tmp[2] == "me]" || tmp[2] == "moi]")) //'me' is replaced by 'moi' in french servers
|
||||
{
|
||||
message = text.Substring(tmp[0].Length + 4 + tmp[2].Length + 1);
|
||||
sender = tmp[0].Substring(1);
|
||||
if (sender[0] == '~') { sender = sender.Substring(1); }
|
||||
return isValidName(sender);
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
catch (IndexOutOfRangeException) { return false; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true is the text passed is a public message written by a player on the chat
|
||||
/// </summary>
|
||||
/// <param name="text">text to test</param>
|
||||
/// <param name="message">if it's message, this will contain the message</param>
|
||||
/// <param name="sender">if it's message, this will contain the player name that sends the message</param>
|
||||
/// <returns>Returns true if the text is a chat message</returns>
|
||||
|
||||
protected static bool isChatMessage(string text, ref string message, ref string sender)
|
||||
{
|
||||
//Detect chat messages
|
||||
//<Someone> message
|
||||
//<*Faction Someone> message
|
||||
//<*Faction Someone>: message
|
||||
//<*Faction ~Nicknamed>: message
|
||||
if (text == "") { return false; }
|
||||
if (text[0] == '<')
|
||||
{
|
||||
try
|
||||
{
|
||||
text = text.Substring(1);
|
||||
string[] tmp = text.Split('>');
|
||||
sender = tmp[0];
|
||||
message = text.Substring(sender.Length + 2);
|
||||
if (message.Length > 1 && message[0] == ' ')
|
||||
{ message = message.Substring(1); }
|
||||
tmp = sender.Split(' ');
|
||||
sender = tmp[tmp.Length - 1];
|
||||
if (sender[0] == '~') { sender = sender.Substring(1); }
|
||||
return isValidName(sender);
|
||||
}
|
||||
catch (IndexOutOfRangeException) { return false; }
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes some text in the console. Nothing will be sent to the server.
|
||||
/// </summary>
|
||||
/// <param name="text">Log text to write</param>
|
||||
|
||||
public static void LogToConsole(string text)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
ConsoleIO.WriteLine("[BOT] " + text);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from the server and restart the program
|
||||
/// It will unload & reload all the bots and then reconnect to the server
|
||||
/// </summary>
|
||||
|
||||
protected void ReconnectToTheServer() { ReconnectToTheServer(3); }
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect from the server and restart the program
|
||||
/// It will unload & reload all the bots and then reconnect to the server
|
||||
/// </summary>
|
||||
/// <param name="attempts">If connection fails, the client will make X extra attempts</param>
|
||||
|
||||
protected void ReconnectToTheServer(int ExtraAttempts)
|
||||
{
|
||||
McTcpClient.AttemptsLeft = ExtraAttempts;
|
||||
Program.Restart();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Unload the chatbot, and release associated memory.
|
||||
/// </summary>
|
||||
|
||||
protected void UnloadBot()
|
||||
{
|
||||
handler.BotUnLoad(this);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
namespace Bots
|
||||
{
|
||||
/// <summary>
|
||||
/// Example of message receiving.
|
||||
/// </summary>
|
||||
|
||||
public class TestBot : ChatBot
|
||||
{
|
||||
public override void GetText(string text)
|
||||
{
|
||||
string message = "";
|
||||
string username = "";
|
||||
text = getVerbatim(text);
|
||||
|
||||
if (isPrivateMessage(text, ref message, ref username))
|
||||
{
|
||||
ConsoleIO.WriteLine("Bot: " + username + " told me : " + message);
|
||||
}
|
||||
else if (isChatMessage(text, ref message, ref username))
|
||||
{
|
||||
ConsoleIO.WriteLine("Bot: " + username + " said : " + message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This bot sends a /ping command every 60 seconds in order to stay non-afk.
|
||||
/// </summary>
|
||||
|
||||
public class AntiAFK : ChatBot
|
||||
{
|
||||
private int count;
|
||||
private int timeping;
|
||||
|
||||
/// <summary>
|
||||
/// This bot sends a /ping command every X seconds in order to stay non-afk.
|
||||
/// </summary>
|
||||
/// <param name="pingparam">Time amount between each ping (10 = 1s, 600 = 1 minute, etc.)</param>
|
||||
|
||||
public AntiAFK(int pingparam)
|
||||
{
|
||||
count = 0;
|
||||
timeping = pingparam;
|
||||
if (timeping < 10) { timeping = 10; } //To avoid flooding
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
count++;
|
||||
if (count == timeping)
|
||||
{
|
||||
SendText("/ping");
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This bot sends a /list command every X seconds and save the result.
|
||||
/// </summary>
|
||||
|
||||
public class PlayerListLogger : ChatBot
|
||||
{
|
||||
private int count;
|
||||
private int timeping;
|
||||
private string file;
|
||||
|
||||
/// <summary>
|
||||
/// This bot sends a /list command every X seconds and save the result.
|
||||
/// </summary>
|
||||
/// <param name="pingparam">Time amount between each list ping (10 = 1s, 600 = 1 minute, etc.)</param>
|
||||
|
||||
public PlayerListLogger(int pingparam, string filetosavein)
|
||||
{
|
||||
count = 0;
|
||||
file = filetosavein;
|
||||
timeping = pingparam;
|
||||
if (timeping < 10) { timeping = 10; } //To avoid flooding
|
||||
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
count++;
|
||||
if (count == timeping)
|
||||
{
|
||||
SendText("/list");
|
||||
count = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetText(string text)
|
||||
{
|
||||
if (text.Contains("Joueurs en ligne") || text.Contains("Connected:") || text.Contains("online:"))
|
||||
{
|
||||
LogToConsole("Saving Player List");
|
||||
DateTime now = DateTime.Now;
|
||||
string TimeStamp = "[" + now.Year + '/' + now.Month + '/' + now.Day + ' ' + now.Hour + ':' + now.Minute + ']';
|
||||
System.IO.File.AppendAllText(file, TimeStamp + "\n" + getVerbatim(text) + "\n\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// "Le jeu du Pendu" (Hangman game)
|
||||
/// </summary>
|
||||
|
||||
public class Pendu : ChatBot
|
||||
{
|
||||
private int vie = 0;
|
||||
private int vie_param = 10;
|
||||
private int compteur = 0;
|
||||
private int compteur_param = 3000; //5 minutes
|
||||
private bool running = false;
|
||||
private bool[] discovered;
|
||||
private string word = "";
|
||||
private string letters = "";
|
||||
private string[] owners;
|
||||
private bool English;
|
||||
|
||||
/// <summary>
|
||||
/// "Le jeu du Pendu" (Hangman Game)
|
||||
/// </summary>
|
||||
/// <param name="english">if true, the game will be in english. If false, the game will be in french.</param>
|
||||
|
||||
public Pendu(bool english)
|
||||
{
|
||||
English = english;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
owners = getowners();
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
if (running)
|
||||
{
|
||||
if (compteur > 0)
|
||||
{
|
||||
compteur--;
|
||||
}
|
||||
else
|
||||
{
|
||||
SendText(English ? "You took too long to try a letter." : "Temps imparti écoulé !");
|
||||
SendText(English ? "Game canceled." : "Partie annulée.");
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetText(string text)
|
||||
{
|
||||
string message = "";
|
||||
string username = "";
|
||||
text = getVerbatim(text);
|
||||
|
||||
if (isPrivateMessage(text, ref message, ref username))
|
||||
{
|
||||
if (owners.Contains(username.ToUpper()))
|
||||
{
|
||||
switch (message)
|
||||
{
|
||||
case "start":
|
||||
start();
|
||||
break;
|
||||
case "stop":
|
||||
running = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (running && isChatMessage(text, ref message, ref username))
|
||||
{
|
||||
if (message.Length == 1)
|
||||
{
|
||||
char letter = message.ToUpper()[0];
|
||||
if (letter >= 'A' && letter <= 'Z')
|
||||
{
|
||||
if (letters.Contains(letter))
|
||||
{
|
||||
SendText(English ? ("Letter " + letter + " has already been tried.") : ("Le " + letter + " a déjà été proposé."));
|
||||
}
|
||||
else
|
||||
{
|
||||
letters += letter;
|
||||
compteur = compteur_param;
|
||||
|
||||
if (word.Contains(letter))
|
||||
{
|
||||
for (int i = 0; i < word.Length; i++) { if (word[i] == letter) { discovered[i] = true; } }
|
||||
SendText(English ? ("Yes, the word contains a " + letter + '!') : ("Le " + letter + " figurait bien dans le mot :)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
vie--;
|
||||
if (vie == 0)
|
||||
{
|
||||
SendText(English ? "Game Over! :]" : "Perdu ! Partie terminée :]");
|
||||
SendText(English ? ("The word was: " + word) : ("Le mot était : " + word));
|
||||
running = false;
|
||||
}
|
||||
else SendText(English ? ("The " + letter + "? No.") : ("Le " + letter + " ? Non."));
|
||||
}
|
||||
|
||||
if (running)
|
||||
{
|
||||
SendText(English ? ("Mysterious word: " + word_cached + " (lives : " + vie + ")")
|
||||
: ("Mot mystère : " + word_cached + " (vie : " + vie + ")"));
|
||||
}
|
||||
|
||||
if (winner)
|
||||
{
|
||||
SendText(English ? ("Congrats, " + username + '!') : ("Félicitations, " + username + " !"));
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void start()
|
||||
{
|
||||
vie = vie_param;
|
||||
running = true;
|
||||
letters = "";
|
||||
word = chooseword();
|
||||
compteur = compteur_param;
|
||||
discovered = new bool[word.Length];
|
||||
|
||||
SendText(English ? "Hangman v1.0 - By ORelio" : "Pendu v1.0 - Par ORelio");
|
||||
SendText(English ? ("Mysterious word: " + word_cached + " (lives : " + vie + ")")
|
||||
: ("Mot mystère : " + word_cached + " (vie : " + vie + ")"));
|
||||
SendText(English ? ("Try some letters ... :)") : ("Proposez une lettre ... :)"));
|
||||
}
|
||||
|
||||
private string chooseword()
|
||||
{
|
||||
if (System.IO.File.Exists(English ? "words.txt" : "mots.txt"))
|
||||
{
|
||||
string[] dico = System.IO.File.ReadAllLines(English ? "words.txt" : "mots.txt");
|
||||
return dico[new Random().Next(dico.Length)];
|
||||
}
|
||||
else
|
||||
{
|
||||
LogToConsole(English ? "Cannot find words.txt !" : "Fichier mots.txt introuvable !");
|
||||
return English ? "WORDSAREMISSING" : "DICOMANQUANT";
|
||||
}
|
||||
}
|
||||
|
||||
private string[] getowners()
|
||||
{
|
||||
List<string> owners = new List<string>();
|
||||
owners.Add("CONSOLE");
|
||||
if (System.IO.File.Exists("bot-owners.txt"))
|
||||
{
|
||||
foreach (string s in System.IO.File.ReadAllLines("bot-owners.txt"))
|
||||
{
|
||||
owners.Add(s.ToUpper());
|
||||
}
|
||||
}
|
||||
else LogToConsole(English ? "Cannot find bot-owners.txt !" : "Fichier bot-owners.txt introuvable !");
|
||||
return owners.ToArray();
|
||||
}
|
||||
|
||||
private string word_cached
|
||||
{
|
||||
get
|
||||
{
|
||||
string printed = "";
|
||||
for (int i = 0; i < word.Length; i++)
|
||||
{
|
||||
if (discovered[i])
|
||||
{
|
||||
printed += word[i];
|
||||
}
|
||||
else printed += '_';
|
||||
}
|
||||
return printed;
|
||||
}
|
||||
}
|
||||
|
||||
private bool winner
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < discovered.Length; i++)
|
||||
{
|
||||
if (!discovered[i])
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This bot make the console beep on some specified words. Useful to detect when someone is talking to you, for example.
|
||||
/// </summary>
|
||||
|
||||
public class Alerts : ChatBot
|
||||
{
|
||||
private string[] dictionnary = new string[0];
|
||||
private string[] excludelist = new string[0];
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
if (System.IO.File.Exists("alerts.txt"))
|
||||
{
|
||||
dictionnary = System.IO.File.ReadAllLines("alerts.txt");
|
||||
|
||||
for (int i = 0; i < dictionnary.Length; i++)
|
||||
{
|
||||
dictionnary[i] = dictionnary[i].ToLower();
|
||||
}
|
||||
}
|
||||
else LogToConsole("Cannot find alerts.txt !");
|
||||
|
||||
if (System.IO.File.Exists("alerts-exclude.txt"))
|
||||
{
|
||||
excludelist = System.IO.File.ReadAllLines("alerts-exclude.txt");
|
||||
|
||||
for (int i = 0; i < excludelist.Length; i++)
|
||||
{
|
||||
excludelist[i] = excludelist[i].ToLower();
|
||||
}
|
||||
}
|
||||
else LogToConsole("Cannot find alerts-exclude.txt !");
|
||||
}
|
||||
|
||||
public override void GetText(string text)
|
||||
{
|
||||
text = getVerbatim(text);
|
||||
string comp = text.ToLower();
|
||||
foreach (string alert in dictionnary)
|
||||
{
|
||||
if (comp.Contains(alert))
|
||||
{
|
||||
bool ok = true;
|
||||
|
||||
foreach (string exclusion in excludelist)
|
||||
{
|
||||
if (comp.Contains(exclusion))
|
||||
{
|
||||
ok = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
Console.Beep(); //Text found !
|
||||
#region Displaying the text with the interesting part highlighted
|
||||
|
||||
Console.BackgroundColor = ConsoleColor.DarkGray;
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
|
||||
//Will be used for text displaying
|
||||
string[] temp = comp.Split(alert.Split(','), StringSplitOptions.RemoveEmptyEntries);
|
||||
int p = 0;
|
||||
|
||||
//Special case : alert in the beginning of the text
|
||||
string test = "";
|
||||
for (int i = 0; i < alert.Length; i++)
|
||||
{
|
||||
test += comp[i];
|
||||
}
|
||||
if (test == alert)
|
||||
{
|
||||
Console.BackgroundColor = ConsoleColor.Yellow;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
for (int i = 0; i < alert.Length; i++)
|
||||
{
|
||||
ConsoleIO.Write(text[p]);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
|
||||
//Displaying the rest of the text
|
||||
for (int i = 0; i < temp.Length; i++)
|
||||
{
|
||||
Console.BackgroundColor = ConsoleColor.DarkGray;
|
||||
Console.ForegroundColor = ConsoleColor.White;
|
||||
for (int j = 0; j < temp[i].Length; j++)
|
||||
{
|
||||
ConsoleIO.Write(text[p]);
|
||||
p++;
|
||||
}
|
||||
Console.BackgroundColor = ConsoleColor.Yellow;
|
||||
Console.ForegroundColor = ConsoleColor.Red;
|
||||
try
|
||||
{
|
||||
for (int j = 0; j < alert.Length; j++)
|
||||
{
|
||||
ConsoleIO.Write(text[p]);
|
||||
p++;
|
||||
}
|
||||
}
|
||||
catch (IndexOutOfRangeException) { }
|
||||
}
|
||||
Console.BackgroundColor = ConsoleColor.Black;
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
ConsoleIO.Write('\n');
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This bot saves the received messages in a text file.
|
||||
/// </summary>
|
||||
|
||||
public class ChatLog : ChatBot
|
||||
{
|
||||
public enum MessageFilter { AllText, AllMessages, OnlyChat, OnlyWhispers };
|
||||
private bool dateandtime;
|
||||
private bool saveOther = true;
|
||||
private bool saveChat = true;
|
||||
private bool savePrivate = true;
|
||||
private string logfile;
|
||||
|
||||
/// <summary>
|
||||
/// This bot saves the messages received in the specified file, with some filters and date/time tagging.
|
||||
/// </summary>
|
||||
/// <param name="file">The file to save the log in</param>
|
||||
/// <param name="filter">The kind of messages to save</param>
|
||||
/// <param name="AddDateAndTime">Add a date and time before each message</param>
|
||||
|
||||
public ChatLog(string file, MessageFilter filter, bool AddDateAndTime)
|
||||
{
|
||||
dateandtime = AddDateAndTime;
|
||||
logfile = file;
|
||||
switch (filter)
|
||||
{
|
||||
case MessageFilter.AllText:
|
||||
saveOther = true;
|
||||
savePrivate = true;
|
||||
saveChat = true;
|
||||
break;
|
||||
case MessageFilter.AllMessages:
|
||||
saveOther = false;
|
||||
savePrivate = true;
|
||||
saveChat = true;
|
||||
break;
|
||||
case MessageFilter.OnlyChat:
|
||||
saveOther = false;
|
||||
savePrivate = false;
|
||||
saveChat = true;
|
||||
break;
|
||||
case MessageFilter.OnlyWhispers:
|
||||
saveOther = false;
|
||||
savePrivate = true;
|
||||
saveChat = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetText(string text)
|
||||
{
|
||||
text = getVerbatim(text);
|
||||
string sender = "";
|
||||
string message = "";
|
||||
|
||||
if (saveChat && isChatMessage(text, ref message, ref sender))
|
||||
{
|
||||
save("Chat " + sender + ": " + message);
|
||||
}
|
||||
else if (savePrivate && isPrivateMessage(text, ref message, ref sender))
|
||||
{
|
||||
save("Private " + sender + ": " + message);
|
||||
}
|
||||
else if (saveOther)
|
||||
{
|
||||
save("Other: " + text);
|
||||
}
|
||||
}
|
||||
|
||||
private void save(string tosave)
|
||||
{
|
||||
if (dateandtime)
|
||||
{
|
||||
int day = DateTime.Now.Day, month = DateTime.Now.Month;
|
||||
int hour = DateTime.Now.Hour, minute = DateTime.Now.Minute, second = DateTime.Now.Second;
|
||||
|
||||
string D = day < 10 ? "0" + day : "" + day;
|
||||
string M = month < 10 ? "0" + month : "" + day;
|
||||
string Y = "" + DateTime.Now.Year;
|
||||
|
||||
string h = hour < 10 ? "0" + hour : "" + hour;
|
||||
string m = minute < 10 ? "0" + minute : "" + minute;
|
||||
string s = second < 10 ? "0" + second : "" + second;
|
||||
|
||||
tosave = "" + D + '-' + M + '-' + Y + ' ' + h + ':' + m + ':' + s + ' ' + tosave;
|
||||
}
|
||||
|
||||
System.IO.FileStream stream = new System.IO.FileStream(logfile, System.IO.FileMode.OpenOrCreate);
|
||||
System.IO.StreamWriter writer = new System.IO.StreamWriter(stream);
|
||||
stream.Seek(0, System.IO.SeekOrigin.End);
|
||||
writer.WriteLine(tosave);
|
||||
writer.Dispose();
|
||||
stream.Close();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This bot automatically re-join the server if kick message contains predefined string (Server is restarting ...)
|
||||
/// </summary>
|
||||
|
||||
public class AutoRelog : ChatBot
|
||||
{
|
||||
private string[] dictionnary = new string[0];
|
||||
private int attempts;
|
||||
private int delay;
|
||||
|
||||
/// <summary>
|
||||
/// This bot automatically re-join the server if kick message contains predefined string
|
||||
/// </summary>
|
||||
/// <param name="DelayBeforeRelog">Delay before re-joining the server (in seconds)</param>
|
||||
/// <param name="retries">Number of retries if connection fails (-1 = infinite)</param>
|
||||
|
||||
public AutoRelog(int DelayBeforeRelog, int retries)
|
||||
{
|
||||
attempts = retries;
|
||||
if (attempts == -1) { attempts = int.MaxValue; }
|
||||
McTcpClient.AttemptsLeft = attempts;
|
||||
delay = DelayBeforeRelog;
|
||||
if (delay < 1) { delay = 1; }
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
McTcpClient.AttemptsLeft = attempts;
|
||||
if (System.IO.File.Exists("kickmessages.txt"))
|
||||
{
|
||||
dictionnary = System.IO.File.ReadAllLines("kickmessages.txt");
|
||||
|
||||
for (int i = 0; i < dictionnary.Length; i++)
|
||||
{
|
||||
dictionnary[i] = dictionnary[i].ToLower();
|
||||
}
|
||||
}
|
||||
else LogToConsole("Cannot find kickmessages.txt !");
|
||||
}
|
||||
|
||||
public override bool OnDisconnect(DisconnectReason reason, string message)
|
||||
{
|
||||
message = getVerbatim(message);
|
||||
string comp = message.ToLower();
|
||||
foreach (string msg in dictionnary)
|
||||
{
|
||||
if (comp.Contains(msg))
|
||||
{
|
||||
LogToConsole("Waiting " + delay + " seconds before reconnecting...");
|
||||
System.Threading.Thread.Sleep(delay * 1000);
|
||||
McTcpClient.AttemptsLeft = attempts;
|
||||
ReconnectToTheServer();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically send login command on servers usign the xAuth plugin
|
||||
/// </summary>
|
||||
|
||||
public class xAuth : ChatBot
|
||||
{
|
||||
private string password;
|
||||
private int countdown = 50;
|
||||
|
||||
public xAuth(string pass)
|
||||
{
|
||||
password = pass;
|
||||
}
|
||||
|
||||
public override void Update()
|
||||
{
|
||||
countdown--;
|
||||
if (countdown == 0)
|
||||
{
|
||||
SendText("/login " + password);
|
||||
UnloadBot(); //This bot is no more needed.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
MinecraftClient/BouncyCastle.Crypto.dll
Normal file
BIN
MinecraftClient/BouncyCastle.Crypto.dll
Normal file
Binary file not shown.
297
MinecraftClient/ChatParser.cs
Normal file
297
MinecraftClient/ChatParser.cs
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
/// <summary>
|
||||
/// This class parses JSON chat data from MC 1.6+ and returns the appropriate string to be printed.
|
||||
/// </summary>
|
||||
|
||||
static class ChatParser
|
||||
{
|
||||
/// <summary>
|
||||
/// The main function to convert text from MC 1.6+ JSON to MC 1.5.2 formatted text
|
||||
/// </summary>
|
||||
/// <param name="json">JSON serialized text</param>
|
||||
/// <returns>Returns the translated text</returns>
|
||||
|
||||
public static string ParseText(string json)
|
||||
{
|
||||
int cursorpos = 0;
|
||||
JSONData jsonData = String2Data(json, ref cursorpos);
|
||||
return JSONData2String(jsonData).Replace("u0027", "'");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An internal class to store unserialized JSON data
|
||||
/// The data can be an object, an array or a string
|
||||
/// </summary>
|
||||
|
||||
private class JSONData
|
||||
{
|
||||
public enum DataType { Object, Array, String };
|
||||
private DataType type;
|
||||
public DataType Type { get { return type; } }
|
||||
public Dictionary<string, JSONData> Properties;
|
||||
public List<JSONData> DataArray;
|
||||
public string StringValue;
|
||||
public JSONData(DataType datatype)
|
||||
{
|
||||
type = datatype;
|
||||
Properties = new Dictionary<string, JSONData>();
|
||||
DataArray = new List<JSONData>();
|
||||
StringValue = String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the classic color tag corresponding to a color name
|
||||
/// </summary>
|
||||
/// <param name="colorname">Color Name</param>
|
||||
/// <returns>Color code</returns>
|
||||
|
||||
private static string color2tag(string colorname)
|
||||
{
|
||||
switch(colorname.ToLower())
|
||||
{
|
||||
case "black": return "§0";
|
||||
case "dark_blue": return "§1";
|
||||
case "dark_green" : return "§2";
|
||||
case "dark_cyan": return "§3";
|
||||
case "dark_cyanred": return "§4";
|
||||
case "dark_magenta": return "§5";
|
||||
case "dark_yellow": return "§6";
|
||||
case "gray": return "§7";
|
||||
case "dark_gray": return "§8";
|
||||
case "blue": return "§9";
|
||||
case "green": return "§a";
|
||||
case "cyan": return "§b";
|
||||
case "red": return "§c";
|
||||
case "magenta": return "§d";
|
||||
case "yellow": return "§e";
|
||||
case "white": return "§f";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Rules for text translation
|
||||
/// </summary>
|
||||
|
||||
private static bool init = false;
|
||||
private static Dictionary<string, string> TranslationRules = new Dictionary<string, string>();
|
||||
public static void InitTranslations() { if (!init) { InitRules(); init = true; } }
|
||||
private static void InitRules()
|
||||
{
|
||||
//Small default dictionnary of translation rules
|
||||
TranslationRules["chat.type.admin"] = "[%s: %s]";
|
||||
TranslationRules["chat.type.announcement"] = "§d[%s] %s";
|
||||
TranslationRules["chat.type.emote"] = " * %s %s";
|
||||
TranslationRules["chat.type.text"] = "<%s> %s";
|
||||
TranslationRules["multiplayer.player.joined"] = "§e%s joined the game.";
|
||||
TranslationRules["multiplayer.player.left"] = "§e%s left the game.";
|
||||
TranslationRules["commands.message.display.incoming"] = "§7%s whispers to you: %s";
|
||||
TranslationRules["commands.message.display.outgoing"] = "§7You whisper to %s: %s";
|
||||
|
||||
//Load an external dictionnary of translation rules
|
||||
if (System.IO.File.Exists("translations.lang"))
|
||||
{
|
||||
string[] translations = System.IO.File.ReadAllLines("translations.lang");
|
||||
foreach (string line in translations)
|
||||
{
|
||||
if (line.Length > 0)
|
||||
{
|
||||
string[] splitted = line.Split('=');
|
||||
if (splitted.Length == 2)
|
||||
{
|
||||
TranslationRules[splitted[0]] = splitted[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
ConsoleIO.WriteLine("Translations file loaded.");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
else //No external dictionnary found.
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
ConsoleIO.WriteLine("MC 1.6+ warning: Translations file \"translations.lang\" not found."
|
||||
+ "\nYou can pick a translation file from .minecraft\\assets\\lang\\"
|
||||
+ "\nCopy to the same folder as MinecraftClient & rename to \"translations.lang\""
|
||||
+ "\nSome messages won't be properly printed without this file.");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format text using a specific formatting rule.
|
||||
/// Example : * %s %s + ["ORelio", "is doing something"] = * ORelio is doing something
|
||||
/// </summary>
|
||||
/// <param name="rulename">Name of the rule, chosen by the server</param>
|
||||
/// <param name="using_data">Data to be used in the rule</param>
|
||||
/// <returns>Returns the formatted text according to the given data</returns>
|
||||
|
||||
private static string TranslateString(string rulename, List<string> using_data)
|
||||
{
|
||||
if (!init) { InitRules(); init = true; }
|
||||
if (TranslationRules.ContainsKey(rulename))
|
||||
{
|
||||
string[] syntax = TranslationRules[rulename].Split(new string[2] { "%s", "%d" }, StringSplitOptions.None);
|
||||
while (using_data.Count < syntax.Length - 1) { using_data.Add(""); }
|
||||
string[] using_array = using_data.ToArray();
|
||||
string translated = "";
|
||||
for (int i = 0; i < syntax.Length - 1; i++)
|
||||
{
|
||||
translated += syntax[i];
|
||||
translated += using_array[i];
|
||||
}
|
||||
translated += syntax[syntax.Length - 1];
|
||||
return translated;
|
||||
}
|
||||
else return "[" + rulename + "] " + String.Join(" ", using_data);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a JSON string to build a JSON object
|
||||
/// </summary>
|
||||
/// <param name="toparse">String to parse</param>
|
||||
/// <param name="cursorpos">Cursor start (set to 0 for function init)</param>
|
||||
/// <returns></returns>
|
||||
|
||||
private static JSONData String2Data(string toparse, ref int cursorpos)
|
||||
{
|
||||
try
|
||||
{
|
||||
JSONData data;
|
||||
switch (toparse[cursorpos])
|
||||
{
|
||||
//Object
|
||||
case '{':
|
||||
data = new JSONData(JSONData.DataType.Object);
|
||||
cursorpos++;
|
||||
while (toparse[cursorpos] != '}')
|
||||
{
|
||||
if (toparse[cursorpos] == '"')
|
||||
{
|
||||
JSONData propertyname = String2Data(toparse, ref cursorpos);
|
||||
if (toparse[cursorpos] == ':') { cursorpos++; } else { /* parse error ? */ }
|
||||
JSONData propertyData = String2Data(toparse, ref cursorpos);
|
||||
data.Properties[propertyname.StringValue] = propertyData;
|
||||
}
|
||||
else cursorpos++;
|
||||
}
|
||||
cursorpos++;
|
||||
break;
|
||||
|
||||
//Array
|
||||
case '[':
|
||||
data = new JSONData(JSONData.DataType.Array);
|
||||
cursorpos++;
|
||||
while (toparse[cursorpos] != ']')
|
||||
{
|
||||
if (toparse[cursorpos] == ',') { cursorpos++; }
|
||||
JSONData arrayItem = String2Data(toparse, ref cursorpos);
|
||||
data.DataArray.Add(arrayItem);
|
||||
}
|
||||
cursorpos++;
|
||||
break;
|
||||
|
||||
//String
|
||||
case '"':
|
||||
data = new JSONData(JSONData.DataType.String);
|
||||
cursorpos++;
|
||||
while (toparse[cursorpos] != '"')
|
||||
{
|
||||
if (toparse[cursorpos] == '\\') { cursorpos++; }
|
||||
data.StringValue += toparse[cursorpos];
|
||||
cursorpos++;
|
||||
}
|
||||
cursorpos++;
|
||||
break;
|
||||
|
||||
//Boolean : true
|
||||
case 't':
|
||||
data = new JSONData(JSONData.DataType.String);
|
||||
cursorpos++;
|
||||
if (toparse[cursorpos] == 'r') { cursorpos++; }
|
||||
if (toparse[cursorpos] == 'u') { cursorpos++; }
|
||||
if (toparse[cursorpos] == 'e') { cursorpos++; data.StringValue = "true"; }
|
||||
break;
|
||||
|
||||
//Boolean : false
|
||||
case 'f':
|
||||
data = new JSONData(JSONData.DataType.String);
|
||||
cursorpos++;
|
||||
if (toparse[cursorpos] == 'a') { cursorpos++; }
|
||||
if (toparse[cursorpos] == 'l') { cursorpos++; }
|
||||
if (toparse[cursorpos] == 's') { cursorpos++; }
|
||||
if (toparse[cursorpos] == 'e') { cursorpos++; data.StringValue = "false"; }
|
||||
break;
|
||||
|
||||
//Unknown data
|
||||
default:
|
||||
cursorpos++;
|
||||
return String2Data(toparse, ref cursorpos);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
catch (IndexOutOfRangeException)
|
||||
{
|
||||
return new JSONData(JSONData.DataType.String);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use a JSON Object to build the corresponding string
|
||||
/// </summary>
|
||||
/// <param name="data">JSON object to convert</param>
|
||||
/// <returns>returns the Minecraft-formatted string</returns>
|
||||
|
||||
private static string JSONData2String(JSONData data)
|
||||
{
|
||||
string colorcode = "";
|
||||
switch (data.Type)
|
||||
{
|
||||
case JSONData.DataType.Object:
|
||||
if (data.Properties.ContainsKey("color"))
|
||||
{
|
||||
colorcode = color2tag(JSONData2String(data.Properties["color"]));
|
||||
}
|
||||
if (data.Properties.ContainsKey("text"))
|
||||
{
|
||||
return colorcode + JSONData2String(data.Properties["text"]) + colorcode;
|
||||
}
|
||||
else if (data.Properties.ContainsKey("translate"))
|
||||
{
|
||||
List<string> using_data = new List<string>();
|
||||
if (data.Properties.ContainsKey("using"))
|
||||
{
|
||||
JSONData[] array = data.Properties["using"].DataArray.ToArray();
|
||||
for (int i = 0; i < array.Length; i++)
|
||||
{
|
||||
using_data.Add(JSONData2String(array[i]));
|
||||
}
|
||||
}
|
||||
return colorcode + TranslateString(JSONData2String(data.Properties["translate"]), using_data) + colorcode;
|
||||
}
|
||||
else return "";
|
||||
|
||||
case JSONData.DataType.Array:
|
||||
string result = "";
|
||||
foreach (JSONData item in data.DataArray)
|
||||
{
|
||||
result += JSONData2String(item);
|
||||
}
|
||||
return result;
|
||||
|
||||
case JSONData.DataType.String:
|
||||
return data.StringValue;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
219
MinecraftClient/ConsoleIO.cs
Normal file
219
MinecraftClient/ConsoleIO.cs
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Allows simultaneous console input and output without breaking user input
|
||||
/// (Without having this annoying behaviour : User inp[Some Console output]ut)
|
||||
/// </summary>
|
||||
|
||||
public static class ConsoleIO
|
||||
{
|
||||
public static void Reset() { if (reading) { reading = false; Console.Write("\b \b"); } }
|
||||
private static LinkedList<string> previous = new LinkedList<string>();
|
||||
private static string buffer = "";
|
||||
private static string buffer2 = "";
|
||||
private static bool consolelock = false;
|
||||
private static bool reading = false;
|
||||
private static bool writing = false;
|
||||
|
||||
#region Read User Input
|
||||
public static string ReadLine()
|
||||
{
|
||||
ConsoleKeyInfo k = new ConsoleKeyInfo();
|
||||
Console.Write('>');
|
||||
reading = true;
|
||||
buffer = "";
|
||||
buffer2 = "";
|
||||
|
||||
while (k.Key != ConsoleKey.Enter)
|
||||
{
|
||||
k = Console.ReadKey(true);
|
||||
while (writing) { }
|
||||
consolelock = true;
|
||||
switch (k.Key)
|
||||
{
|
||||
case ConsoleKey.Escape:
|
||||
ClearLineAndBuffer();
|
||||
break;
|
||||
case ConsoleKey.Backspace:
|
||||
RemoveOneChar();
|
||||
break;
|
||||
case ConsoleKey.Enter:
|
||||
Console.Write('\n');
|
||||
break;
|
||||
case ConsoleKey.LeftArrow:
|
||||
GoLeft();
|
||||
break;
|
||||
case ConsoleKey.RightArrow:
|
||||
GoRight();
|
||||
break;
|
||||
case ConsoleKey.Home:
|
||||
while (buffer.Length > 0) { GoLeft(); }
|
||||
break;
|
||||
case ConsoleKey.End:
|
||||
while (buffer2.Length > 0) { GoRight(); }
|
||||
break;
|
||||
case ConsoleKey.Delete:
|
||||
if (buffer2.Length > 0)
|
||||
{
|
||||
GoRight();
|
||||
RemoveOneChar();
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.Oem6:
|
||||
break;
|
||||
case ConsoleKey.DownArrow:
|
||||
if (previous.Count > 0)
|
||||
{
|
||||
ClearLineAndBuffer();
|
||||
buffer = previous.First.Value;
|
||||
previous.AddLast(buffer);
|
||||
previous.RemoveFirst();
|
||||
Console.Write(buffer);
|
||||
}
|
||||
break;
|
||||
case ConsoleKey.UpArrow:
|
||||
if (previous.Count > 0)
|
||||
{
|
||||
ClearLineAndBuffer();
|
||||
buffer = previous.Last.Value;
|
||||
previous.AddFirst(buffer);
|
||||
previous.RemoveLast();
|
||||
Console.Write(buffer);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
AddChar(k.KeyChar);
|
||||
break;
|
||||
}
|
||||
consolelock = false;
|
||||
}
|
||||
while (writing) { }
|
||||
reading = false;
|
||||
previous.AddLast(buffer + buffer2);
|
||||
return buffer + buffer2;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Console Output
|
||||
public static void Write(string text)
|
||||
{
|
||||
while (consolelock) { }
|
||||
writing = true;
|
||||
if (reading)
|
||||
{
|
||||
ConsoleColor fore = Console.ForegroundColor;
|
||||
ConsoleColor back = Console.BackgroundColor;
|
||||
string buf = buffer;
|
||||
string buf2 = buffer2;
|
||||
ClearLineAndBuffer();
|
||||
if (Console.CursorLeft == 0)
|
||||
{
|
||||
Console.CursorLeft = Console.BufferWidth - 1;
|
||||
Console.CursorTop--;
|
||||
Console.Write(' ');
|
||||
Console.CursorLeft = Console.BufferWidth - 1;
|
||||
Console.CursorTop--;
|
||||
}
|
||||
else Console.Write("\b \b");
|
||||
Console.Write(text);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.BackgroundColor = ConsoleColor.Black;
|
||||
buffer = buf;
|
||||
buffer2 = buf2;
|
||||
Console.Write(">" + buffer);
|
||||
if (buffer2.Length > 0)
|
||||
{
|
||||
Console.Write(buffer2 + " \b");
|
||||
for (int i = 0; i < buffer2.Length; i++) { GoBack(); }
|
||||
}
|
||||
Console.ForegroundColor = fore;
|
||||
Console.BackgroundColor = back;
|
||||
}
|
||||
else Console.Write(text);
|
||||
writing = false;
|
||||
}
|
||||
|
||||
public static void WriteLine(string line)
|
||||
{
|
||||
Write(line + '\n');
|
||||
}
|
||||
|
||||
public static void Write(char c)
|
||||
{
|
||||
Write("" + c);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region subfunctions
|
||||
private static void ClearLineAndBuffer()
|
||||
{
|
||||
while (buffer2.Length > 0) { GoRight(); }
|
||||
while (buffer.Length > 0) { RemoveOneChar(); }
|
||||
}
|
||||
private static void RemoveOneChar()
|
||||
{
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
if (Console.CursorLeft == 0)
|
||||
{
|
||||
Console.CursorLeft = Console.BufferWidth - 1;
|
||||
Console.CursorTop--;
|
||||
Console.Write(' ');
|
||||
Console.CursorLeft = Console.BufferWidth - 1;
|
||||
Console.CursorTop--;
|
||||
}
|
||||
else Console.Write("\b \b");
|
||||
buffer = buffer.Substring(0, buffer.Length - 1);
|
||||
|
||||
if (buffer2.Length > 0)
|
||||
{
|
||||
Console.Write(buffer2 + " \b");
|
||||
for (int i = 0; i < buffer2.Length; i++) { GoBack(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void GoBack()
|
||||
{
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
if (Console.CursorLeft == 0)
|
||||
{
|
||||
Console.CursorLeft = Console.BufferWidth - 1;
|
||||
Console.CursorTop--;
|
||||
}
|
||||
else Console.Write('\b');
|
||||
}
|
||||
}
|
||||
private static void GoLeft()
|
||||
{
|
||||
if (buffer.Length > 0)
|
||||
{
|
||||
buffer2 = "" + buffer[buffer.Length - 1] + buffer2;
|
||||
buffer = buffer.Substring(0, buffer.Length - 1);
|
||||
Console.Write('\b');
|
||||
}
|
||||
}
|
||||
private static void GoRight()
|
||||
{
|
||||
if (buffer2.Length > 0)
|
||||
{
|
||||
buffer = buffer + buffer2[0];
|
||||
Console.Write(buffer2[0]);
|
||||
buffer2 = buffer2.Substring(1);
|
||||
}
|
||||
}
|
||||
private static void AddChar(char c)
|
||||
{
|
||||
Console.Write(c);
|
||||
buffer += c;
|
||||
Console.Write(buffer2);
|
||||
for (int i = 0; i < buffer2.Length; i++) { GoBack(); }
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
203
MinecraftClient/Crypto.cs
Normal file
203
MinecraftClient/Crypto.cs
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Security.Cryptography;
|
||||
using java.security;
|
||||
using java.security.spec;
|
||||
using javax.crypto;
|
||||
using javax.crypto.spec;
|
||||
using Org.BouncyCastle.Crypto;
|
||||
using Org.BouncyCastle.Crypto.Parameters;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Cryptographic functions ported from Minecraft Source Code (Java). Decompiled with MCP. Copy, paste, little adjustements.
|
||||
/// </summary>
|
||||
|
||||
public class Crypto
|
||||
{
|
||||
public static PublicKey GenerateRSAPublicKey(byte[] key)
|
||||
{
|
||||
X509EncodedKeySpec localX509EncodedKeySpec = new X509EncodedKeySpec(key);
|
||||
KeyFactory localKeyFactory = KeyFactory.getInstance("RSA");
|
||||
return localKeyFactory.generatePublic(localX509EncodedKeySpec);
|
||||
}
|
||||
|
||||
public static SecretKey GenerateAESPrivateKey()
|
||||
{
|
||||
CipherKeyGenerator var0 = new CipherKeyGenerator();
|
||||
var0.Init(new KeyGenerationParameters(new Org.BouncyCastle.Security.SecureRandom(), 128));
|
||||
return new SecretKeySpec(var0.GenerateKey(), "AES");
|
||||
}
|
||||
|
||||
public static byte[] getServerHash(String toencode, PublicKey par1PublicKey, SecretKey par2SecretKey)
|
||||
{
|
||||
return digest("SHA-1", new byte[][] { Encoding.GetEncoding("iso-8859-1").GetBytes(toencode), par2SecretKey.getEncoded(), par1PublicKey.getEncoded() });
|
||||
}
|
||||
|
||||
public static byte[] Encrypt(Key par0Key, byte[] par1ArrayOfByte)
|
||||
{
|
||||
return func_75885_a(1, par0Key, par1ArrayOfByte);
|
||||
}
|
||||
|
||||
private static byte[] digest(String par0Str, byte[][] par1ArrayOfByte)
|
||||
{
|
||||
MessageDigest var2 = MessageDigest.getInstance(par0Str);
|
||||
byte[][] var3 = par1ArrayOfByte;
|
||||
int var4 = par1ArrayOfByte.Length;
|
||||
|
||||
for (int var5 = 0; var5 < var4; ++var5)
|
||||
{
|
||||
byte[] var6 = var3[var5];
|
||||
var2.update(var6);
|
||||
}
|
||||
|
||||
return var2.digest();
|
||||
}
|
||||
private static byte[] func_75885_a(int par0, Key par1Key, byte[] par2ArrayOfByte)
|
||||
{
|
||||
try
|
||||
{
|
||||
return cypherencrypt(par0, par1Key.getAlgorithm(), par1Key).doFinal(par2ArrayOfByte);
|
||||
}
|
||||
catch (IllegalBlockSizeException var4)
|
||||
{
|
||||
var4.printStackTrace();
|
||||
}
|
||||
catch (BadPaddingException var5)
|
||||
{
|
||||
var5.printStackTrace();
|
||||
}
|
||||
|
||||
Console.Error.WriteLine("Cipher data failed!");
|
||||
return null;
|
||||
}
|
||||
private static Cipher cypherencrypt(int par0, String par1Str, Key par2Key)
|
||||
{
|
||||
try
|
||||
{
|
||||
Cipher var3 = Cipher.getInstance(par1Str);
|
||||
var3.init(par0, par2Key);
|
||||
return var3;
|
||||
}
|
||||
catch (InvalidKeyException var4)
|
||||
{
|
||||
var4.printStackTrace();
|
||||
}
|
||||
catch (NoSuchAlgorithmException var5)
|
||||
{
|
||||
var5.printStackTrace();
|
||||
}
|
||||
catch (NoSuchPaddingException var6)
|
||||
{
|
||||
var6.printStackTrace();
|
||||
}
|
||||
|
||||
Console.Error.WriteLine("Cipher creation failed!");
|
||||
return null;
|
||||
}
|
||||
|
||||
public static AesStream SwitchToAesMode(System.IO.Stream stream, Key key)
|
||||
{
|
||||
return new AesStream(stream, key.getEncoded());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An encrypted stream using AES
|
||||
/// </summary>
|
||||
|
||||
public class AesStream : System.IO.Stream
|
||||
{
|
||||
CryptoStream enc;
|
||||
CryptoStream dec;
|
||||
public AesStream(System.IO.Stream stream, byte[] key)
|
||||
{
|
||||
BaseStream = stream;
|
||||
enc = new CryptoStream(stream, GenerateAES(key).CreateEncryptor(), CryptoStreamMode.Write);
|
||||
dec = new CryptoStream(stream, GenerateAES(key).CreateDecryptor(), CryptoStreamMode.Read);
|
||||
}
|
||||
public System.IO.Stream BaseStream { get; set; }
|
||||
|
||||
public override bool CanRead
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override bool CanSeek
|
||||
{
|
||||
get { return false; }
|
||||
}
|
||||
|
||||
public override bool CanWrite
|
||||
{
|
||||
get { return true; }
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
BaseStream.Flush();
|
||||
}
|
||||
|
||||
public override long Length
|
||||
{
|
||||
get { throw new NotSupportedException(); }
|
||||
}
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
set
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
|
||||
public override int ReadByte()
|
||||
{
|
||||
return dec.ReadByte();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
return dec.Read(buffer, offset, count);
|
||||
}
|
||||
|
||||
public override long Seek(long offset, System.IO.SeekOrigin origin)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
public override void WriteByte(byte b)
|
||||
{
|
||||
enc.WriteByte(b);
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
enc.Write(buffer, offset, count);
|
||||
}
|
||||
|
||||
private RijndaelManaged GenerateAES(byte[] key)
|
||||
{
|
||||
RijndaelManaged cipher = new RijndaelManaged();
|
||||
cipher.Mode = CipherMode.CFB;
|
||||
cipher.Padding = PaddingMode.None;
|
||||
cipher.KeySize = 128;
|
||||
cipher.FeedbackSize = 8;
|
||||
cipher.Key = key;
|
||||
cipher.IV = key;
|
||||
return cipher;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
MinecraftClient/IKVM.OpenJDK.Core.dll
Normal file
BIN
MinecraftClient/IKVM.OpenJDK.Core.dll
Normal file
Binary file not shown.
BIN
MinecraftClient/IKVM.OpenJDK.Security.dll
Normal file
BIN
MinecraftClient/IKVM.OpenJDK.Security.dll
Normal file
Binary file not shown.
BIN
MinecraftClient/IKVM.OpenJDK.Util.dll
Normal file
BIN
MinecraftClient/IKVM.OpenJDK.Util.dll
Normal file
Binary file not shown.
BIN
MinecraftClient/IKVM.Runtime.dll
Normal file
BIN
MinecraftClient/IKVM.Runtime.dll
Normal file
Binary file not shown.
243
MinecraftClient/McTcpClient.cs
Normal file
243
MinecraftClient/McTcpClient.cs
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
/// <summary>
|
||||
/// The main client class, used to connect to a Minecraft server.
|
||||
/// It allows message sending and text receiving.
|
||||
/// </summary>
|
||||
|
||||
class McTcpClient
|
||||
{
|
||||
public static int AttemptsLeft = 0;
|
||||
|
||||
string host;
|
||||
int port;
|
||||
string username;
|
||||
string text;
|
||||
Thread t_updater;
|
||||
Thread t_sender;
|
||||
TcpClient client;
|
||||
MinecraftCom handler;
|
||||
|
||||
/// <summary>
|
||||
/// Starts the main chat client, wich will login to the server using the MinecraftCom class.
|
||||
/// </summary>
|
||||
/// <param name="username">The chosen username of a premium Minecraft Account</param>
|
||||
/// <param name="sessionID">A valid sessionID obtained with MinecraftCom.GetLogin()</param>
|
||||
/// <param name="server_port">The server IP (serveradress or serveradress:port)</param>
|
||||
|
||||
public McTcpClient(string username, string sessionID, string server_port, MinecraftCom handler)
|
||||
{
|
||||
StartClient(username, sessionID, server_port, false, handler, "");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the main chat client in single command sending mode, wich will login to the server using the MinecraftCom class, send the command and close.
|
||||
/// </summary>
|
||||
/// <param name="username">The chosen username of a premium Minecraft Account</param>
|
||||
/// <param name="sessionID">A valid sessionID obtained with MinecraftCom.GetLogin()</param>
|
||||
/// <param name="server_port">The server IP (serveradress or serveradress:port)</param>
|
||||
/// <param name="command">The text or command to send.</param>
|
||||
|
||||
public McTcpClient(string username, string sessionID, string server_port, MinecraftCom handler, string command)
|
||||
{
|
||||
StartClient(username, sessionID, server_port, true, handler, command);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Starts the main chat client, wich will login to the server using the MinecraftCom class.
|
||||
/// </summary>
|
||||
/// <param name="user">The chosen username of a premium Minecraft Account</param>
|
||||
/// <param name="sessionID">A valid sessionID obtained with MinecraftCom.GetLogin()</param>
|
||||
/// <param name="server_port">The server IP (serveradress or serveradress:port)/param>
|
||||
/// <param name="singlecommand">If set to true, the client will send a single command and then disconnect from the server</param>
|
||||
/// <param name="command">The text or command to send. Will only be sent if singlecommand is set to true.</param>
|
||||
|
||||
private void StartClient(string user, string sessionID, string server_port, bool singlecommand, MinecraftCom handler, string command)
|
||||
{
|
||||
this.handler = handler;
|
||||
username = user;
|
||||
string[] sip = server_port.Split(':');
|
||||
host = sip[0];
|
||||
if (sip.Length == 1)
|
||||
{
|
||||
port = 25565;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
port = Convert.ToInt32(sip[1]);
|
||||
}
|
||||
catch (FormatException) { port = 25565; }
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Connecting...");
|
||||
client = new TcpClient(host, port);
|
||||
client.ReceiveBufferSize = 1024 * 1024;
|
||||
handler.setClient(client);
|
||||
byte[] token = new byte[1]; string serverID = "";
|
||||
if (handler.Handshake(user, sessionID, ref serverID, ref token, host, port))
|
||||
{
|
||||
Console.WriteLine("Logging in...");
|
||||
|
||||
if (handler.FinalizeLogin())
|
||||
{
|
||||
//Single command sending
|
||||
if (singlecommand)
|
||||
{
|
||||
handler.SendChatMessage(command);
|
||||
Console.Write("Command ");
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
Console.Write(command);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.WriteLine(" sent.");
|
||||
Thread.Sleep(5000);
|
||||
handler.Disconnect("disconnect.quitting");
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Server was successfuly joined.\nType '/quit' to leave the server.");
|
||||
|
||||
//Command sending thread, allowing user input
|
||||
t_sender = new Thread(new ThreadStart(StartTalk));
|
||||
t_sender.Name = "CommandSender";
|
||||
t_sender.Start();
|
||||
|
||||
//Data receiving thread, allowing text receiving
|
||||
t_updater = new Thread(new ThreadStart(Updater));
|
||||
t_updater.Name = "PacketHandler";
|
||||
t_updater.Start();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Login failed.");
|
||||
if (!singlecommand) { Program.ReadLineReconnect(); }
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid session ID.");
|
||||
if (!singlecommand) { Program.ReadLineReconnect(); }
|
||||
}
|
||||
}
|
||||
catch (SocketException)
|
||||
{
|
||||
Console.WriteLine("Failed to connect to this IP.");
|
||||
if (AttemptsLeft > 0)
|
||||
{
|
||||
ChatBot.LogToConsole("Waiting 5 seconds (" + AttemptsLeft + " attempts left)...");
|
||||
Thread.Sleep(5000); AttemptsLeft--; Program.Restart();
|
||||
}
|
||||
else if (!singlecommand){ Console.ReadLine(); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Allows the user to send chat messages, commands, and to leave the server.
|
||||
/// Will be automatically called on a separate Thread by StartClient()
|
||||
/// </summary>
|
||||
|
||||
private void StartTalk()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (client.Client.Connected)
|
||||
{
|
||||
text = ConsoleIO.ReadLine();
|
||||
if (text == "/quit" || text == "/reco" || text == "/reconnect") { break; }
|
||||
while (text.Length > 0 && text[0] == ' ') { text = text.Substring(1); }
|
||||
if (text != "")
|
||||
{
|
||||
//Message is too long
|
||||
if (text.Length > 100)
|
||||
{
|
||||
if (text[0] == '/')
|
||||
{
|
||||
//Send the first 100 chars of the command
|
||||
text = text.Substring(0, 100);
|
||||
handler.SendChatMessage(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
//Send the message splitted in sereval messages
|
||||
while (text.Length > 100)
|
||||
{
|
||||
handler.SendChatMessage(text.Substring(0, 100));
|
||||
text = text.Substring(100, text.Length - 100);
|
||||
}
|
||||
handler.SendChatMessage(text);
|
||||
}
|
||||
}
|
||||
else handler.SendChatMessage(text);
|
||||
}
|
||||
}
|
||||
|
||||
if (text == "/quit")
|
||||
{
|
||||
ConsoleIO.WriteLine("You have left the server.");
|
||||
Disconnect();
|
||||
}
|
||||
|
||||
else if (text == "/reco" || text == "/reconnect")
|
||||
{
|
||||
ConsoleIO.WriteLine("You have left the server.");
|
||||
Program.Restart();
|
||||
}
|
||||
}
|
||||
catch (IOException) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Receive the data (including chat messages) from the server, and keep the connection alive.
|
||||
/// Will be automatically called on a separate Thread by StartClient()
|
||||
/// </summary>
|
||||
|
||||
private void Updater()
|
||||
{
|
||||
try
|
||||
{
|
||||
//handler.DebugDump();
|
||||
do
|
||||
{
|
||||
Thread.Sleep(100);
|
||||
} while (handler.Update());
|
||||
}
|
||||
catch (IOException) { }
|
||||
catch (SocketException) { }
|
||||
catch (ObjectDisposedException) { }
|
||||
|
||||
if (!handler.HasBeenKicked)
|
||||
{
|
||||
ConsoleIO.WriteLine("Connection has been lost.");
|
||||
if (!handler.OnConnectionLost() && !Program.ReadLineReconnect()) { t_sender.Abort(); }
|
||||
}
|
||||
else if (Program.ReadLineReconnect()) { t_sender.Abort(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect the client from the server
|
||||
/// </summary>
|
||||
|
||||
public void Disconnect()
|
||||
{
|
||||
handler.Disconnect("disconnect.quitting");
|
||||
Thread.Sleep(1000);
|
||||
if (t_updater != null) { t_updater.Abort(); }
|
||||
if (t_sender != null) { t_sender.Abort(); }
|
||||
if (client != null) { client.Close(); }
|
||||
}
|
||||
}
|
||||
}
|
||||
127
MinecraftClient/MinecraftClient.csproj
Normal file
127
MinecraftClient/MinecraftClient.csproj
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">x86</Platform>
|
||||
<ProductVersion>8.0.30703</ProductVersion>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<ProjectGuid>{1E2FACE4-F5CA-4323-9641-740C6A551770}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||
<RootNamespace>MinecraftClient</RootNamespace>
|
||||
<AssemblyName>MinecraftClient</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<TargetFrameworkProfile>Client</TargetFrameworkProfile>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<PublishUrl>publish\</PublishUrl>
|
||||
<Install>true</Install>
|
||||
<InstallFrom>Disk</InstallFrom>
|
||||
<UpdateEnabled>false</UpdateEnabled>
|
||||
<UpdateMode>Foreground</UpdateMode>
|
||||
<UpdateInterval>7</UpdateInterval>
|
||||
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
|
||||
<UpdatePeriodically>false</UpdatePeriodically>
|
||||
<UpdateRequired>false</UpdateRequired>
|
||||
<MapFileExtensions>true</MapFileExtensions>
|
||||
<ApplicationRevision>0</ApplicationRevision>
|
||||
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
|
||||
<IsWebBootstrapper>false</IsWebBootstrapper>
|
||||
<UseApplicationTrust>false</UseApplicationTrust>
|
||||
<BootstrapperEnabled>true</BootstrapperEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
|
||||
<PlatformTarget>x86</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup />
|
||||
<PropertyGroup>
|
||||
<SignManifests>false</SignManifests>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="BouncyCastle.Crypto, Version=1.7.4114.6375, Culture=neutral, PublicKeyToken=0e99375e54769942">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>.\BouncyCastle.Crypto.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="IKVM.OpenJDK.Core, Version=7.0.4335.0, Culture=neutral, PublicKeyToken=13235d27fcbfff58, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>.\IKVM.OpenJDK.Core.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="IKVM.OpenJDK.Security, Version=7.0.4335.0, Culture=neutral, PublicKeyToken=13235d27fcbfff58, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>.\IKVM.OpenJDK.Security.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="IKVM.OpenJDK.Util, Version=7.0.4335.0, Culture=neutral, PublicKeyToken=13235d27fcbfff58, processorArchitecture=MSIL">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>.\IKVM.OpenJDK.Util.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Bots.cs" />
|
||||
<Compile Include="ConsoleIO.cs" />
|
||||
<Compile Include="Crypto.cs" />
|
||||
<Compile Include="ChatParser.cs" />
|
||||
<Compile Include="MinecraftCom.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="McTcpClient.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include=".NETFramework,Version=v4.0,Profile=Client">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Microsoft .NET Framework 4 Client Profile %28x86 and x64%29</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>.NET Framework 3.5 SP1</ProductName>
|
||||
<Install>false</Install>
|
||||
</BootstrapperPackage>
|
||||
<BootstrapperPackage Include="Microsoft.Windows.Installer.3.1">
|
||||
<Visible>False</Visible>
|
||||
<ProductName>Windows Installer 3.1</ProductName>
|
||||
<Install>true</Install>
|
||||
</BootstrapperPackage>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="BouncyCastle.Crypto.dll" />
|
||||
<Content Include="IKVM.OpenJDK.Core.dll" />
|
||||
<Content Include="IKVM.OpenJDK.Security.dll" />
|
||||
<Content Include="IKVM.OpenJDK.Util.dll" />
|
||||
<Content Include="IKVM.Runtime.dll" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||
Other similar extension points exist, see Microsoft.Common.targets.
|
||||
<Target Name="BeforeBuild">
|
||||
</Target>
|
||||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
21
MinecraftClient/MinecraftClient.csproj.user
Normal file
21
MinecraftClient/MinecraftClient.csproj.user
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
|
||||
<StartArguments>
|
||||
</StartArguments>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<PublishUrlHistory>publish\</PublishUrlHistory>
|
||||
<InstallUrlHistory />
|
||||
<SupportUrlHistory />
|
||||
<UpdateUrlHistory />
|
||||
<BootstrapperUrlHistory />
|
||||
<ErrorReportUrlHistory />
|
||||
<FallbackCulture>en-US</FallbackCulture>
|
||||
<VerifyUploadedFiles>false</VerifyUploadedFiles>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
|
||||
<StartArguments>
|
||||
</StartArguments>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
825
MinecraftClient/MinecraftCom.cs
Normal file
825
MinecraftClient/MinecraftCom.cs
Normal file
|
|
@ -0,0 +1,825 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
/// <summary>
|
||||
/// The class containing all the core functions needed to communicate with a Minecraft server.
|
||||
/// </summary>
|
||||
|
||||
public class MinecraftCom
|
||||
{
|
||||
#region Login to Minecraft.net, Obtaining a session ID
|
||||
|
||||
public enum LoginResult { Error, Success, WrongPassword, Blocked, AccountMigrated, NotPremium };
|
||||
|
||||
/// <summary>
|
||||
/// Allows to login to a premium Minecraft account, and retrieve the session ID.
|
||||
/// </summary>
|
||||
/// <param name="user">Login</param>
|
||||
/// <param name="pass">Password</param>
|
||||
/// <param name="outdata">Will contain the data returned by Minecraft.net, if the login is successful : Version:UpdateTicket:Username:SessionID</param>
|
||||
/// <returns>Returns the status of the login (Success, Failure, etc.)</returns>
|
||||
|
||||
public static LoginResult GetLogin(string user, string pass, ref string outdata)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
WebClient wClient = new WebClient();
|
||||
Console.WriteLine("https://login.minecraft.net/?user=" + user + "&password=<******>&version=13");
|
||||
string result = wClient.DownloadString("https://login.minecraft.net/?user=" + user + "&password=" + pass + "&version=13");
|
||||
outdata = result;
|
||||
Console.WriteLine(result);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
if (result == "Bad login") { return LoginResult.WrongPassword; }
|
||||
if (result == "User not premium") { return LoginResult.NotPremium; }
|
||||
if (result == "Too many failed logins") { return LoginResult.Blocked; }
|
||||
if (result == "Account migrated, use e-mail as username.") { return LoginResult.AccountMigrated; }
|
||||
else return LoginResult.Success;
|
||||
}
|
||||
catch (WebException) { return LoginResult.Error; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keep-Alive for a Minecraft.net session, should be called every 5 minutes (currently unused)
|
||||
|
||||
/// <summary>
|
||||
/// The session ID will expire within 5 minutes unless this function is called every 5 minutes
|
||||
/// </summary>
|
||||
/// <param name="user">Username</param>
|
||||
/// <param name="sessionID">Session ID to keep alive</param>
|
||||
|
||||
public static void SessionKeepAlive(string user, string sessionID)
|
||||
{
|
||||
new WebClient().DownloadString("https://login.minecraft.net/session?name=" + user + "&session=" + sessionID);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Session checking when joining a server in online mode
|
||||
|
||||
/// <summary>
|
||||
/// This method allows to join an online-mode server.
|
||||
/// It Should be called between the handshake and the login attempt.
|
||||
/// </summary>
|
||||
/// <param name="user">Username</param>
|
||||
/// <param name="sessionID">A valid session ID for this username</param>
|
||||
/// <param name="hash">Hash returned by the server during the handshake</param>
|
||||
/// <returns>Returns true if the check was successful</returns>
|
||||
|
||||
public static bool SessionCheck(string user, string sessionID, string hash)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
WebClient client = new WebClient();
|
||||
Console.Write("http://session.minecraft.net/game/joinserver.jsp?user=" + user + "&sessionId=" + sessionID + "&serverId=" + hash + " ... ");
|
||||
string result = client.DownloadString("http://session.minecraft.net/game/joinserver.jsp?user=" + user + "&sessionId=" + sessionID + "&serverId=" + hash);
|
||||
Console.WriteLine(result);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
return (result == "OK");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Server-side session checking (programmed for testing purposes)
|
||||
|
||||
/// <summary>
|
||||
/// Reproduces the username checking done by an online-mode server during the login process.
|
||||
/// </summary>
|
||||
/// <param name="user">Username</param>
|
||||
/// <param name="hash">Hash sent by the server during the handshake</param>
|
||||
/// <returns>Returns true if the user is allowed to join the server</returns>
|
||||
|
||||
public static bool ServerSessionCheck(string user, string hash)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
WebClient client = new WebClient();
|
||||
ConsoleIO.WriteLine("http://session.minecraft.net/game/checkserver.jsp?user=" + user + "&serverId=" + hash);
|
||||
string result = client.DownloadString("http://session.minecraft.net/game/checkserver.jsp?user=" + user + "&serverId=" + hash);
|
||||
ConsoleIO.WriteLine(result);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
return (result == "YES");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
TcpClient c = new TcpClient();
|
||||
Crypto.AesStream s;
|
||||
|
||||
public bool HasBeenKicked { get { return connectionlost; } }
|
||||
bool connectionlost = false;
|
||||
bool encrypted = false;
|
||||
byte protocolversion;
|
||||
|
||||
public bool Update()
|
||||
{
|
||||
for (int i = 0; i < bots.Count; i++) { bots[i].Update(); }
|
||||
if (c.Client == null || !c.Connected) { return false; }
|
||||
byte id = 0;
|
||||
|
||||
try
|
||||
{
|
||||
while (c.Client.Available > 0)
|
||||
{
|
||||
id = readNextByte();
|
||||
ProcessResult result = processPacket(id);
|
||||
|
||||
//Debug : Print packet IDs that are beign processed. Green = OK, Red = Unknown packet
|
||||
//If the client gets out of sync, check the last green packet processing code.
|
||||
//if (result == ProcessResult.OK) { printstring("§a0x" + id.ToString("X"), false); }
|
||||
//else { printstring("§c0x" + id.ToString("X"), false); }
|
||||
|
||||
if (result == ProcessResult.ConnectionLost)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SocketException) { return false; }
|
||||
return true;
|
||||
}
|
||||
public void DebugDump()
|
||||
{
|
||||
byte[] cache = new byte[128000];
|
||||
Receive(cache, 0, 128000, SocketFlags.None);
|
||||
string dump = BitConverter.ToString(cache);
|
||||
System.IO.File.WriteAllText("debug.txt", dump);
|
||||
System.Diagnostics.Process.Start("debug.txt");
|
||||
}
|
||||
public bool OnConnectionLost()
|
||||
{
|
||||
if (!connectionlost)
|
||||
{
|
||||
connectionlost = true;
|
||||
for (int i = 0; i < bots.Count; i++)
|
||||
{
|
||||
if (bots[i].OnDisconnect(ChatBot.DisconnectReason.ConnectionLost, "Connection has been lost."))
|
||||
{
|
||||
return true; //The client is about to restart
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private enum ProcessResult { OK, ConnectionLost, UnknownPacket }
|
||||
private ProcessResult processPacket(int id)
|
||||
{
|
||||
int nbr = 0;
|
||||
switch (id)
|
||||
{
|
||||
case 0x00: byte[] keepalive = new byte[5] { 0, 0, 0, 0, 0 };
|
||||
Receive(keepalive, 1, 4, SocketFlags.None);
|
||||
Send(keepalive); break;
|
||||
case 0x01: readData(4); readNextString(); readData(5); break;
|
||||
case 0x02: readData(1); readNextString(); readNextString(); readData(4); break;
|
||||
case 0x03:
|
||||
string message = readNextString();
|
||||
if (protocolversion >= 72)
|
||||
{
|
||||
//printstring("§8" + message, false); //Debug
|
||||
message = ChatParser.ParseText(message);
|
||||
printstring(message, false);
|
||||
}
|
||||
else printstring(message, false);
|
||||
for (int i = 0; i < bots.Count; i++) { bots[i].GetText(message); } break;
|
||||
case 0x04: readData(16); break;
|
||||
case 0x05: readData(6); readNextItemSlot(); break;
|
||||
case 0x06: readData(12); break;
|
||||
case 0x07: readData(9); break;
|
||||
case 0x08: if (protocolversion >= 72) { readData(10); } else readData(8); break;
|
||||
case 0x09: readData(8); readNextString(); break;
|
||||
case 0x0A: readData(1); break;
|
||||
case 0x0B: readData(33); break;
|
||||
case 0x0C: readData(9); break;
|
||||
case 0x0D: readData(41); break;
|
||||
case 0x0E: readData(11); break;
|
||||
case 0x0F: readData(10); readNextItemSlot(); readData(3); break;
|
||||
case 0x10: readData(2); break;
|
||||
case 0x11: readData(14); break;
|
||||
case 0x12: readData(5); break;
|
||||
case 0x13: if (protocolversion >= 72) { readData(9); } else readData(5); break;
|
||||
case 0x14: readData(4); readNextString(); readData(16); readNextEntityMetaData(); break;
|
||||
case 0x16: readData(8); break;
|
||||
case 0x17: readData(19); readNextObjectData(); break;
|
||||
case 0x18: readData(26); readNextEntityMetaData(); break;
|
||||
case 0x19: readData(4); readNextString(); readData(16); break;
|
||||
case 0x1A: readData(18); break;
|
||||
case 0x1B: if (protocolversion >= 72) { readData(10); } break;
|
||||
case 0x1C: readData(10); break;
|
||||
case 0x1D: nbr = (int)readNextByte(); readData(nbr * 4); break;
|
||||
case 0x1E: readData(4); break;
|
||||
case 0x1F: readData(7); break;
|
||||
case 0x20: readData(6); break;
|
||||
case 0x21: readData(9); break;
|
||||
case 0x22: readData(18); break;
|
||||
case 0x23: readData(5); break;
|
||||
case 0x26: readData(5); break;
|
||||
case 0x27: if (protocolversion >= 72) { readData(9); } else readData(8); break;
|
||||
case 0x28: readData(4); readNextEntityMetaData(); break;
|
||||
case 0x29: readData(8); break;
|
||||
case 0x2A: readData(5); break;
|
||||
case 0x2B: readData(8); break;
|
||||
case 0x2C: if (protocolversion >= 72) { readNextEntityProperties(protocolversion); } break;
|
||||
case 0x33: readData(13); nbr = readNextInt(); readData(nbr); break;
|
||||
case 0x34: readData(10); nbr = readNextInt(); readData(nbr); break;
|
||||
case 0x35: readData(12); break;
|
||||
case 0x36: readData(14); break;
|
||||
case 0x37: readData(17); break;
|
||||
case 0x38: readNextChunkBulkData(); break;
|
||||
case 0x3C: readData(28); nbr = readNextInt(); readData(3 * nbr); readData(12); break;
|
||||
case 0x3D: readData(18); break;
|
||||
case 0x3E: readNextString(); readData(17); break;
|
||||
case 0x3F: if (protocolversion > 51) { readNextString(); readData(32); } break;
|
||||
case 0x46: readData(2); break;
|
||||
case 0x47: readData(17); break;
|
||||
case 0x64: readNextWindowData(protocolversion); break;
|
||||
case 0x65: readData(1); break;
|
||||
case 0x66: readData(7); readNextItemSlot(); break;
|
||||
case 0x67: readData(3); readNextItemSlot(); break;
|
||||
case 0x68: readData(1); for (nbr = readNextShort(); nbr > 0; nbr--) { readNextItemSlot(); } break;
|
||||
case 0x69: readData(5); break;
|
||||
case 0x6A: readData(4); break;
|
||||
case 0x6B: readData(2); readNextItemSlot(); break;
|
||||
case 0x6C: readData(2); break;
|
||||
case 0x82: readData(10); readNextString(); readNextString(); readNextString(); readNextString(); break;
|
||||
case 0x83: readData(4); nbr = readNextShort(); readData(nbr); break;
|
||||
case 0x84: readData(11); nbr = readNextShort(); if (nbr > 0) { readData(nbr); } break;
|
||||
case 0x85: if (protocolversion >= 74) { readData(13); } break;
|
||||
case 0xC8: if (protocolversion >= 72) { readData(8); } else readData(5); break;
|
||||
case 0xC9: readNextString(); readData(3); break;
|
||||
case 0xCA: if (protocolversion >= 72) { readData(9); } else readData(3); break;
|
||||
case 0xCB: readNextString(); break;
|
||||
case 0xCC: readNextString(); readData(4); break;
|
||||
case 0xCD: readData(1); break;
|
||||
case 0xCE: if (protocolversion > 51) { readNextString(); readNextString(); readData(1); } break;
|
||||
case 0xCF: if (protocolversion > 51) { readNextString(); readData(1); readNextString(); } readData(4); break;
|
||||
case 0xD0: if (protocolversion > 51) { readData(1); readNextString(); } break;
|
||||
case 0xD1: if (protocolversion > 51) { readNextTeamData(); } break;
|
||||
case 0xFA: readNextString(); nbr = readNextShort(); readData(nbr); break;
|
||||
case 0xFF: string reason = readNextString();
|
||||
ConsoleIO.WriteLine("Disconnected by Server :"); printstring(reason, true); connectionlost = true;
|
||||
for (int i = 0; i < bots.Count; i++) { bots[i].OnDisconnect(ChatBot.DisconnectReason.InGameKick, reason); } return ProcessResult.ConnectionLost;
|
||||
default: return ProcessResult.UnknownPacket; //unknown packet!
|
||||
}
|
||||
return ProcessResult.OK; //packet has been successfully skipped
|
||||
}
|
||||
private void readData(int offset)
|
||||
{
|
||||
if (offset > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] cache = new byte[offset];
|
||||
Receive(cache, 0, offset, SocketFlags.None);
|
||||
}
|
||||
catch (OutOfMemoryException) { }
|
||||
}
|
||||
}
|
||||
private string readNextString()
|
||||
{
|
||||
short lenght = readNextShort();
|
||||
if (lenght > 0)
|
||||
{
|
||||
byte[] cache = new byte[lenght * 2];
|
||||
Receive(cache, 0, lenght * 2, SocketFlags.None);
|
||||
string result = ByteArrayToString(cache);
|
||||
return result;
|
||||
}
|
||||
else return "";
|
||||
}
|
||||
private byte[] readNextByteArray()
|
||||
{
|
||||
short len = readNextShort();
|
||||
byte[] data = new byte[len];
|
||||
Receive(data, 0, len, SocketFlags.None);
|
||||
return data;
|
||||
}
|
||||
private short readNextShort()
|
||||
{
|
||||
byte[] tmp = new byte[2];
|
||||
Receive(tmp, 0, 2, SocketFlags.None);
|
||||
Array.Reverse(tmp);
|
||||
return BitConverter.ToInt16(tmp, 0);
|
||||
}
|
||||
private int readNextInt()
|
||||
{
|
||||
byte[] tmp = new byte[4];
|
||||
Receive(tmp, 0, 4, SocketFlags.None);
|
||||
Array.Reverse(tmp);
|
||||
return BitConverter.ToInt32(tmp, 0);
|
||||
}
|
||||
private byte readNextByte()
|
||||
{
|
||||
byte[] result = new byte[1];
|
||||
Receive(result, 0, 1, SocketFlags.None);
|
||||
return result[0];
|
||||
}
|
||||
private void readNextItemSlot()
|
||||
{
|
||||
short itemid = readNextShort();
|
||||
//If slot not empty (item ID != -1)
|
||||
if (itemid != -1)
|
||||
{
|
||||
readData(1); //Item count
|
||||
readData(2); //Item damage
|
||||
short length = readNextShort();
|
||||
//If lenght of optional NBT data > 0, read it
|
||||
if (length > 0) { readData(length); }
|
||||
}
|
||||
}
|
||||
private void readNextEntityMetaData()
|
||||
{
|
||||
do
|
||||
{
|
||||
byte[] id = new byte[1];
|
||||
Receive(id, 0, 1, SocketFlags.None);
|
||||
if (id[0] == 0x7F) { break; }
|
||||
int index = id[0] & 0x1F;
|
||||
int type = id[0] >> 5;
|
||||
switch (type)
|
||||
{
|
||||
case 0: readData(1); break; //Byte
|
||||
case 1: readData(2); break; //Short
|
||||
case 2: readData(4); break; //Int
|
||||
case 3: readData(4); break; //Float
|
||||
case 4: readNextString(); break; //String
|
||||
case 5: readNextItemSlot(); break; //Slot
|
||||
case 6: readData(12); break; //Vector (3 Int)
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
private void readNextObjectData()
|
||||
{
|
||||
int id = readNextInt();
|
||||
if (id != 0) { readData(6); }
|
||||
}
|
||||
private void readNextTeamData()
|
||||
{
|
||||
readNextString(); //Internal Name
|
||||
byte mode = readNextByte();
|
||||
|
||||
if (mode == 0 || mode == 2)
|
||||
{
|
||||
readNextString(); //Display Name
|
||||
readNextString(); //Prefix
|
||||
readNextString(); //Suffix
|
||||
readData(1); //Friendly Fire
|
||||
}
|
||||
|
||||
if (mode == 0 || mode == 3 || mode == 4)
|
||||
{
|
||||
short count = readNextShort();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
readNextString(); //Players
|
||||
}
|
||||
}
|
||||
}
|
||||
private void readNextEntityProperties(int protocolversion)
|
||||
{
|
||||
if (protocolversion >= 72)
|
||||
{
|
||||
if (protocolversion >= 74)
|
||||
{
|
||||
//Minecraft 1.6.2
|
||||
readNextInt(); //Entity ID
|
||||
int count = readNextInt();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
readNextString(); //Property name
|
||||
readData(8); //Property value (Double)
|
||||
short othercount = readNextShort();
|
||||
readData(25 * othercount);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Minecraft 1.6.0 / 1.6.1
|
||||
readNextInt(); //Entity ID
|
||||
int count = readNextInt();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
readNextString(); //Property name
|
||||
readData(8); //Property value (Double)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private void readNextWindowData(int protocolversion)
|
||||
{
|
||||
readData(1);
|
||||
byte windowtype = readNextByte();
|
||||
readNextString();
|
||||
readData(1);
|
||||
if (protocolversion > 51)
|
||||
{
|
||||
readData(1);
|
||||
if (protocolversion >= 72 && windowtype == 0xb)
|
||||
{
|
||||
readNextInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
private void readNextChunkBulkData()
|
||||
{
|
||||
short chunkcount = readNextShort();
|
||||
int datalen = readNextInt();
|
||||
readData(1);
|
||||
readData(datalen);
|
||||
readData(12 * (chunkcount));
|
||||
}
|
||||
|
||||
private void setcolor(char c)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '0': Console.ForegroundColor = ConsoleColor.Gray; break; //Should be Black but Black is non-readable on a black background
|
||||
case '1': Console.ForegroundColor = ConsoleColor.DarkBlue; break;
|
||||
case '2': Console.ForegroundColor = ConsoleColor.DarkGreen; break;
|
||||
case '3': Console.ForegroundColor = ConsoleColor.DarkCyan; break;
|
||||
case '4': Console.ForegroundColor = ConsoleColor.DarkRed; break;
|
||||
case '5': Console.ForegroundColor = ConsoleColor.DarkMagenta; break;
|
||||
case '6': Console.ForegroundColor = ConsoleColor.DarkYellow; break;
|
||||
case '7': Console.ForegroundColor = ConsoleColor.Gray; break;
|
||||
case '8': Console.ForegroundColor = ConsoleColor.DarkGray; break;
|
||||
case '9': Console.ForegroundColor = ConsoleColor.Blue; break;
|
||||
case 'a': Console.ForegroundColor = ConsoleColor.Green; break;
|
||||
case 'b': Console.ForegroundColor = ConsoleColor.Cyan; break;
|
||||
case 'c': Console.ForegroundColor = ConsoleColor.Red; break;
|
||||
case 'd': Console.ForegroundColor = ConsoleColor.Magenta; break;
|
||||
case 'e': Console.ForegroundColor = ConsoleColor.Yellow; break;
|
||||
case 'f': Console.ForegroundColor = ConsoleColor.White; break;
|
||||
case 'r': Console.ForegroundColor = ConsoleColor.White; break;
|
||||
}
|
||||
}
|
||||
private void printstring(string str, bool acceptnewlines)
|
||||
{
|
||||
if (str != "")
|
||||
{
|
||||
char prev = ' ';
|
||||
foreach (char c in str)
|
||||
{
|
||||
if (c == '§')
|
||||
{
|
||||
prev = c;
|
||||
continue;
|
||||
}
|
||||
else if (prev == '§')
|
||||
{
|
||||
setcolor(c);
|
||||
prev = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (c == '\n' && !acceptnewlines) { continue; }
|
||||
else ConsoleIO.Write(c);
|
||||
}
|
||||
}
|
||||
ConsoleIO.Write('\n');
|
||||
}
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
private string ReverseString(string a)
|
||||
{
|
||||
char[] tmp = a.ToCharArray();
|
||||
Array.Reverse(tmp);
|
||||
return new string(tmp);
|
||||
}
|
||||
private string ByteArrayToString(byte[] ba)
|
||||
{
|
||||
string conv = "";
|
||||
for (int i = 1; i < ba.Length; i += 2)
|
||||
{
|
||||
conv += (char)ba[i];
|
||||
}
|
||||
return conv;
|
||||
}
|
||||
|
||||
public void setVersion(byte ver) { protocolversion = ver; }
|
||||
public void setClient(TcpClient n) { c = n; }
|
||||
private void setEncryptedClient(Crypto.AesStream n) { s = n; encrypted = true; }
|
||||
private void Receive(byte[] buffer, int start, int offset, SocketFlags f)
|
||||
{
|
||||
while (c.Client.Available < start + offset) { }
|
||||
if (encrypted)
|
||||
{
|
||||
s.Read(buffer, start, offset);
|
||||
}
|
||||
else c.Client.Receive(buffer, start, offset, f);
|
||||
}
|
||||
private void Send(byte[] buffer)
|
||||
{
|
||||
if (encrypted)
|
||||
{
|
||||
s.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
else c.Client.Send(buffer);
|
||||
}
|
||||
|
||||
public static bool GetServerInfo(string serverIP, ref byte protocolversion, ref string version)
|
||||
{
|
||||
try
|
||||
{
|
||||
string host; int port;
|
||||
string[] sip = serverIP.Split(':');
|
||||
host = sip[0];
|
||||
|
||||
if (sip.Length == 1)
|
||||
{
|
||||
port = 25565;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
port = Convert.ToInt32(sip[1]);
|
||||
}
|
||||
catch (FormatException) { port = 25565; }
|
||||
}
|
||||
|
||||
TcpClient tcp = new TcpClient(host, port);
|
||||
byte[] ping = new byte[2] { 0xfe, 0x01 };
|
||||
tcp.Client.Send(ping, SocketFlags.None);
|
||||
|
||||
tcp.Client.Receive(ping, 0, 1, SocketFlags.None);
|
||||
if (ping[0] == 0xff)
|
||||
{
|
||||
MinecraftCom ComTmp = new MinecraftCom();
|
||||
ComTmp.setClient(tcp);
|
||||
string result = ComTmp.readNextString();
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
//Console.WriteLine(result.Replace((char)0x00, ' '));
|
||||
if (result.Length > 2 && result[0] == '§' && result[1] == '1')
|
||||
{
|
||||
string[] tmp = result.Split((char)0x00);
|
||||
protocolversion = (byte)Int16.Parse(tmp[1]);
|
||||
version = tmp[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
protocolversion = (byte)39;
|
||||
version = "B1.8.1 - 1.3.2";
|
||||
}
|
||||
Console.WriteLine("Server version : MC " + version + " (protocol v" + protocolversion + ").");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
Console.WriteLine("Unexpected answer from the server (is that a Minecraft server ?)");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
Console.WriteLine("An error occured while attempting to connect to this IP.");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public bool Handshake(string username, string sessionID, ref string serverID, ref byte[] token, string host, int port)
|
||||
{
|
||||
username = ReverseString(username);
|
||||
//array
|
||||
byte[] data = new byte[10 + (username.Length * 2) + (host.Length * 2)];
|
||||
|
||||
//packet id
|
||||
data[0] = (byte)2;
|
||||
|
||||
//Protocol Version - Minecraft 1.3.1 & 1.3.2
|
||||
//data[1] = (byte)39;
|
||||
|
||||
//Protocol Version - Minecraft 1.4.2
|
||||
//data[1] = (byte)47;
|
||||
|
||||
//Protocol Version - Minecraft 1.4.4
|
||||
//data[1] = (byte)49;
|
||||
|
||||
//Protocol Version - Minecraft 1.4.6 & 1.4.7
|
||||
//data[1] = (byte)51;
|
||||
|
||||
//Protocol Version - Minecraft 1.5.0
|
||||
//data[1] = (byte)60;
|
||||
|
||||
//Protocol Version - Custom
|
||||
data[1] = protocolversion;
|
||||
|
||||
//short len
|
||||
byte[] sh = new byte[2];
|
||||
sh = BitConverter.GetBytes((short)username.Length);
|
||||
Array.Reverse(sh);
|
||||
sh.CopyTo(data, 2);
|
||||
|
||||
//username
|
||||
byte[] name = Encoding.Unicode.GetBytes(username);
|
||||
Array.Reverse(name);
|
||||
name.CopyTo(data, 4);
|
||||
|
||||
//short len
|
||||
sh = new byte[2];
|
||||
sh = BitConverter.GetBytes((short)host.Length);
|
||||
Array.Reverse(sh);
|
||||
sh.CopyTo(data, 4 + (username.Length * 2));
|
||||
|
||||
//host
|
||||
byte[] bhost = Encoding.Unicode.GetBytes(username);
|
||||
Array.Reverse(bhost);
|
||||
bhost.CopyTo(data, 6 + (username.Length * 2));
|
||||
|
||||
//port
|
||||
sh = new byte[4];
|
||||
sh = BitConverter.GetBytes(port);
|
||||
Array.Reverse(sh);
|
||||
sh.CopyTo(data, 6 + (username.Length * 2) + (host.Length * 2));
|
||||
|
||||
Send(data);
|
||||
|
||||
byte[] pid = new byte[1];
|
||||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
while (pid[0] == 0xFA) //Skip some early plugin messages
|
||||
{
|
||||
processPacket(pid[0]);
|
||||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
}
|
||||
if (pid[0] == 0xFD)
|
||||
{
|
||||
serverID = readNextString();
|
||||
byte[] Serverkey_RAW = readNextByteArray();
|
||||
token = readNextByteArray();
|
||||
|
||||
if (serverID == "-")
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
Console.WriteLine("Server is in offline mode.");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
return true; //No need to check session or start encryption
|
||||
}
|
||||
else
|
||||
{
|
||||
var PublicServerkey = Crypto.GenerateRSAPublicKey(Serverkey_RAW);
|
||||
var SecretKey = Crypto.GenerateAESPrivateKey();
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
Console.WriteLine("Handshake sussessful. (Server ID: " + serverID + ')');
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
return StartEncryption(ReverseString(username), sessionID, token, serverID, PublicServerkey, SecretKey);
|
||||
}
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
public bool StartEncryption(string username, string sessionID, byte[] token, string serverIDhash, java.security.PublicKey serverKey, javax.crypto.SecretKey secretKey)
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
ConsoleIO.WriteLine("Crypto keys & hash generated.");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
|
||||
if (serverIDhash != "-")
|
||||
{
|
||||
Console.WriteLine("Checking Session...");
|
||||
if (!SessionCheck(username, sessionID, new java.math.BigInteger(Crypto.getServerHash(serverIDhash, serverKey, secretKey)).toString(16)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Encrypt the data
|
||||
byte[] key_enc = Crypto.Encrypt(serverKey, secretKey.getEncoded());
|
||||
byte[] token_enc = Crypto.Encrypt(serverKey, token);
|
||||
byte[] keylen = BitConverter.GetBytes((short)key_enc.Length);
|
||||
byte[] tokenlen = BitConverter.GetBytes((short)token_enc.Length);
|
||||
|
||||
Array.Reverse(keylen);
|
||||
Array.Reverse(tokenlen);
|
||||
|
||||
//Building the packet
|
||||
byte[] data = new byte[5 + (short)key_enc.Length + (short)token_enc.Length];
|
||||
data[0] = 0xFC;
|
||||
keylen.CopyTo(data, 1);
|
||||
key_enc.CopyTo(data, 3);
|
||||
tokenlen.CopyTo(data, 3 + (short)key_enc.Length);
|
||||
token_enc.CopyTo(data, 5 + (short)key_enc.Length);
|
||||
|
||||
//Send it back
|
||||
Send(data);
|
||||
|
||||
//Getting the next packet
|
||||
byte[] pid = new byte[1];
|
||||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
if (pid[0] == 0xFC)
|
||||
{
|
||||
readData(4);
|
||||
setEncryptedClient(Crypto.SwitchToAesMode(c.GetStream(), secretKey));
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
public bool FinalizeLogin()
|
||||
{
|
||||
//Creating byte array
|
||||
byte[] data = new byte[2];
|
||||
data[0] = 0xCD;
|
||||
data[1] = 0;
|
||||
|
||||
Send(data);
|
||||
try
|
||||
{
|
||||
byte[] pid = new byte[1];
|
||||
try
|
||||
{
|
||||
if (c.Connected)
|
||||
{
|
||||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
while (pid[0] >= 0xC0 && pid[0] != 0xFF) //Skip some early packets or plugin messages
|
||||
{
|
||||
processPacket(pid[0]);
|
||||
Receive(pid, 0, 1, SocketFlags.None);
|
||||
}
|
||||
if (pid[0] == (byte)1)
|
||||
{
|
||||
readData(4); readNextString(); readData(5);
|
||||
return true; //The Server accepted the request
|
||||
}
|
||||
else if (pid[0] == (byte)0xFF)
|
||||
{
|
||||
string reason = readNextString();
|
||||
Console.WriteLine("Login rejected by Server :"); printstring(reason, true);
|
||||
for (int i = 0; i < bots.Count; i++) { bots[i].OnDisconnect(ChatBot.DisconnectReason.LoginRejected, reason); }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Connection failed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//Network error
|
||||
Console.WriteLine("Connection Lost.");
|
||||
return false;
|
||||
}
|
||||
return false; //Login was unsuccessful (received a kick...)
|
||||
}
|
||||
public bool SendChatMessage(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
message = ReverseString(message);
|
||||
byte[] chat = new byte[3 + (message.Length * 2)];
|
||||
chat[0] = (byte)3;
|
||||
|
||||
byte[] msglen = new byte[2];
|
||||
msglen = BitConverter.GetBytes((short)message.Length);
|
||||
Array.Reverse(msglen);
|
||||
msglen.CopyTo(chat, 1);
|
||||
|
||||
byte[] msg = new byte[message.Length * 2];
|
||||
msg = Encoding.Unicode.GetBytes(message);
|
||||
Array.Reverse(msg);
|
||||
msg.CopyTo(chat, 3);
|
||||
|
||||
Send(chat);
|
||||
return true;
|
||||
}
|
||||
catch (SocketException) { return false; }
|
||||
}
|
||||
public void Disconnect(string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
message = ReverseString(message);
|
||||
byte[] reason = new byte[3 + (message.Length * 2)];
|
||||
reason[0] = (byte)0xff;
|
||||
|
||||
byte[] msglen = new byte[2];
|
||||
msglen = BitConverter.GetBytes((short)message.Length);
|
||||
Array.Reverse(msglen);
|
||||
msglen.CopyTo(reason, 1);
|
||||
|
||||
byte[] msg = new byte[message.Length * 2];
|
||||
msg = Encoding.Unicode.GetBytes(message);
|
||||
Array.Reverse(msg);
|
||||
msg.CopyTo(reason, 3);
|
||||
|
||||
Send(reason);
|
||||
}
|
||||
catch (SocketException) { }
|
||||
catch (System.IO.IOException) { }
|
||||
}
|
||||
|
||||
private List<ChatBot> bots = new List<ChatBot>();
|
||||
public void BotLoad(ChatBot b) { b.SetHandler(this); bots.Add(b); b.Initialize(); }
|
||||
public void BotUnLoad(ChatBot b) { bots.RemoveAll(item => object.ReferenceEquals(item, b)); }
|
||||
public void BotClear() { bots.Clear(); }
|
||||
}
|
||||
}
|
||||
280
MinecraftClient/Program.cs
Normal file
280
MinecraftClient/Program.cs
Normal file
|
|
@ -0,0 +1,280 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace MinecraftClient
|
||||
{
|
||||
/// <summary>
|
||||
/// Minecraft Console Client by ORelio (c) 2012-2013.
|
||||
/// Allows to connect to any Minecraft server, send and receive text, automated scripts.
|
||||
/// This source code is released under the CDDL 1.0 License.
|
||||
/// </summary>
|
||||
|
||||
class Program
|
||||
{
|
||||
private static McTcpClient Client;
|
||||
private static string loginusername = "";
|
||||
private static string user = "";
|
||||
private static string pass = "";
|
||||
private static string ip = "";
|
||||
private static string command = "";
|
||||
private static string[] startupargs;
|
||||
|
||||
/// <summary>
|
||||
/// The main entry point of Minecraft Console Client
|
||||
/// </summary>
|
||||
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Console Client for MC 1.4.6 to 1.6.2 - v1.5.2 - By ORelio (or3L1o@live.fr)");
|
||||
|
||||
//Processing Command-line arguments
|
||||
|
||||
if (args.Length >= 1)
|
||||
{
|
||||
user = args[0];
|
||||
if (args.Length >= 2)
|
||||
{
|
||||
pass = args[1];
|
||||
if (args.Length >= 3)
|
||||
{
|
||||
ip = args[2];
|
||||
if (args.Length >= 4)
|
||||
{
|
||||
command = args[3];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Asking the user to type in missing data such as Username and Password
|
||||
|
||||
if (user == "") {
|
||||
Console.Write("Username : ");
|
||||
user = Console.ReadLine();
|
||||
}
|
||||
if (pass == "") {
|
||||
Console.Write("Password : ");
|
||||
pass = Console.ReadLine();
|
||||
|
||||
//Hide the password
|
||||
Console.CursorTop--;
|
||||
Console.Write("Password : <******>");
|
||||
for (int i = 19; i < Console.BufferWidth; i++) { Console.Write(' '); }
|
||||
}
|
||||
|
||||
//Save the arguments
|
||||
startupargs = args;
|
||||
loginusername = user;
|
||||
|
||||
//Start the Client
|
||||
InitializeClient();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start a new Client
|
||||
/// </summary>
|
||||
|
||||
private static void InitializeClient()
|
||||
{
|
||||
MinecraftCom.LoginResult result;
|
||||
string logindata = "";
|
||||
|
||||
if (pass == "-")
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
Console.WriteLine("You chose to run in offline mode.");
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
result = MinecraftCom.LoginResult.Success;
|
||||
logindata = "0:deprecated:" + user + ":0";
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Connecting to Minecraft.net...");
|
||||
result = MinecraftCom.GetLogin(loginusername, pass, ref logindata);
|
||||
}
|
||||
if (result == MinecraftCom.LoginResult.Success)
|
||||
{
|
||||
user = logindata.Split(':')[2];
|
||||
string sessionID = logindata.Split(':')[3];
|
||||
Console.WriteLine("Success. (session ID: " + sessionID + ')');
|
||||
if (ip == "")
|
||||
{
|
||||
Console.Write("Server IP : ");
|
||||
ip = Console.ReadLine();
|
||||
}
|
||||
|
||||
//Get server version
|
||||
Console.WriteLine("Retrieving Server Info...");
|
||||
byte protocolversion = 0; string version = "";
|
||||
if (MinecraftCom.GetServerInfo(ip, ref protocolversion, ref version))
|
||||
{
|
||||
//Supported protocol version ?
|
||||
int[] supportedVersions = { 51, 60, 61, 72, 73, 74 };
|
||||
if (Array.IndexOf(supportedVersions, protocolversion) > -1)
|
||||
{
|
||||
//Minecraft 1.6+ ? Load translations
|
||||
if (protocolversion >= 72) { ChatParser.InitTranslations(); }
|
||||
|
||||
//Will handle the connection for this client
|
||||
Console.WriteLine("Version is supported.");
|
||||
MinecraftCom handler = new MinecraftCom();
|
||||
handler.setVersion(protocolversion);
|
||||
|
||||
//Load & initialize bots if needed
|
||||
foreach (string arg in startupargs)
|
||||
{
|
||||
if (arg.Length > 4 && arg.Substring(0, 4).ToLower() == "bot:")
|
||||
{
|
||||
int param;
|
||||
string[] botargs = arg.ToLower().Split(':');
|
||||
switch (botargs[1])
|
||||
{
|
||||
case "antiafk":
|
||||
#region Arguments for the AntiAFK bot
|
||||
param = 600;
|
||||
if (botargs.Length > 2)
|
||||
{
|
||||
try { param = Convert.ToInt32(botargs[2]); }
|
||||
catch (FormatException) { }
|
||||
}
|
||||
#endregion
|
||||
handler.BotLoad(new Bots.AntiAFK(param)); break;
|
||||
|
||||
case "pendu": handler.BotLoad(new Bots.Pendu(false)); break;
|
||||
case "hangman": handler.BotLoad(new Bots.Pendu(true)); break;
|
||||
case "alerts": handler.BotLoad(new Bots.Alerts()); break;
|
||||
|
||||
case "log":
|
||||
#region Arguments for the ChatLog bot
|
||||
bool datetime = true;
|
||||
string file = "chat-" + ip + ".log";
|
||||
Bots.ChatLog.MessageFilter filter = Bots.ChatLog.MessageFilter.AllMessages;
|
||||
if (botargs.Length > 2)
|
||||
{
|
||||
datetime = (botargs[2] != "0");
|
||||
if (botargs.Length > 3)
|
||||
{
|
||||
switch (botargs[3])
|
||||
{
|
||||
case "all": filter = Bots.ChatLog.MessageFilter.AllText; break;
|
||||
case "messages": filter = Bots.ChatLog.MessageFilter.AllMessages; break;
|
||||
case "chat": filter = Bots.ChatLog.MessageFilter.OnlyChat; break;
|
||||
case "private": filter = Bots.ChatLog.MessageFilter.OnlyWhispers; break;
|
||||
}
|
||||
if (botargs.Length > 4 && botargs[4] != "") { file = botargs[4]; }
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
handler.BotLoad(new Bots.ChatLog(file, filter, datetime)); break;
|
||||
|
||||
case "logplayerlist":
|
||||
#region Arguments for the PlayerListLogger bot
|
||||
param = 600;
|
||||
if (botargs.Length > 2)
|
||||
{
|
||||
try { param = Convert.ToInt32(botargs[2]); }
|
||||
catch (FormatException) { }
|
||||
}
|
||||
#endregion
|
||||
handler.BotLoad(new Bots.PlayerListLogger(param, "connected-" + ip + ".log")); break;
|
||||
|
||||
case "autorelog":
|
||||
#region Arguments for the AutoRelog bot
|
||||
int delay = 10;
|
||||
if (botargs.Length > 2)
|
||||
{
|
||||
try { delay = Convert.ToInt32(botargs[2]); }
|
||||
catch (FormatException) { }
|
||||
}
|
||||
int retries = 3;
|
||||
if (botargs.Length > 3)
|
||||
{
|
||||
try { retries = Convert.ToInt32(botargs[3]); }
|
||||
catch (FormatException) { }
|
||||
}
|
||||
#endregion
|
||||
handler.BotLoad(new Bots.AutoRelog(delay, retries)); break;
|
||||
|
||||
case "xauth":
|
||||
if (botargs.Length > 2) { handler.BotLoad(new Bots.xAuth(botargs[2])); } break;
|
||||
}
|
||||
|
||||
command = "";
|
||||
}
|
||||
}
|
||||
|
||||
//Start the main TCP client
|
||||
if (command != "")
|
||||
{
|
||||
Client = new McTcpClient(user, sessionID, ip, handler, command);
|
||||
}
|
||||
else Client = new McTcpClient(user, sessionID, ip, handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Cannot connect to the server : This version is not supported !");
|
||||
ReadLineReconnect();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Failed to ping this IP.");
|
||||
ReadLineReconnect();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
Console.Write("Connection failed : ");
|
||||
switch (result)
|
||||
{
|
||||
case MinecraftCom.LoginResult.AccountMigrated: Console.WriteLine("Account migrated, use e-mail as username."); break;
|
||||
case MinecraftCom.LoginResult.Blocked: Console.WriteLine("Too many failed logins. Please try again later."); break;
|
||||
case MinecraftCom.LoginResult.WrongPassword: Console.WriteLine("Incorrect password."); break;
|
||||
case MinecraftCom.LoginResult.NotPremium: Console.WriteLine("User not premium."); break;
|
||||
case MinecraftCom.LoginResult.Error: Console.WriteLine("Network error."); break;
|
||||
}
|
||||
while (Console.KeyAvailable) { Console.ReadKey(false); }
|
||||
if (command == "") { ReadLineReconnect(); }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnect the current client from the server and restart it
|
||||
/// </summary>
|
||||
|
||||
public static void Restart()
|
||||
{
|
||||
new System.Threading.Thread(new System.Threading.ThreadStart(t_restart)).Start();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pause the program, usually when an error or a kick occured, letting the user press Enter to quit OR type /reconnect
|
||||
/// </summary>
|
||||
/// <returns>Return True if the user typed "/reconnect"</returns>
|
||||
|
||||
public static bool ReadLineReconnect()
|
||||
{
|
||||
string text = Console.ReadLine();
|
||||
if (text == "reco" || text == "reconnect" || text == "/reco" || text == "/reconnect")
|
||||
{
|
||||
Program.Restart();
|
||||
return true;
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Private thread for restarting the program. Called through Restart()
|
||||
/// </summary>
|
||||
|
||||
private static void t_restart()
|
||||
{
|
||||
if (Client != null) { Client.Disconnect(); ConsoleIO.Reset(); }
|
||||
Console.WriteLine("Restarting Minecraft Console Client...");
|
||||
InitializeClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
36
MinecraftClient/Properties/AssemblyInfo.cs
Normal file
36
MinecraftClient/Properties/AssemblyInfo.cs
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Minecraft Console Client")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("MinecraftClient")]
|
||||
[assembly: AssemblyCopyright("Copyright © ORelio 2012-2013")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("78af6200-1f48-4daa-b473-109a9728b61f")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.3")]
|
||||
[assembly: AssemblyFileVersion("1.3")]
|
||||
Loading…
Add table
Add a link
Reference in a new issue