using System; using System.IO; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; namespace MinecraftClient.ChatBots { /// /// This bot automatically runs actions when a user sends a message matching a specified rule /// class AutoRespond : ChatBot { private string matchesFile; private List respondRules; private enum MessageType { Public, Private, Other }; /// /// Create a new AutoRespond bot /// /// INI File to load matches from public AutoRespond(string matchesFile) { this.matchesFile = matchesFile; } /// /// Describe a respond rule based on a simple match or a regex /// private class RespondRule { private Regex regex; private string match; private string actionPublic; private string actionPrivate; private string actionOther; private bool ownersOnly; /// /// Create a respond rule from a regex and a reponse message or command /// /// Regex /// Internal command to run for public messages /// Internal command to run for private messages /// Internal command to run for any other messages /// Only match messages from bot owners public RespondRule(Regex regex, string actionPublic, string actionPrivate, string actionOther, bool ownersOnly) { this.regex = regex; this.match = null; this.actionPublic = actionPublic; this.actionPrivate = actionPrivate; this.actionOther = actionOther; this.ownersOnly = ownersOnly; } /// /// Create a respond rule from a match string and a reponse message or command /// /// Match string /// Internal command to run for public messages /// Internal command to run for private messages /// Only match messages from bot owners public RespondRule(string match, string actionPublic, string actionPrivate, string actionOther, bool ownersOnly) { this.regex = null; this.match = match; this.actionPublic = actionPublic; this.actionPrivate = actionPrivate; this.actionOther = actionOther; this.ownersOnly = ownersOnly; } /// /// Match the respond rule to the specified string and return a message or command to send if a match is detected /// /// Player who have sent the message /// Message to match against the regex or match string /// Type of the message public/private message, or other message /// Dictionary to populate with match variables in case of Regex match /// Internal command to run as a response to this user, or null if no match has been detected public string Match(string username, string message, MessageType msgType, Dictionary localVars) { string toSend = null; if (ownersOnly && (String.IsNullOrEmpty(username) || !Settings.Bots_Owners.Contains(username.ToLower()))) return null; switch (msgType) { case MessageType.Public: toSend = actionPublic; break; case MessageType.Private: toSend = actionPrivate; break; case MessageType.Other: toSend = actionOther; break; } if (String.IsNullOrEmpty(toSend)) return null; if (regex != null) { if (regex.IsMatch(message)) { Match regexMatch = regex.Match(message); localVars["match_0"] = regexMatch.Groups[0].Value; for (int i = regexMatch.Groups.Count - 1; i >= 1; i--) { toSend = toSend.Replace("$" + i, regexMatch.Groups[i].Value); localVars["match_" + i] = regexMatch.Groups[i].Value; } toSend = toSend.Replace("$u", username); localVars["match_u"] = username; return toSend; } } else if (!String.IsNullOrEmpty(match)) { if (message.ToLower().Contains(match.ToLower())) { localVars["match_0"] = message; localVars["match_u"] = username; return toSend.Replace("$u", username); } } return null; } } /// /// Initialize the AutoRespond bot from the matches file /// public override void Initialize() { if (File.Exists(matchesFile)) { Regex matchRegex = null; string matchString = null; string matchAction = null; string matchActionPrivate = null; string matchActionOther = null; bool ownersOnly = false; respondRules = new List(); if (Settings.DebugMessages) LogToConsole("Loading matches from file: " + System.IO.Path.GetFullPath(matchesFile)); foreach (string lineRAW in File.ReadAllLines(matchesFile, Encoding.UTF8)) { string line = lineRAW.Split('#')[0].Trim(); if (line.Length > 0) { if (line[0] == '[' && line[line.Length - 1] == ']') { switch (line.Substring(1, line.Length - 2).ToLower()) { case "match": CheckAddMatch(matchRegex, matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly); matchRegex = null; matchString = null; matchAction = null; matchActionPrivate = null; matchActionOther = null; ownersOnly = false; break; } } else { string argName = line.Split('=')[0]; if (line.Length > (argName.Length + 1)) { string argValue = line.Substring(argName.Length + 1); switch (argName.ToLower()) { case "regex": matchRegex = new Regex(argValue); break; case "match": matchString = argValue; break; case "action": matchAction = argValue; break; case "actionprivate": matchActionPrivate = argValue; break; case "actionother": matchActionOther = argValue; break; case "ownersonly": ownersOnly = Settings.str2bool(argValue); break; } } } } } CheckAddMatch(matchRegex, matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly); } else { LogToConsole("File not found: '" + System.IO.Path.GetFullPath(matchesFile) + "'"); UnloadBot(); //No need to keep the bot active } } /// /// Create a new respond rule from the provided arguments, only if they are valid: at least one match and one action /// /// Matching regex /// Matching string /// Action if the matching message is public /// Action if the matching message is private /// Only match messages from bot owners private void CheckAddMatch(Regex matchRegex, string matchString, string matchAction, string matchActionPrivate, string matchActionOther, bool ownersOnly) { if (matchAction != null || matchActionPrivate != null || matchActionOther != null) { if (matchRegex != null) { respondRules.Add(new RespondRule(matchRegex, matchAction, matchActionPrivate, matchActionOther, ownersOnly)); } else if (matchString != null) { respondRules.Add(new RespondRule(matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly)); } } } public override void GetText(string text) { //Remove colour codes text = GetVerbatim(text); //Get Message type string sender = "", message = ""; MessageType msgType = MessageType.Other; if (IsChatMessage(text, ref message, ref sender)) msgType = MessageType.Public; else if (IsPrivateMessage(text, ref message, ref sender)) msgType = MessageType.Private; else message = text; //Do not process messages sent by the bot itself if (msgType == MessageType.Other || sender != Settings.Username) { foreach (RespondRule rule in respondRules) { Dictionary localVars = new Dictionary(); string toPerform = rule.Match(sender, message, msgType, localVars); if (!String.IsNullOrEmpty(toPerform)) { string response = null; LogToConsole(toPerform); PerformInternalCommand(toPerform, ref response, localVars); if (!String.IsNullOrEmpty(response)) LogToConsole(response); } } } } } }