mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
AutoRespond: Support for per-match cooldown (#593)
Prevent a match from triggering too often using a cooldown By default, matches do not have a cooldown (it's opt-in) Also add translation support and more debug messages
This commit is contained in:
parent
e6b2b87366
commit
b9935ab8fa
4 changed files with 87 additions and 16 deletions
|
|
@ -35,6 +35,8 @@ namespace MinecraftClient.ChatBots
|
||||||
private string actionPrivate;
|
private string actionPrivate;
|
||||||
private string actionOther;
|
private string actionOther;
|
||||||
private bool ownersOnly;
|
private bool ownersOnly;
|
||||||
|
private TimeSpan cooldown;
|
||||||
|
private DateTime cooldownExpiration;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Create a respond rule from a regex and a reponse message or command
|
/// Create a respond rule from a regex and a reponse message or command
|
||||||
|
|
@ -44,7 +46,8 @@ namespace MinecraftClient.ChatBots
|
||||||
/// <param name="actionPrivate">Internal command to run for private messages</param>
|
/// <param name="actionPrivate">Internal command to run for private messages</param>
|
||||||
/// <param name="actionOther">Internal command to run for any other messages</param>
|
/// <param name="actionOther">Internal command to run for any other messages</param>
|
||||||
/// <param name="ownersOnly">Only match messages from bot owners</param>
|
/// <param name="ownersOnly">Only match messages from bot owners</param>
|
||||||
public RespondRule(Regex regex, string actionPublic, string actionPrivate, string actionOther, bool ownersOnly)
|
/// <param name="cooldown">Minimal cooldown between two matches</param>
|
||||||
|
public RespondRule(Regex regex, string actionPublic, string actionPrivate, string actionOther, bool ownersOnly, TimeSpan cooldown)
|
||||||
{
|
{
|
||||||
this.regex = regex;
|
this.regex = regex;
|
||||||
this.match = null;
|
this.match = null;
|
||||||
|
|
@ -52,6 +55,8 @@ namespace MinecraftClient.ChatBots
|
||||||
this.actionPrivate = actionPrivate;
|
this.actionPrivate = actionPrivate;
|
||||||
this.actionOther = actionOther;
|
this.actionOther = actionOther;
|
||||||
this.ownersOnly = ownersOnly;
|
this.ownersOnly = ownersOnly;
|
||||||
|
this.cooldown = cooldown;
|
||||||
|
this.cooldownExpiration = DateTime.MinValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -61,7 +66,8 @@ namespace MinecraftClient.ChatBots
|
||||||
/// <param name="actionPublic">Internal command to run for public messages</param>
|
/// <param name="actionPublic">Internal command to run for public messages</param>
|
||||||
/// <param name="actionPrivate">Internal command to run for private messages</param>
|
/// <param name="actionPrivate">Internal command to run for private messages</param>
|
||||||
/// <param name="ownersOnly">Only match messages from bot owners</param>
|
/// <param name="ownersOnly">Only match messages from bot owners</param>
|
||||||
public RespondRule(string match, string actionPublic, string actionPrivate, string actionOther, bool ownersOnly)
|
/// <param name="cooldown">Minimal cooldown between two matches</param>
|
||||||
|
public RespondRule(string match, string actionPublic, string actionPrivate, string actionOther, bool ownersOnly, TimeSpan cooldown)
|
||||||
{
|
{
|
||||||
this.regex = null;
|
this.regex = null;
|
||||||
this.match = match;
|
this.match = match;
|
||||||
|
|
@ -69,6 +75,8 @@ namespace MinecraftClient.ChatBots
|
||||||
this.actionPrivate = actionPrivate;
|
this.actionPrivate = actionPrivate;
|
||||||
this.actionOther = actionOther;
|
this.actionOther = actionOther;
|
||||||
this.ownersOnly = ownersOnly;
|
this.ownersOnly = ownersOnly;
|
||||||
|
this.cooldown = cooldown;
|
||||||
|
this.cooldownExpiration = DateTime.MinValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -81,6 +89,9 @@ namespace MinecraftClient.ChatBots
|
||||||
/// <returns>Internal command to run as a response to this user, or null if no match has been detected</returns>
|
/// <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, MessageType msgType, Dictionary<string, object> localVars)
|
public string Match(string username, string message, MessageType msgType, Dictionary<string, object> localVars)
|
||||||
{
|
{
|
||||||
|
if (DateTime.Now < cooldownExpiration)
|
||||||
|
return null;
|
||||||
|
|
||||||
string toSend = null;
|
string toSend = null;
|
||||||
|
|
||||||
if (ownersOnly && (String.IsNullOrEmpty(username) || !Settings.Bots_Owners.Contains(username.ToLower())))
|
if (ownersOnly && (String.IsNullOrEmpty(username) || !Settings.Bots_Owners.Contains(username.ToLower())))
|
||||||
|
|
@ -100,6 +111,7 @@ namespace MinecraftClient.ChatBots
|
||||||
{
|
{
|
||||||
if (regex.IsMatch(message))
|
if (regex.IsMatch(message))
|
||||||
{
|
{
|
||||||
|
cooldownExpiration = DateTime.Now + cooldown;
|
||||||
Match regexMatch = regex.Match(message);
|
Match regexMatch = regex.Match(message);
|
||||||
localVars["match_0"] = regexMatch.Groups[0].Value;
|
localVars["match_0"] = regexMatch.Groups[0].Value;
|
||||||
for (int i = regexMatch.Groups.Count - 1; i >= 1; i--)
|
for (int i = regexMatch.Groups.Count - 1; i >= 1; i--)
|
||||||
|
|
@ -116,6 +128,7 @@ namespace MinecraftClient.ChatBots
|
||||||
{
|
{
|
||||||
if (message.ToLower().Contains(match.ToLower()))
|
if (message.ToLower().Contains(match.ToLower()))
|
||||||
{
|
{
|
||||||
|
cooldownExpiration = DateTime.Now + cooldown;
|
||||||
localVars["match_0"] = message;
|
localVars["match_0"] = message;
|
||||||
localVars["match_u"] = username;
|
localVars["match_u"] = username;
|
||||||
return toSend.Replace("$u", username);
|
return toSend.Replace("$u", username);
|
||||||
|
|
@ -124,6 +137,24 @@ namespace MinecraftClient.ChatBots
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a string representation of the RespondRule
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Translations.Get(
|
||||||
|
"bot.autoRespond.match",
|
||||||
|
match,
|
||||||
|
regex,
|
||||||
|
actionPublic,
|
||||||
|
actionPrivate,
|
||||||
|
actionOther,
|
||||||
|
ownersOnly,
|
||||||
|
(int)cooldown.TotalSeconds
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -139,10 +170,10 @@ namespace MinecraftClient.ChatBots
|
||||||
string matchActionPrivate = null;
|
string matchActionPrivate = null;
|
||||||
string matchActionOther = null;
|
string matchActionOther = null;
|
||||||
bool ownersOnly = false;
|
bool ownersOnly = false;
|
||||||
|
TimeSpan cooldown = TimeSpan.Zero;
|
||||||
respondRules = new List<RespondRule>();
|
respondRules = new List<RespondRule>();
|
||||||
|
|
||||||
if (Settings.DebugMessages)
|
LogDebugToConsoleTranslated("bot.autoRespond.loading", System.IO.Path.GetFullPath(matchesFile));
|
||||||
LogToConsole("Loading matches from file: " + System.IO.Path.GetFullPath(matchesFile));
|
|
||||||
|
|
||||||
foreach (string lineRAW in File.ReadAllLines(matchesFile, Encoding.UTF8))
|
foreach (string lineRAW in File.ReadAllLines(matchesFile, Encoding.UTF8))
|
||||||
{
|
{
|
||||||
|
|
@ -154,13 +185,14 @@ namespace MinecraftClient.ChatBots
|
||||||
switch (line.Substring(1, line.Length - 2).ToLower())
|
switch (line.Substring(1, line.Length - 2).ToLower())
|
||||||
{
|
{
|
||||||
case "match":
|
case "match":
|
||||||
CheckAddMatch(matchRegex, matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly);
|
CheckAddMatch(matchRegex, matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly, cooldown);
|
||||||
matchRegex = null;
|
matchRegex = null;
|
||||||
matchString = null;
|
matchString = null;
|
||||||
matchAction = null;
|
matchAction = null;
|
||||||
matchActionPrivate = null;
|
matchActionPrivate = null;
|
||||||
matchActionOther = null;
|
matchActionOther = null;
|
||||||
ownersOnly = false;
|
ownersOnly = false;
|
||||||
|
cooldown = TimeSpan.Zero;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,16 +210,17 @@ namespace MinecraftClient.ChatBots
|
||||||
case "actionprivate": matchActionPrivate = argValue; break;
|
case "actionprivate": matchActionPrivate = argValue; break;
|
||||||
case "actionother": matchActionOther = argValue; break;
|
case "actionother": matchActionOther = argValue; break;
|
||||||
case "ownersonly": ownersOnly = Settings.str2bool(argValue); break;
|
case "ownersonly": ownersOnly = Settings.str2bool(argValue); break;
|
||||||
|
case "cooldown": cooldown = TimeSpan.FromSeconds(Settings.str2int(argValue)); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
CheckAddMatch(matchRegex, matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly);
|
CheckAddMatch(matchRegex, matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly, cooldown);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
LogToConsole("File not found: '" + System.IO.Path.GetFullPath(matchesFile) + "'");
|
LogToConsoleTranslated("bot.autoRespond.file_not_found", System.IO.Path.GetFullPath(matchesFile));
|
||||||
UnloadBot(); //No need to keep the bot active
|
UnloadBot(); //No need to keep the bot active
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -200,21 +233,32 @@ namespace MinecraftClient.ChatBots
|
||||||
/// <param name="matchAction">Action if the matching message is public</param>
|
/// <param name="matchAction">Action if the matching message is public</param>
|
||||||
/// <param name="matchActionPrivate">Action if the matching message is private</param>
|
/// <param name="matchActionPrivate">Action if the matching message is private</param>
|
||||||
/// <param name="ownersOnly">Only match messages from bot owners</param>
|
/// <param name="ownersOnly">Only match messages from bot owners</param>
|
||||||
private void CheckAddMatch(Regex matchRegex, string matchString, string matchAction, string matchActionPrivate, string matchActionOther, bool ownersOnly)
|
/// <param name="cooldown">Minimal cooldown between two matches</param>
|
||||||
|
private void CheckAddMatch(Regex matchRegex, string matchString, string matchAction, string matchActionPrivate, string matchActionOther, bool ownersOnly, TimeSpan cooldown)
|
||||||
{
|
{
|
||||||
|
if (matchRegex != null || matchString != null || matchAction != null || matchActionPrivate != null || matchActionOther != null || ownersOnly || cooldown != TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
RespondRule rule = matchRegex != null
|
||||||
|
? new RespondRule(matchRegex, matchAction, matchActionPrivate, matchActionOther, ownersOnly, cooldown)
|
||||||
|
: new RespondRule(matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly, cooldown);
|
||||||
|
|
||||||
if (matchAction != null || matchActionPrivate != null || matchActionOther != null)
|
if (matchAction != null || matchActionPrivate != null || matchActionOther != null)
|
||||||
{
|
{
|
||||||
if (matchRegex != null)
|
if (matchRegex != null || matchString != null)
|
||||||
{
|
{
|
||||||
respondRules.Add(new RespondRule(matchRegex, matchAction, matchActionPrivate, matchActionOther, ownersOnly));
|
respondRules.Add(rule);
|
||||||
|
LogDebugToConsoleTranslated("bot.autoRespond.loaded_match", rule);
|
||||||
}
|
}
|
||||||
else if (matchString != null)
|
else LogDebugToConsoleTranslated("bot.autoRespond.no_trigger", rule);
|
||||||
{
|
|
||||||
respondRules.Add(new RespondRule(matchString, matchAction, matchActionPrivate, matchActionOther, ownersOnly));
|
|
||||||
}
|
}
|
||||||
|
else LogDebugToConsoleTranslated("bot.autoRespond.no_action", rule);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process messages from the server and test them against all matches
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="text">Text from the server</param>
|
||||||
public override void GetText(string text)
|
public override void GetText(string text)
|
||||||
{
|
{
|
||||||
//Remove colour codes
|
//Remove colour codes
|
||||||
|
|
@ -239,7 +283,7 @@ namespace MinecraftClient.ChatBots
|
||||||
if (!String.IsNullOrEmpty(toPerform))
|
if (!String.IsNullOrEmpty(toPerform))
|
||||||
{
|
{
|
||||||
string response = null;
|
string response = null;
|
||||||
LogToConsole(toPerform);
|
LogToConsoleTranslated("bot.autoRespond.match_run", toPerform);
|
||||||
PerformInternalCommand(toPerform, ref response, localVars);
|
PerformInternalCommand(toPerform, ref response, localVars);
|
||||||
if (!String.IsNullOrEmpty(response))
|
if (!String.IsNullOrEmpty(response))
|
||||||
LogToConsole(response);
|
LogToConsole(response);
|
||||||
|
|
|
||||||
|
|
@ -429,6 +429,15 @@ bot.autoRelog.reconnect=Nachricht enhält '{0}'. Verbinde erneut.
|
||||||
bot.autoRelog.reconnect_ignore=Kick Nachricht enthält keine Schlüsselwörter. Wird ignoriert!
|
bot.autoRelog.reconnect_ignore=Kick Nachricht enthält keine Schlüsselwörter. Wird ignoriert!
|
||||||
bot.autoRelog.wait=Warte {0} Sekunden vor erneuter Verbindung...
|
bot.autoRelog.wait=Warte {0} Sekunden vor erneuter Verbindung...
|
||||||
|
|
||||||
|
# AutoRespond
|
||||||
|
bot.autoRespond.loading=Loading matches from '{0}'
|
||||||
|
bot.autoRespond.file_not_found=File not found: '{0}'
|
||||||
|
bot.autoRespond.loaded_match=Loaded match:\n{0}
|
||||||
|
bot.autoRespond.no_trigger=This match will never trigger:\n{0}
|
||||||
|
bot.autoRespond.no_action=No action for match:\n{0}
|
||||||
|
bot.autoRespond.match_run=Running action: {0}
|
||||||
|
bot.autoRespond.match=match: {0}\nregex: {1}\naction: {2}\nactionPrivate: {3}\nactionOther: {4}\nownersOnly: {5}\ncooldown: {6}
|
||||||
|
|
||||||
# ChatLog
|
# ChatLog
|
||||||
bot.chatLog.invalid_file=Pfad '{0}' enthält ungültige Zeichen.
|
bot.chatLog.invalid_file=Pfad '{0}' enthält ungültige Zeichen.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -429,6 +429,15 @@ bot.autoRelog.reconnect=Message contains '{0}'. Reconnecting.
|
||||||
bot.autoRelog.reconnect_ignore=Message not containing any defined keywords. Ignoring.
|
bot.autoRelog.reconnect_ignore=Message not containing any defined keywords. Ignoring.
|
||||||
bot.autoRelog.wait=Waiting {0} seconds before reconnecting...
|
bot.autoRelog.wait=Waiting {0} seconds before reconnecting...
|
||||||
|
|
||||||
|
# AutoRespond
|
||||||
|
bot.autoRespond.loading=Loading matches from '{0}'
|
||||||
|
bot.autoRespond.file_not_found=File not found: '{0}'
|
||||||
|
bot.autoRespond.loaded_match=Loaded match:\n{0}
|
||||||
|
bot.autoRespond.no_trigger=This match will never trigger:\n{0}
|
||||||
|
bot.autoRespond.no_action=No action for match:\n{0}
|
||||||
|
bot.autoRespond.match_run=Running action: {0}
|
||||||
|
bot.autoRespond.match=match: {0}\nregex: {1}\naction: {2}\nactionPrivate: {3}\nactionOther: {4}\nownersOnly: {5}\ncooldown: {6}
|
||||||
|
|
||||||
# ChatLog
|
# ChatLog
|
||||||
bot.chatLog.invalid_file=Path '{0}' contains invalid characters.
|
bot.chatLog.invalid_file=Path '{0}' contains invalid characters.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
# You can define an action if the match was not sent by a player
|
# You can define an action if the match was not sent by a player
|
||||||
# Regex matches are also supported eg $1, $2, $3.. in actions
|
# Regex matches are also supported eg $1, $2, $3.. in actions
|
||||||
# Matches can optionally be restricted to bot owners only
|
# Matches can optionally be restricted to bot owners only
|
||||||
|
# Matches can have a cooldown, specified in seconds
|
||||||
|
|
||||||
# When running a script from an AutoRespond match,
|
# When running a script from an AutoRespond match,
|
||||||
# additional %variables% are available from within your script:
|
# additional %variables% are available from within your script:
|
||||||
|
|
@ -23,6 +24,7 @@ action=send hi, $u!
|
||||||
actionprivate=send /tell $u Hello!
|
actionprivate=send /tell $u Hello!
|
||||||
actionother=log detected "hi" message
|
actionother=log detected "hi" message
|
||||||
ownersonly=false
|
ownersonly=false
|
||||||
|
cooldown=0
|
||||||
|
|
||||||
# You do not need to specify all the "action" fields
|
# You do not need to specify all the "action" fields
|
||||||
# Only one of them is required for each match
|
# Only one of them is required for each match
|
||||||
|
|
@ -54,5 +56,12 @@ match=gohome
|
||||||
actionprivate=send /home
|
actionprivate=send /home
|
||||||
ownersonly=true
|
ownersonly=true
|
||||||
|
|
||||||
|
# Example of match with 1-minute cooldown
|
||||||
|
|
||||||
|
[Match]
|
||||||
|
match=hello
|
||||||
|
action=send hello!
|
||||||
|
cooldown=60
|
||||||
|
|
||||||
# Enjoy!
|
# Enjoy!
|
||||||
# - ORelio
|
# - ORelio
|
||||||
Loading…
Add table
Add a link
Reference in a new issue