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;
using MinecraftClient.Protocol;
using MinecraftClient.Proxy;
namespace MinecraftClient
{
///
/// The main client class, used to connect to a Minecraft server.
///
public class McTcpClient : IMinecraftComHandler
{
private List bots = new List();
private static List scripts_on_hold = new List();
public void BotLoad(ChatBot b) { b.SetHandler(this); bots.Add(b); b.Initialize(); Settings.SingleCommand = ""; }
public void BotUnLoad(ChatBot b) { bots.RemoveAll(item => object.ReferenceEquals(item, b)); }
public void BotClear() { bots.Clear(); }
public static int AttemptsLeft = 0;
private string host;
private int port;
private string username;
private string uuid;
private string sessionid;
public int getServerPort() { return port; }
public string getServerHost() { return host; }
public string getUsername() { return username; }
public string getUserUUID() { return uuid; }
public string getSessionID() { return sessionid; }
TcpClient client;
IMinecraftCom handler;
///
/// Starts the main chat client
///
/// The chosen username of a premium Minecraft Account
/// The player's UUID for online-mode authentication
/// A valid sessionID obtained after logging in
/// The server IP
/// The server port to use
/// Minecraft protocol version to use
public McTcpClient(string username, string uuid, string sessionID, int protocolversion, string server_ip, short port)
{
StartClient(username, uuid, sessionID, server_ip, port, protocolversion, false, "");
}
///
/// Starts the main chat client in single command sending mode
///
/// The chosen username of a premium Minecraft Account
/// The player's UUID for online-mode authentication
/// A valid sessionID obtained after logging in
/// The server IP
/// The server port to use
/// Minecraft protocol version to use
/// The text or command to send.
public McTcpClient(string username, string uuid, string sessionID, string server_ip, short port, int protocolversion, string command)
{
StartClient(username, uuid, sessionID, server_ip, port, protocolversion, true, command);
}
///
/// Starts the main chat client, wich will login to the server using the MinecraftCom class.
///
/// The chosen username of a premium Minecraft Account
/// A valid sessionID obtained with MinecraftCom.GetLogin()
/// The server IP
/// The server port to use
/// Minecraft protocol version to use
/// The player's UUID for online-mode authentication
/// If set to true, the client will send a single command and then disconnect from the server
/// The text or command to send. Will only be sent if singlecommand is set to true.
private void StartClient(string user, string uuid, string sessionID, string server_ip, short port, int protocolversion, bool singlecommand, string command)
{
this.sessionid = sessionID;
this.uuid = uuid;
this.username = user;
this.host = server_ip;
this.port = port;
if (!singlecommand)
{
if (Settings.AntiAFK_Enabled) { BotLoad(new ChatBots.AntiAFK(Settings.AntiAFK_Delay)); }
if (Settings.Hangman_Enabled) { BotLoad(new ChatBots.HangmanGame(Settings.Hangman_English)); }
if (Settings.Alerts_Enabled) { BotLoad(new ChatBots.Alerts()); }
if (Settings.ChatLog_Enabled) { BotLoad(new ChatBots.ChatLog(Settings.expandVars(Settings.ChatLog_File), Settings.ChatLog_Filter, Settings.ChatLog_DateTime)); }
if (Settings.PlayerLog_Enabled) { BotLoad(new ChatBots.PlayerListLogger(Settings.PlayerLog_Delay, Settings.expandVars(Settings.PlayerLog_File))); }
if (Settings.AutoRelog_Enabled) { BotLoad(new ChatBots.AutoRelog(Settings.AutoRelog_Delay, Settings.AutoRelog_Retries)); }
if (Settings.ScriptScheduler_Enabled) { BotLoad(new ChatBots.ScriptScheduler(Settings.expandVars(Settings.ScriptScheduler_TasksFile))); }
if (Settings.RemoteCtrl_Enabled) { BotLoad(new ChatBots.RemoteControl()); }
}
try
{
client = ProxyHandler.newTcpClient(host, port);
client.ReceiveBufferSize = 1024 * 1024;
handler = Protocol.ProtocolHandler.getProtocolHandler(client, protocolversion, this);
Console.WriteLine("Version is supported.\nLogging in...");
if (handler.Login())
{
if (singlecommand)
{
handler.SendChatMessage(command);
ConsoleIO.WriteLineFormatted("§7Command §8" + command + "§7 sent.");
Thread.Sleep(5000);
handler.Disconnect();
Thread.Sleep(1000);
}
else
{
foreach (ChatBot bot in scripts_on_hold) { bots.Add(bot); }
scripts_on_hold.Clear();
Console.WriteLine("Server was successfully joined.\nType '"
+ (Settings.internalCmdChar == ' ' ? "" : "" + Settings.internalCmdChar)
+ "quit' to leave the server.");
StartTalk();
}
}
}
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(); }
}
}
///
/// Allows the user to send chat messages, commands, and to leave the server.
///
private void StartTalk()
{
try
{
string text = "";
Thread.Sleep(500);
handler.SendRespawnPacket();
while (client.Client.Connected)
{
text = ConsoleIO.ReadLine();
if (ConsoleIO.basicIO && text.Length > 0 && text[0] == (char)0x00)
{
//Process a request from the GUI
string[] command = text.Substring(1).Split((char)0x00);
switch (command[0].ToLower())
{
case "autocomplete":
if (command.Length > 1) { ConsoleIO.WriteLine((char)0x00 + "autocomplete" + (char)0x00 + handler.AutoComplete(command[1])); }
else Console.WriteLine((char)0x00 + "autocomplete" + (char)0x00);
break;
}
}
else
{
text = text.Trim();
if (text.Length > 0)
{
if (Settings.internalCmdChar == ' ' || text[0] == Settings.internalCmdChar)
{
string response_msg = "";
string command = Settings.internalCmdChar == ' ' ? text : text.Substring(1);
if (!performInternalCommand(Settings.expandVars(command), ref response_msg) && Settings.internalCmdChar == '/')
{
SendChatMessage(text);
}
else if (response_msg.Length > 0)
{
ConsoleIO.WriteLineFormatted("§8MCC: " + response_msg);
}
}
else SendChatMessage(text);
}
}
}
}
catch (IOException) { }
}
///
/// Perform an internal MCC command (not a server command, use SendChatMessage() instead for that!)
///
/// The command
/// Set to true if command was sent by the user using the command prompt
/// May contain a confirmation or error message after processing the command, or "" otherwise.
/// TRUE if the command was indeed an internal MCC command
public bool performInternalCommand(string command, ref string response_msg)
{
response_msg = "";
string[] command_args = command.Split(' ');
string command_name = command_args[0].ToLower();
switch (command_name)
{
case "exit":
case "quit":
Program.Exit();
break;
case "reco":
Program.Restart();
break;
case "respawn":
handler.SendRespawnPacket();
response_msg = "You have respawned.";
break;
case "send":
if (command.Length > 5)
{
string text = command.Substring(5);
SendChatMessage(text);
}
else response_msg = "send : send a chat message or command.";
break;
case "set":
if (command.Length > 3)
{
string[] temp = command.Substring(4).Split('=');
if (temp.Length > 1)
{
if (!Settings.setVar(temp[0], command.Substring(temp[0].Length + 5)))
{
response_msg = "variable name must be A-Za-z0-9.";
}
}
else response_msg = "set varname=value: set a custom %variable%.";
}
else response_msg = "set varname=value: set a custom %variable%.";
break;
case "script":
if (command.Length > 8)
{
BotLoad(new ChatBots.Script(command.Substring(8)));
}
else response_msg = "script : run a script file.";
break;
case "connect":
if (command_args.Length > 1)
{
Settings.setServerIP(command_args[1]);
Program.Restart();
}
else response_msg = "connect : connect to the specified server.";
break;
case "help":
if (command.Length >= 6)
{
string help_cmd_name = command.Substring(5).ToLower();
switch (help_cmd_name)
{
case "quit": response_msg = "quit: disconnect from the server."; break;
case "exit": response_msg = "exit: disconnect from the server."; break;
case "reco": response_msg = "reco: restart and reconnct to the server."; break;
case "respawn": response_msg = "respawn: respawn after death."; break;
case "send": response_msg = "send : send a chat message or command."; break;
case "set": response_msg = "set varname=value: set a custom %variable%."; break;
case "script": response_msg = "script : run a script file."; break;
case "connect": response_msg = "connect : connect to the specified server."; break;
case "help": response_msg = "help : show brief help about a command."; break;
default: response_msg = "help: unknown command '" + help_cmd_name + "'."; break;
}
}
else response_msg = "help . Available commands: exit, reco, script, send, connect.";
break;
default:
response_msg = "Unknown command '" + command_name + "'. Use 'help' for help.";
return false;
}
return true;
}
///
/// Disconnect the client from the server
///
public void Disconnect()
{
foreach (ChatBot bot in bots)
if (bot is ChatBots.Script)
scripts_on_hold.Add((ChatBots.Script)bot);
handler.Disconnect();
handler.Dispose();
Thread.Sleep(1000);
if (client != null) { client.Close(); }
}
///
/// Received some text from the server
///
/// Text received
public void OnTextReceived(string text)
{
ConsoleIO.WriteLineFormatted(text, false);
foreach (ChatBot bot in bots)
bot.GetText(text);
}
///
/// When connection has been lost
///
public void OnConnectionLost(ChatBot.DisconnectReason reason, string message)
{
bool will_restart = false;
switch (reason)
{
case ChatBot.DisconnectReason.ConnectionLost:
message = "Connection has been lost.";
ConsoleIO.WriteLine(message);
break;
case ChatBot.DisconnectReason.InGameKick:
ConsoleIO.WriteLine("Disconnected by Server :");
ConsoleIO.WriteLineFormatted(message);
break;
case ChatBot.DisconnectReason.LoginRejected:
ConsoleIO.WriteLine("Login failed :");
ConsoleIO.WriteLineFormatted(message);
break;
}
foreach (ChatBot bot in bots)
will_restart |= bot.OnDisconnect(reason, message);
if (!will_restart) { Program.ReadLineReconnect(); }
}
///
/// Called ~10 times per second by the protocol handler
///
public void OnUpdate()
{
for (int i = 0; i < bots.Count; i++)
{
try
{
bots[i].Update();
}
catch (Exception e)
{
ConsoleIO.WriteLineFormatted("§8Got error from " + bots[i].ToString() + ": " + e.ToString());
}
}
}
///
/// Send a chat message or command to the server
///
/// Text to send to the server
/// True if the text was sent with no error
public bool SendChatMessage(string text)
{
if (text.Length > 100) //Message is too long?
{
if (text[0] == '/')
{
//Send the first 100 chars of the command
text = text.Substring(0, 100);
return handler.SendChatMessage(text);
}
else
{
//Send the message splitted into several messages
while (text.Length > 100)
{
handler.SendChatMessage(text.Substring(0, 100));
text = text.Substring(100, text.Length - 100);
}
return handler.SendChatMessage(text);
}
}
else return handler.SendChatMessage(text);
}
}
}