mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
AutoRespond improvements
- Add improvements from pull request #76 - Add support for regexes instead of simple matches - Add support for internal MCC commands eg script - Add support for flexible INI file containing matches TODO: Testing, sample INI file, proper documentation
This commit is contained in:
parent
840ac01dc5
commit
0029561135
3 changed files with 197 additions and 31 deletions
|
|
@ -1,38 +1,209 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MinecraftClient.ChatBots
|
||||
{
|
||||
/// <summary>
|
||||
/// This bot automatically runs actions when a user sends a message matching a specified rule
|
||||
/// </summary>
|
||||
class AutoRespond : ChatBot
|
||||
{
|
||||
private string[] respondon = new string[0];
|
||||
private string[] torespond = new string[0];
|
||||
private string matchesFile;
|
||||
private List<RespondRule> respondRules;
|
||||
private static string header = "[AutoRespond] ";
|
||||
|
||||
//Initalize the bot
|
||||
/// <summary>
|
||||
/// Create a new AutoRespond bot
|
||||
/// </summary>
|
||||
/// <param name="matchesFile">INI File to load matches from</param>
|
||||
public AutoRespond(string matchesFile)
|
||||
{
|
||||
this.matchesFile = matchesFile;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Describe a respond rule based on a simple match or a regex
|
||||
/// </summary>
|
||||
private class RespondRule
|
||||
{
|
||||
private Regex regex;
|
||||
private string match;
|
||||
private string actionPublic;
|
||||
private string actionPrivate;
|
||||
|
||||
/// <summary>
|
||||
/// Create a respond rule from a regex and a reponse message or command
|
||||
/// </summary>
|
||||
/// <param name="regex">Regex</param>
|
||||
/// <param name="actionPublic">Internal command to run for public messages</param>
|
||||
/// <param name="actionPrivate">Internal command to run for private messages</param>
|
||||
public RespondRule(Regex regex, string actionPublic, string actionPrivate)
|
||||
{
|
||||
this.regex = regex;
|
||||
this.match = null;
|
||||
this.actionPublic = actionPublic;
|
||||
this.actionPrivate = actionPrivate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a respond rule from a match string and a reponse message or command
|
||||
/// </summary>
|
||||
/// <param name="match">Match string</param>
|
||||
/// <param name="actionPublic">Internal command to run for public messages</param>
|
||||
/// <param name="actionPrivate">Internal command to run for private messages</param>
|
||||
public RespondRule(string match, string actionPublic, string actionPrivate)
|
||||
{
|
||||
this.regex = null;
|
||||
this.match = match;
|
||||
this.actionPublic = actionPublic;
|
||||
this.actionPrivate = actionPrivate;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match the respond rule to the specified string and return a message or command to send if a match is detected
|
||||
/// </summary>
|
||||
/// <param name="username">Player who have sent the message</param>
|
||||
/// <param name="message">Message to match against the regex or match string</param>
|
||||
/// <param name="privateMsg">True if the provided message was sent privately eg with /tell</param>
|
||||
/// <returns>Internal command to run as a response to this user, or null if no match has been detected</returns>
|
||||
public string Match(string username, string message, bool privateMsg)
|
||||
{
|
||||
if (regex != null)
|
||||
{
|
||||
if (regex.IsMatch(message))
|
||||
{
|
||||
Match regexMatch = regex.Match(message);
|
||||
string toSend = privateMsg ? actionPrivate : actionPublic;
|
||||
for (int i = regexMatch.Groups.Count - 1; i >= 1; i--)
|
||||
toSend = toSend.Replace("$" + i, regexMatch.Groups[i].Value);
|
||||
toSend = toSend.Replace("$u", username);
|
||||
return toSend;
|
||||
}
|
||||
}
|
||||
else if (!String.IsNullOrEmpty(match))
|
||||
{
|
||||
if (message.Contains(match))
|
||||
{
|
||||
return (privateMsg
|
||||
? actionPrivate
|
||||
: actionPublic).Replace("$u", username);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize the AutoRespond bot from the matches file
|
||||
/// </summary>
|
||||
public override void Initialize()
|
||||
{
|
||||
respondon = LoadDistinctEntriesFromFile(Settings.Respond_MatchesFile);
|
||||
torespond = LoadDistinctEntriesFromFile(Settings.Respond_RespondFile);
|
||||
ConsoleIO.WriteLine("Auto Respond Bot Sucessfully loaded!");
|
||||
if (File.Exists(matchesFile))
|
||||
{
|
||||
Regex matchRegex = null;
|
||||
string matchString = null;
|
||||
string matchAction = null;
|
||||
string matchActionPrivate = null;
|
||||
respondRules = new List<RespondRule>();
|
||||
|
||||
foreach (string lineRAW in File.ReadAllLines(matchesFile))
|
||||
{
|
||||
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);
|
||||
matchRegex = null;
|
||||
matchString = null;
|
||||
matchAction = null;
|
||||
matchActionPrivate = null;
|
||||
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": matchAction = argValue; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CheckAddMatch(matchRegex, matchString, matchAction, matchActionPrivate);
|
||||
}
|
||||
else
|
||||
{
|
||||
LogToConsole("File not found: '" + matchesFile + "'");
|
||||
UnloadBot(); //No need to keep the bot active
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new respond rule from the provided arguments, only if they are valid: at least one match and one action
|
||||
/// </summary>
|
||||
/// <param name="matchRegex">Matching regex</param>
|
||||
/// <param name="matchString">Matching string</param>
|
||||
/// <param name="matchAction">Action if the matching message is public</param>
|
||||
/// <param name="matchActionPrivate">Action if the matching message is private</param>
|
||||
private void CheckAddMatch(Regex matchRegex, string matchString, string matchAction, string matchActionPrivate)
|
||||
{
|
||||
if (matchAction != null || matchActionPrivate != null)
|
||||
{
|
||||
if (matchActionPrivate == null)
|
||||
{
|
||||
matchActionPrivate = matchAction;
|
||||
}
|
||||
|
||||
if (matchRegex != null)
|
||||
{
|
||||
respondRules.Add(new RespondRule(matchRegex, matchAction, matchActionPrivate));
|
||||
}
|
||||
else if (matchString != null)
|
||||
{
|
||||
respondRules.Add(new RespondRule(matchString, matchAction, matchActionPrivate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void GetText(string text)
|
||||
{
|
||||
//Remove colour codes
|
||||
text = getVerbatim(text).ToLower();
|
||||
//Check text to see if bot should respond
|
||||
foreach (string alert in respondon.Where(alert => text.Contains(alert)))
|
||||
|
||||
//Check if this is a valid message
|
||||
string sender = "", message = "";
|
||||
bool chatMessage = isChatMessage(text, ref message, ref sender);
|
||||
bool privateMessage = false;
|
||||
if (!chatMessage)
|
||||
privateMessage = isPrivateMessage(text, ref message, ref sender);
|
||||
|
||||
//Process only chat messages sent by another user
|
||||
if ((chatMessage || privateMessage) && sender != Settings.Username)
|
||||
{
|
||||
//Find what to respond with
|
||||
for (int x = 0; x < respondon.Length; x++)
|
||||
foreach (RespondRule rule in respondRules)
|
||||
{
|
||||
if (respondon[x].ToString().Contains(alert))
|
||||
string toPerform = rule.Match(sender, message, privateMessage);
|
||||
if (toPerform != null)
|
||||
{
|
||||
//Respond
|
||||
SendText(torespond[x].ToString());
|
||||
string response = null;
|
||||
LogToConsole(header + toPerform);
|
||||
performInternalCommand(toPerform, ref response);
|
||||
if (!String.IsNullOrEmpty(response))
|
||||
LogToConsole(header + response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,7 +106,7 @@ namespace MinecraftClient
|
|||
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()); }
|
||||
if (Settings.Respond_Enabled) { BotLoad(new ChatBots.AutoRespond()); }
|
||||
if (Settings.AutoRespond_Enabled) { BotLoad(new ChatBots.AutoRespond(Settings.AutoRespond_Matches)); }
|
||||
}
|
||||
|
||||
try
|
||||
|
|
|
|||
|
|
@ -90,16 +90,15 @@ namespace MinecraftClient
|
|||
public static bool RemoteCtrl_AutoTpaccept_Everyone = false;
|
||||
|
||||
//Auto Respond
|
||||
public static bool Respond_Enabled = false;
|
||||
public static string Respond_MatchesFile = "detect.txt";
|
||||
public static string Respond_RespondFile = "respond.txt";
|
||||
public static bool AutoRespond_Enabled = false;
|
||||
public static string AutoRespond_Matches = "matches.ini";
|
||||
|
||||
//Custom app variables and Minecraft accounts
|
||||
private static Dictionary<string, string> AppVars = new Dictionary<string, string>();
|
||||
private static Dictionary<string, KeyValuePair<string, string>> Accounts = new Dictionary<string, KeyValuePair<string, string>>();
|
||||
private static Dictionary<string, KeyValuePair<string, ushort>> Servers = new Dictionary<string, KeyValuePair<string, ushort>>();
|
||||
|
||||
private enum ParseMode { Default, Main, AppVars, Proxy, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, Auto_Respond };
|
||||
private enum ParseMode { Default, Main, AppVars, Proxy, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, AutoRespond };
|
||||
|
||||
/// <summary>
|
||||
/// Load settings from the give INI file
|
||||
|
|
@ -133,7 +132,7 @@ namespace MinecraftClient
|
|||
case "remotecontrol": pMode = ParseMode.RemoteControl; break;
|
||||
case "proxy": pMode = ParseMode.Proxy; break;
|
||||
case "appvars": pMode = ParseMode.AppVars; break;
|
||||
case "auto respond": pMode = ParseMode.Auto_Respond; break;
|
||||
case "autorespond": pMode = ParseMode.AutoRespond; break;
|
||||
default: pMode = ParseMode.Default; break;
|
||||
}
|
||||
}
|
||||
|
|
@ -317,12 +316,11 @@ namespace MinecraftClient
|
|||
setVar(argName, argValue);
|
||||
break;
|
||||
|
||||
case ParseMode.Auto_Respond:
|
||||
case ParseMode.AutoRespond:
|
||||
switch (argName.ToLower())
|
||||
{
|
||||
case "enabled": Respond_Enabled = str2bool(argValue); break;
|
||||
case "matchfile": Respond_MatchesFile = argValue; break;
|
||||
case "respondfile": Respond_RespondFile = argValue; break;
|
||||
case "enabled": AutoRespond_Enabled = str2bool(argValue); break;
|
||||
case "matchesfile": AutoRespond_Matches = argValue; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
@ -422,12 +420,9 @@ namespace MinecraftClient
|
|||
+ "autotpaccept=true\r\n"
|
||||
+ "tpaccepteveryone=false\r\n"
|
||||
+ "\r\n"
|
||||
+ "[Auto Respond]\r\n"
|
||||
+ "[AutoRespond]\r\n"
|
||||
+ "enabled=false\r\n"
|
||||
+ "matchfile=detect.txt\r\n"
|
||||
+ "respondfile=respond.txt\r\n"
|
||||
+ "#To use the bot, place the text to detect in the matchfile file and the text to respond with in the respondfile\r\n"
|
||||
+ "#Each line in each file is relevant to the same line in the other document, for example if the bot detects the text in line 1 of the first file, it will respond with line 1 of the second file.\r\n", Encoding.UTF8);
|
||||
+ "matchesfile=matches.ini\r\n", Encoding.UTF8);
|
||||
}
|
||||
|
||||
public static int str2int(string str) { try { return Convert.ToInt32(str); } catch { return 0; } }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue