diff --git a/.gitignore b/.gitignore index cf71df70..960877d2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/DebugTools/MinecraftClientProxy.suo +/DebugTools/MinecraftClientProxy.v11.suo /MinecraftClient.v11.suo /MinecraftClient.suo /MinecraftClientGUI.v11.suo diff --git a/MinecraftClient/ChatBots/AutoAttack.cs b/MinecraftClient/ChatBots/AutoAttack.cs index 49390bd9..1f18f245 100644 --- a/MinecraftClient/ChatBots/AutoAttack.cs +++ b/MinecraftClient/ChatBots/AutoAttack.cs @@ -24,8 +24,8 @@ namespace MinecraftClient.ChatBots { if (!GetEntityHandlingEnabled()) { - ConsoleIO.WriteLine("[AutoAttack] Entity Handling is not enabled in the config file!"); - ConsoleIO.WriteLine("[AutoAttack] This bot will be unloaded."); + LogToConsole("Entity Handling is not enabled in the config file!"); + LogToConsole("This bot will be unloaded."); UnloadBot(); } } diff --git a/MinecraftClient/ChatBots/AutoFishing.cs b/MinecraftClient/ChatBots/AutoFishing.cs index 7fb1f4ba..92d22165 100644 --- a/MinecraftClient/ChatBots/AutoFishing.cs +++ b/MinecraftClient/ChatBots/AutoFishing.cs @@ -26,8 +26,8 @@ namespace MinecraftClient.ChatBots { if (!GetEntityHandlingEnabled()) { - ConsoleIO.WriteLine("[AutoFishing] Entity Handling is not enabled in the config file!"); - ConsoleIO.WriteLine("[AutoFishing] This bot will be unloaded."); + LogToConsole("Entity Handling is not enabled in the config file!"); + LogToConsole("This bot will be unloaded."); UnloadBot(); } inventoryEnabled = GetInventoryEnabled(); @@ -39,7 +39,7 @@ namespace MinecraftClient.ChatBots { if (GetCurrentLocation().Distance(entity.Location) < 2 && !isFishing) { - ConsoleIO.WriteLine("Threw a fishing rod"); + LogToConsole("Threw a fishing rod"); fishingRod = entity; LastPos = entity.Location; isFishing = true; @@ -93,14 +93,14 @@ namespace MinecraftClient.ChatBots /// public void OnCaughtFish() { - ConsoleIO.WriteLine(GetTimestamp()+": Caught a fish!"); + LogToConsole(GetTimestamp() + ": Caught a fish!"); // retract fishing rod UseItemOnHand(); if (inventoryEnabled) { if (!hasFishingRod()) { - ConsoleIO.WriteLine(GetTimestamp() + ": No Fishing Rod on hand. Maybe broken?"); + LogToConsole(GetTimestamp() + ": No Fishing Rod on hand. Maybe broken?"); return; } } diff --git a/MinecraftClient/ConsoleIO.cs b/MinecraftClient/ConsoleIO.cs index 2ed377d6..fe57fd63 100644 --- a/MinecraftClient/ConsoleIO.cs +++ b/MinecraftClient/ConsoleIO.cs @@ -384,8 +384,11 @@ namespace MinecraftClient /// Write a prefixed log line. Prefix is set in LogPrefix. /// /// Text of the log line - public static void WriteLogLine(string text) + /// Allow line breaks + public static void WriteLogLine(string text, bool acceptnewlines = true) { + if (!acceptnewlines) + text = text.Replace('\n', ' '); WriteLineFormatted(LogPrefix + text); } diff --git a/MinecraftClient/McTcpClient.cs b/MinecraftClient/McTcpClient.cs index f4596f5f..67f29360 100644 --- a/MinecraftClient/McTcpClient.cs +++ b/MinecraftClient/McTcpClient.cs @@ -11,7 +11,6 @@ using MinecraftClient.Proxy; using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Mapping; using MinecraftClient.Inventory; -using System.Threading.Tasks; namespace MinecraftClient { @@ -56,6 +55,7 @@ namespace MinecraftClient private string sessionid; private DateTime lastKeepAlive; private object lastKeepAliveLock = new object(); + private int respawnTicks = 0; private int playerEntityID; // not really understand the Inventory Class @@ -279,7 +279,7 @@ namespace MinecraftClient } else if (response_msg.Length > 0) { - ConsoleIO.WriteLineFormatted("§8MCC: " + response_msg); + ConsoleIO.WriteLogLine(response_msg); } } else SendText(text); @@ -342,7 +342,7 @@ namespace MinecraftClient } catch (Exception e) { - ConsoleIO.WriteLine(e.Message); + ConsoleIO.WriteLogLine(e.Message); } } } @@ -756,7 +756,7 @@ namespace MinecraftClient ConsoleIO.WriteLineFormatted(text, true); if (Settings.DisplayChatLinks) foreach (string link in links) - ConsoleIO.WriteLineFormatted("§8MCC: Link: " + link, false); + ConsoleIO.WriteLogLine("Link: " + link, false); foreach (ChatBot bot in bots.ToArray()) { try @@ -769,7 +769,7 @@ namespace MinecraftClient { if (!(e is ThreadAbortException)) { - ConsoleIO.WriteLineFormatted("§8GetText: Got error from " + bot.ToString() + ": " + e.ToString()); + ConsoleIO.WriteLogLine("GetText: Got error from " + bot.ToString() + ": " + e.ToString()); } else throw; //ThreadAbortException should not be caught } @@ -904,7 +904,7 @@ namespace MinecraftClient { if (!(e is ThreadAbortException)) { - ConsoleIO.WriteLineFormatted("§8Update: Got error from " + bot.ToString() + ": " + e.ToString()); + ConsoleIO.WriteLogLine("Update: Got error from " + bot.ToString() + ": " + e.ToString()); } else throw; //ThreadAbortException should not be caught } @@ -941,6 +941,13 @@ namespace MinecraftClient pitch = null; } } + + if (Settings.AutoRespawn && respawnTicks > 0) + { + respawnTicks--; + if (respawnTicks == 0) + SendRespawnPacket(); + } } /// @@ -1361,7 +1368,8 @@ namespace MinecraftClient public bool PlaceBlock(Location location) { //WORK IN PROGRESS. MAY NOT WORK YET - ConsoleIO.WriteLine(location.ToString()); + if (Settings.DebugMessages) + ConsoleIO.WriteLogLine(location.ToString()); return handler.SendPlayerBlockPlacement(0, location, 1, 0.5f, 0.5f, 0.5f, false); } @@ -1388,18 +1396,16 @@ namespace MinecraftClient /// Player current health public void OnUpdateHealth(float health) { - if (Settings.AutoRespawn) + if (health <= 0) { - if (health <= 0) + if (Settings.AutoRespawn) { - ConsoleIO.WriteLine("Client player dead."); - ConsoleIO.WriteLine("Respawn after 1 second..."); - Task.Factory.StartNew(delegate - { - // wait before respawn - Thread.Sleep(1000); - SendRespawnPacket(); - }); + ConsoleIO.WriteLogLine("You are dead. Automatically respawning after 1 second."); + respawnTicks = 10; + } + else + { + ConsoleIO.WriteLogLine("You are dead. Type /respawn to respawn."); } } } diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index 30f83fb2..43fbd6a1 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -41,6 +41,18 @@ namespace MinecraftClient.Protocol.Handlers ConsoleIO.WriteLineFormatted("§8Terrain & Movements currently not handled for that MC version."); Handler.SetTerrainEnabled(false); } + + if (handler.GetInventoryEnabled()) + { + ConsoleIO.WriteLineFormatted("§8Inventories are currently not handled for that MC version."); + handler.SetInventoryEnabled(false); + } + + if (handler.GetEntityHandlingEnabled()) + { + ConsoleIO.WriteLineFormatted("§8Entities are currently not handled for that MC version."); + handler.SetEntityHandlingEnabled(false); + } } private Protocol16Handler(TcpClient Client) @@ -155,7 +167,7 @@ namespace MinecraftClient.Protocol.Handlers case 0x84: readData(11); nbr = readNextShort(); if (nbr > 0) { readData(nbr); } break; case 0x85: if (protocolversion >= 74) { readData(13); } break; case 0xC8: - if (readNextInt() == 2022) { ConsoleIO.WriteLineFormatted("§MCC: You are dead. Type /reco to respawn & reconnect."); } + if (readNextInt() == 2022) { ConsoleIO.WriteLogLine("You are dead. Type /respawn to respawn."); } if (protocolversion >= 72) { readData(4); } else readData(1); break; case 0xC9: diff --git a/MinecraftClient/config/Modules/VkMessager.cs b/MinecraftClient/config/Modules/VkMessager.cs new file mode 100644 index 00000000..9e801089 --- /dev/null +++ b/MinecraftClient/config/Modules/VkMessager.cs @@ -0,0 +1,168 @@ +//MCCScript 1.0 +//using System.Threading.Tasks; + +//==== CONFIG START ==== +string vkToken = ""; +string chatId = ""; +string botCommunityId = ""; +//==== CONFIG END ==== + +MCC.LoadBot(new VkMessager(vkToken, chatId, botCommunityId)); + +//MCCScript Extensions + +/// +/// This bot forwarding messages between Minecraft and VKonrakte chats. +/// Shares only messages that starts with dot ("."). Example: .Hello! +/// Also, send message to VK when any player joins or leaves. +/// +/// Needs: +/// - VK Community token (also LongPool API with NewMessageEvent, api >= 5.80), +/// - VK ChatId (typically 2000000001, etc.) +/// - Bot's CommunityId +/// +public class VkMessager : ChatBot +{ + private VkLongPoolClient VkLongPoolClient { get; set; } + private readonly string ChatId; + + /// + /// This bot forwarding messages between Minecraft and VKonrakte chats. + /// Shares only messages that starts with dot ("."). Example: .Hello! + /// Also, send message to VK when any player joins or leaves. + /// + /// VK Community token + /// VK ChatId + /// Bot's CommunityId + public VkMessager(string vkToken, string chatId, string botCommunityId) + { + VkLongPoolClient = new VkLongPoolClient(vkToken, botCommunityId, ProcessMsgFromVk); + ChatId = chatId; + } + + public override void GetText(string text) + { + text = GetVerbatim(text); + string sender = ""; + string message = ""; + + if (IsChatMessage(text, ref message, ref sender)) + { + ProcessMsgFromMinecraft(sender, message); + } + else if (IsPrivateMessage(text, ref message, ref sender)) + { + ProcessMsgFromMinecraft(sender, message); + } + else + { + ProcessMsgFromMinecraft("Server", text); + } + } + + private void ProcessMsgFromVk(string senderId, string text) + { + if (!text.StartsWith(".")) return; + + SendText("[VK " + senderId.Substring(0, 2) + "]: " + text.TrimStart('.')); + } + + private void ProcessMsgFromMinecraft(string senderName, string text) + { + if (!text.StartsWith(".") && !text.Contains("left") && !text.Contains("joined")) return; + if (text.Contains("[VK")) return; // loop protection + + VkLongPoolClient.SendMessage(ChatId, String.Format("[MC {0}]\r\n{1}", senderName, text.TrimStart('.'))); + } +} + +/// +/// Client for VK Community (bot) LongPool API. +/// Also can send messages. +/// +internal class VkLongPoolClient +{ + public VkLongPoolClient(string token, string botCommunityId, Action onMessageReceivedCallback, IWebProxy webProxy = null) + { + Token = token; + BotCommunityId = botCommunityId; + OnMessageReceivedCallback = onMessageReceivedCallback; + ReceiverWebClient = new WebClient() { Proxy = webProxy, Encoding = Encoding.UTF8 }; + SenderWebClient = new WebClient() { Proxy = webProxy, Encoding = Encoding.UTF8 }; + + Init(); + StartLongPoolAsync(); + } + + private WebClient ReceiverWebClient { get; set; } + private WebClient SenderWebClient { get; set; } + private string Token { get; set; } + private string LastTs { get; set; } + private string Server { get; set; } + private string Key { get; set; } + private Action OnMessageReceivedCallback { get; set; } + private string BotCommunityId { get; set; } + + private void Init() + { + var jsonResult = CallVkMethod("groups.getLongPollServer", "group_id=" + BotCommunityId); + var data = Json.ParseJson(jsonResult); + + Key = data.Properties["response"].Properties["key"].StringValue; + Server = data.Properties["response"].Properties["server"].StringValue; + LastTs = data.Properties["response"].Properties["ts"].StringValue; + } + + public void SendMessage(string chatId, string text) + { + CallVkMethod("messages.send", "peer_id=" + chatId + "&message=" + text); + } + + private void StartLongPoolAsync() + { + var baseUrl = String.Format("{0}?act=a_check&version=2&wait=25&key={1}&ts=", Server, Key); + Task.Factory.StartNew(() => + { + while (true) + { + var data = ReceiverWebClient.DownloadString(baseUrl + LastTs); + var messages = ProcessResponse(data); + + foreach (var message in messages) + { + OnMessageReceivedCallback(message.Item1, message.Item2); + } + } + }); + } + + private IEnumerable> ProcessResponse(string jsonData) + { + var data = Json.ParseJson(jsonData); + LastTs = data.Properties["ts"].StringValue; + + var updates = data.Properties["updates"].DataArray; + var messages = new List>(); + foreach (var str in updates) + { + if (str.Properties["type"].StringValue != "message_new") continue; + + var msgData = str.Properties["object"].Properties; + + var userId = msgData["from_id"].StringValue; + var msgText = msgData["text"].StringValue; + + messages.Add(new Tuple(userId, msgText)); + } + + return messages; + } + + private string CallVkMethod(string methodName, string data) + { + var url = String.Format("https://api.vk.com/method/{0}?v=5.80&access_token={1}&{2}", methodName, Token, data); + var jsonResult = SenderWebClient.DownloadString(url); + + return jsonResult; + } +} \ No newline at end of file