mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
Add Mailer bot (#1108)
* Update for the mail script. As requested, I added the synchronization between the config debugmessage bool and the one in the script. Furthermore, I added a way to send anonymous mails by writing "tellonym". The messages are saved as normal mails, which lets them count to the mail cap, due to the fact that the host knows the sender. I added the script to the chat bots because of the problems, that the scripts have with serialization. Instead of rewriting the whole serialization part, my idea was to add the script to the other chat bots, to avoid the compiling issues. Then the serialization would work perfectly fine. Then you could remove the option class at some point and move all the settings to the config file with the addition to activate the whole script. * Correction of debug message loading. The object was missing and the change would be overridden a few lines later. * Update McClient.cs * Add Mail to config file * Correcting the safe file. * Small correction of Settings.c * Update Mailscript Added a failsafe version of the path changing commands. If a path could not be found, an error will be created and the path will be reseted to standart, to avoid endless chains of errors. * Fix for the mail script Removed a wrong option call. Removed the debug_msg condition around the path functions. => Users are aware of what happened (if they see the error) although they turned off debug_msg. * Added some features. Added a try statement to all number changing commands. Added a command to list all moderators to the console. * Serialization Fix There was a chance, that if two bots work on one file, and two users send messages in a short time period, that one bot deserializes the message and then the other bot deserialize the same file, before the other one could save its changes. This would lead to one message disappearing, because one bot never deserialized this message. For this I changed the whole serialization process. All changes are now committed after the interval and not after an incoming mail command directly. All mails are safed temporarily in cache and get serialized after the interval. Due to this changes, you can determit when the individual bot changes the file (there are no more direct interactions with the file after a command, which lead to a certain randomness). Furthermore you can now set an interval of e.g. 2 mins and reset the interval of one bot with "resettimer" after one minute so that the bots won't disturb eachother and no files get lost. * My idea of a manual. This is my idea of a manual for the bot. Improvements of my language / further ideas are welcome! :D * addIgnored [NAME] and removeIgnored[NAME] Added an ignored list. Moderators can add players to the list. The bot won't react to them and just log to the console that they are ignored, everytime they are sending a message, to ensure that they are not accidently ignored. (Just if debug_msg is active.) Especially useful if there are other chat bots on the server, which spam many messages that aren't useful for the mail system. Or block spammers etc. * Add the three commands to the manual. Added addignored, removeignored and getignored to the manual. * Remove moderators. Implement Console Control. Due to security concerns, I converted all moderator commands to console internal commands. Thereby only the host can change crucial settings. Special thanks to ORelio for the hint! * Added empty statement check Added if to all commands, where the syntax is not already protected by a try, so that an incorrect syntax (Empty args[] due to missing statement) won't crash the script. * Changed the serialization fail If the programm can't safe the file, because of some strange character for instance, it first tries to change the path back to normal and if this not helps, it creates a new, file. * toggle mail sending/receiving Add an option to turn mailsending and the listening to commands in chat on/off. * Updated manual. - Removed moderator commands. - Removed moderator part in the network manual + added the two new commands + added a waring for nick plugins and minecraft renames + added a small syntax example * Updated the Settings.cs file. * Smaller fixes and additions + improved command reading of 'mail' & 'tellonym' + sorted internal commands alphabetically + host can set a maximum message length + host can accept commands from public chat + host can decide if 'self mailing' (mailing yourself) is accepted + new order makes 'getsettings' easier to read + new internal commands to toggle 'publiccommands' and 'selfmailing' as well as the maximum mail size - removed the old command interpreter * Small improvements and additions Added a few commands and settings * Completing getsettings + added 'publiccomands' * Completed getsettings + Added 'publiccommand' to 'getsettings' * Removed single bolean, added Dictionary - removed all boleans in the option class - removed all functions relating them + added Dictionary for the booleans + added a single function to set/toggle all booleans * Removed Commands, added interpreter - Removed all Register commands - removed all integer methods + added a single mail command + added integer dictionary + added integer handling similar like bool handling * Small fix + Changed the numbers in several methods to adjust them to the new syntax. - removed parameters in several methods, because they got unneccesary * Even smaller fix + Sorted 'getsettings' alphabetically + corrected a typo * New Serialization method. Now serializing through the .INI format! Thanks to ORelio, who helped me a lot! :) * Added different time Added the option to switch between utc and the time of the local machine for timestamps. * Made timeinutc serializable Added the bool to the serialization method. * Adding the INIFile.cs For Dictionary serialization. * Reworked ignore feature Ignored players are now serialized in a file and reloaded, after the bot enters a server. * Mailer bot refactoring Rename Mail to Mailer Move options to MinecraftClient.ini Make the bot much simpler by removing some settings Create specific MailDatabase and IgnoreList classes However the core functionality for users is the same Settings removed: - allow_sendmail: Cannot use Mailer if it's disabled - allow_receivemail: Cannot use Mailer if it's disabled - path_setting: Settings moved to MinecraftClient.ini - debug_msg: MCC already has a setting for that with LogDebugToConsole() - auto_respawn: MCC already has a built-in auto-respawn feature - allow_selfmail: Is it really necessary to block self mails? ;) - maxcharsinmsg: Automatically calculated based on max chat message length - timeinutc: DateTime is not show to the recipient so I think it's not absolutely necessary - interval_sendmail: Set to 10 seconds for now Internal Commands removed: - changemailpath: Now a static setting in config - changesettingspath: Now a static setting in config - updatemails: Already updated every 10 seconds - getsettings: Shown on startup with debugmessages=true - resettimer: Seems only useful for debugging - setbool: Settings are static in config file - setinteger: Settings are static in config file All user commands are retained: - mail - tellonym * Reload database for mailer network feature * Merge Mail documentation to Readme.md Co-authored-by: ORelio <oreliogitantispam.l0gin@spamgourmet.com>
This commit is contained in:
parent
ca1e902307
commit
92e776cebc
7 changed files with 539 additions and 1 deletions
|
|
@ -1193,6 +1193,15 @@ namespace MinecraftClient
|
||||||
return Handler.CloseInventory(inventoryID);
|
return Handler.CloseInventory(inventoryID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get max length for chat messages
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Max length, in characters</returns>
|
||||||
|
protected int GetMaxChatMessageLength()
|
||||||
|
{
|
||||||
|
return Handler.GetMaxChatMessageLength();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Command runner definition.
|
/// Command runner definition.
|
||||||
/// Returned string will be the output of the command
|
/// Returned string will be the output of the command
|
||||||
|
|
|
||||||
345
MinecraftClient/ChatBots/Mailer.cs
Normal file
345
MinecraftClient/ChatBots/Mailer.cs
Normal file
|
|
@ -0,0 +1,345 @@
|
||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MinecraftClient.ChatBots
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// ChatBot for storing and delivering Mails
|
||||||
|
/// </summary>
|
||||||
|
public class Mailer : ChatBot
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the list of ignored players
|
||||||
|
/// </summary>
|
||||||
|
private class IgnoreList : HashSet<string>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Read ignore list from file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">Path to the ignore list</param>
|
||||||
|
/// <returns>Ignore list</returns>
|
||||||
|
public static IgnoreList FromFile(string filePath)
|
||||||
|
{
|
||||||
|
IgnoreList ignoreList = new IgnoreList();
|
||||||
|
foreach (string line in File.ReadAllLines(filePath))
|
||||||
|
{
|
||||||
|
if (!line.StartsWith("#"))
|
||||||
|
{
|
||||||
|
string entry = line.ToLower();
|
||||||
|
if (!ignoreList.Contains(entry))
|
||||||
|
ignoreList.Add(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ignoreList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save ignore list to file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">Path to destination file</param>
|
||||||
|
public void SaveToFile(string filePath)
|
||||||
|
{
|
||||||
|
List<string> lines = new List<string>();
|
||||||
|
lines.Add("#Ignored Players");
|
||||||
|
foreach (string player in this)
|
||||||
|
lines.Add(player);
|
||||||
|
File.WriteAllLines(filePath, lines);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds the Mail database: a collection of Mails sent from a player to another player
|
||||||
|
/// </summary>
|
||||||
|
private class MailDatabase : List<Mail>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Read mail database from file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">Path to the database</param>
|
||||||
|
/// <returns>Mail database</returns>
|
||||||
|
public static MailDatabase FromFile(string filePath)
|
||||||
|
{
|
||||||
|
MailDatabase database = new MailDatabase();
|
||||||
|
Dictionary<string, Dictionary<string, string>> iniFileDict = INIFile.ParseFile(filePath);
|
||||||
|
foreach (KeyValuePair<string, Dictionary<string, string>> iniSection in iniFileDict)
|
||||||
|
{
|
||||||
|
//iniSection.Key is "mailXX" but we don't need it here
|
||||||
|
string sender = iniSection.Value["sender"];
|
||||||
|
string recipient = iniSection.Value["recipient"];
|
||||||
|
string content = iniSection.Value["content"];
|
||||||
|
DateTime timestamp = DateTime.Parse(iniSection.Value["timestamp"]);
|
||||||
|
bool anonymous = INIFile.Str2Bool(iniSection.Value["anonymous"]);
|
||||||
|
database.Add(new Mail(sender, recipient, content, anonymous, timestamp));
|
||||||
|
}
|
||||||
|
return database;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Save mail database to file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="filePath">Path to destination file</param>
|
||||||
|
public void SaveToFile(string filePath)
|
||||||
|
{
|
||||||
|
Dictionary<string, Dictionary<string, string>> iniFileDict = new Dictionary<string, Dictionary<string, string>>();
|
||||||
|
int mailCount = 0;
|
||||||
|
foreach (Mail mail in this)
|
||||||
|
{
|
||||||
|
mailCount++;
|
||||||
|
Dictionary<string, string> iniSection = new Dictionary<string, string>();
|
||||||
|
iniSection["sender"] = mail.Sender;
|
||||||
|
iniSection["recipient"] = mail.Recipient;
|
||||||
|
iniSection["content"] = mail.Content;
|
||||||
|
iniSection["timestamp"] = mail.DateSent.ToString();
|
||||||
|
iniSection["anonymous"] = mail.Anonymous.ToString();
|
||||||
|
iniFileDict["mail" + mailCount] = iniSection;
|
||||||
|
}
|
||||||
|
INIFile.WriteFile(filePath, iniFileDict, "Mail Database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Mail sent from a player to another player
|
||||||
|
/// </summary>
|
||||||
|
private class Mail
|
||||||
|
{
|
||||||
|
private string sender;
|
||||||
|
private string senderLower;
|
||||||
|
private string recipient;
|
||||||
|
private string message;
|
||||||
|
private DateTime datesent;
|
||||||
|
private bool delivered;
|
||||||
|
private bool anonymous;
|
||||||
|
|
||||||
|
public Mail(string sender, string recipient, string message, bool anonymous, DateTime datesent)
|
||||||
|
{
|
||||||
|
this.sender = sender;
|
||||||
|
this.senderLower = sender.ToLower();
|
||||||
|
this.recipient = recipient;
|
||||||
|
this.message = message;
|
||||||
|
this.datesent = datesent;
|
||||||
|
this.delivered = false;
|
||||||
|
this.anonymous = anonymous;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Sender { get { return sender; } }
|
||||||
|
public string SenderLowercase { get { return senderLower; } }
|
||||||
|
public string Recipient { get { return recipient; } }
|
||||||
|
public string Content { get { return message; } }
|
||||||
|
public DateTime DateSent { get { return datesent; } }
|
||||||
|
public bool Delivered { get { return delivered; } }
|
||||||
|
public bool Anonymous { get { return anonymous; } }
|
||||||
|
public void setDelivered() { delivered = true; }
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Format("{0} {1} {2} {3}", Sender, Recipient, Content, DateSent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal variables
|
||||||
|
private int maxMessageLength = 0;
|
||||||
|
private DateTime nextMailSend = DateTime.Now;
|
||||||
|
private MailDatabase mailDatabase = new MailDatabase();
|
||||||
|
private IgnoreList ignoreList = new IgnoreList();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialization of the Mailer bot
|
||||||
|
/// </summary>
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
LogDebugToConsole("Initializing Mailer with settings:");
|
||||||
|
LogDebugToConsole(" - Database File: " + Settings.Mailer_DatabaseFile);
|
||||||
|
LogDebugToConsole(" - Ignore List: " + Settings.Mailer_IgnoreListFile);
|
||||||
|
LogDebugToConsole(" - Public Interactions: " + Settings.Mailer_PublicInteractions);
|
||||||
|
LogDebugToConsole(" - Max Mails per Player: " + Settings.Mailer_MaxMailsPerPlayer);
|
||||||
|
LogDebugToConsole(" - Max Database Size: " + Settings.Mailer_MaxDatabaseSize);
|
||||||
|
LogDebugToConsole(" - Mail Retention: " + Settings.Mailer_MailRetentionDays + " days");
|
||||||
|
|
||||||
|
if (Settings.Mailer_MaxDatabaseSize <= 0)
|
||||||
|
{
|
||||||
|
LogToConsole("Cannot enable Mailer: Max Database Size must be greater than zero. Please review the settings.");
|
||||||
|
UnloadBot();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.Mailer_MaxMailsPerPlayer <= 0)
|
||||||
|
{
|
||||||
|
LogToConsole("Cannot enable Mailer: Max Mails per Player must be greater than zero. Please review the settings.");
|
||||||
|
UnloadBot();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings.Mailer_MailRetentionDays <= 0)
|
||||||
|
{
|
||||||
|
LogToConsole("Cannot enable Mailer: Mail Retention must be greater than zero. Please review the settings.");
|
||||||
|
UnloadBot();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(Settings.Mailer_DatabaseFile))
|
||||||
|
{
|
||||||
|
LogToConsole("Creating new database file: " + Path.GetFullPath(Settings.Mailer_DatabaseFile));
|
||||||
|
new MailDatabase().SaveToFile(Settings.Mailer_DatabaseFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!File.Exists(Settings.Mailer_IgnoreListFile))
|
||||||
|
{
|
||||||
|
LogToConsole("Creating new ignore list: " + Path.GetFullPath(Settings.Mailer_IgnoreListFile));
|
||||||
|
new IgnoreList().SaveToFile(Settings.Mailer_IgnoreListFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
LogDebugToConsole("Loading database file: " + Path.GetFullPath(Settings.Mailer_DatabaseFile));
|
||||||
|
mailDatabase = MailDatabase.FromFile(Settings.Mailer_DatabaseFile);
|
||||||
|
|
||||||
|
LogDebugToConsole("Loading ignore list: " + Path.GetFullPath(Settings.Mailer_IgnoreListFile));
|
||||||
|
ignoreList = IgnoreList.FromFile(Settings.Mailer_IgnoreListFile);
|
||||||
|
|
||||||
|
RegisterChatBotCommand("mailer", "Subcommands: getmails, addignored, getignored, removeignored", ProcessInternalCommand);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Standard settings for the bot.
|
||||||
|
/// </summary>
|
||||||
|
public override void AfterGameJoined()
|
||||||
|
{
|
||||||
|
maxMessageLength = GetMaxChatMessageLength()
|
||||||
|
- 44 // Deduct length of "/ 16CharPlayerName 16CharPlayerName mailed: "
|
||||||
|
- Settings.PrivateMsgsCmdName.Length; // Deduct length of "tell" command
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process chat messages from the server
|
||||||
|
/// </summary>
|
||||||
|
public override void GetText(string text)
|
||||||
|
{
|
||||||
|
string message = "";
|
||||||
|
string username = "";
|
||||||
|
text = GetVerbatim(text);
|
||||||
|
|
||||||
|
if (IsPrivateMessage(text, ref message, ref username) || (Settings.Mailer_PublicInteractions && IsChatMessage(text, ref message, ref username)))
|
||||||
|
{
|
||||||
|
string usernameLower = username.ToLower();
|
||||||
|
if (!ignoreList.Contains(usernameLower))
|
||||||
|
{
|
||||||
|
string command = message.Split(' ')[0].ToLower();
|
||||||
|
switch (command)
|
||||||
|
{
|
||||||
|
case "mail":
|
||||||
|
case "tellonym":
|
||||||
|
if (usernameLower != GetUsername().ToLower()
|
||||||
|
&& mailDatabase.Count < Settings.Mailer_MaxDatabaseSize
|
||||||
|
&& mailDatabase.Where(mail => mail.SenderLowercase == usernameLower).Count() < Settings.Mailer_MaxMailsPerPlayer)
|
||||||
|
{
|
||||||
|
Queue<string> args = new Queue<string>(Command.getArgs(message));
|
||||||
|
if (args.Count >= 2)
|
||||||
|
{
|
||||||
|
bool anonymous = (command == "tellonym");
|
||||||
|
string recipient = args.Dequeue();
|
||||||
|
message = string.Join(" ", args);
|
||||||
|
|
||||||
|
if (IsValidName(recipient))
|
||||||
|
{
|
||||||
|
if (message.Length <= maxMessageLength)
|
||||||
|
{
|
||||||
|
Mail mail = new Mail(username, recipient, message, anonymous, DateTime.Now);
|
||||||
|
LogToConsole("Saving message: " + mail.ToString());
|
||||||
|
mailDatabase.Add(mail);
|
||||||
|
mailDatabase.SaveToFile(Settings.Mailer_DatabaseFile);
|
||||||
|
SendPrivateMessage(username, "Message saved!");
|
||||||
|
}
|
||||||
|
else SendPrivateMessage(username, "Your message cannot be longer than " + maxMessageLength + " characters.");
|
||||||
|
}
|
||||||
|
else SendPrivateMessage(username, "Recipient '" + recipient + "' is not a valid player name.");
|
||||||
|
}
|
||||||
|
else SendPrivateMessage(username, "Usage: " + command + " <recipient> <message>");
|
||||||
|
}
|
||||||
|
else SendPrivateMessage(username, "Couldn't save Message. Limit reached!");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else LogDebugToConsole(username + " is ignored!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Called on each MCC tick, around 10 times per second
|
||||||
|
/// </summary>
|
||||||
|
public override void Update()
|
||||||
|
{
|
||||||
|
DateTime dateNow = DateTime.Now;
|
||||||
|
if (nextMailSend < dateNow)
|
||||||
|
{
|
||||||
|
LogDebugToConsole("Looking for mails to send @ " + DateTime.Now);
|
||||||
|
|
||||||
|
// Reload mail and ignore list database in case several instances are sharing the same database
|
||||||
|
mailDatabase = MailDatabase.FromFile(Settings.Mailer_DatabaseFile);
|
||||||
|
ignoreList = IgnoreList.FromFile(Settings.Mailer_IgnoreListFile);
|
||||||
|
|
||||||
|
// Process at most 3 mails at a time to avoid spamming. Other mails will be processed on next mail send
|
||||||
|
HashSet<string> onlinePlayer = new HashSet<string>(GetOnlinePlayers());
|
||||||
|
foreach (Mail mail in mailDatabase.Where(mail => !mail.Delivered && onlinePlayer.Contains(mail.Recipient)).Take(3))
|
||||||
|
{
|
||||||
|
string sender = mail.Anonymous ? "Anonymous" : mail.Sender;
|
||||||
|
SendPrivateMessage(mail.Recipient, sender + " mailed: " + mail.Content);
|
||||||
|
mail.setDelivered();
|
||||||
|
LogDebugToConsole("Delivered: " + mail.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
mailDatabase.RemoveAll(mail => mail.Delivered);
|
||||||
|
mailDatabase.RemoveAll(mail => mail.DateSent.AddDays(Settings.Mailer_MailRetentionDays) < DateTime.Now);
|
||||||
|
mailDatabase.SaveToFile(Settings.Mailer_DatabaseFile);
|
||||||
|
|
||||||
|
nextMailSend = dateNow.AddSeconds(10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interprets local commands.
|
||||||
|
/// </summary>
|
||||||
|
private string ProcessInternalCommand(string cmd, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length > 0)
|
||||||
|
{
|
||||||
|
string commandName = args[0].ToLower();
|
||||||
|
switch (commandName)
|
||||||
|
{
|
||||||
|
case "getmails":
|
||||||
|
return "== Mails in database ==\n" + string.Join("\n", mailDatabase);
|
||||||
|
|
||||||
|
case "getignored":
|
||||||
|
return "== Ignore list ==\n" + string.Join("\n", ignoreList);
|
||||||
|
|
||||||
|
case "addignored":
|
||||||
|
case "removeignored":
|
||||||
|
if (args.Length > 1 && IsValidName(args[1]))
|
||||||
|
{
|
||||||
|
string username = args[1].ToLower();
|
||||||
|
if (commandName == "addignored")
|
||||||
|
{
|
||||||
|
if (!ignoreList.Contains(username))
|
||||||
|
{
|
||||||
|
ignoreList.Add(username);
|
||||||
|
ignoreList.SaveToFile(Settings.Mailer_IgnoreListFile);
|
||||||
|
}
|
||||||
|
return "Added " + args[1] + " to the ignore list!";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (ignoreList.Contains(username))
|
||||||
|
{
|
||||||
|
ignoreList.Remove(username);
|
||||||
|
ignoreList.SaveToFile(Settings.Mailer_IgnoreListFile);
|
||||||
|
}
|
||||||
|
return "Removed " + args[1] + " from the ignore list!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else return "Missing or invalid name. Usage: " + commandName + " <username>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "See usage: /help mailer";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
111
MinecraftClient/INIFile.cs
Normal file
111
MinecraftClient/INIFile.cs
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MinecraftClient
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// INI File tools for parsing and generating user-friendly INI files
|
||||||
|
/// By ORelio (c) 2014 - CDDL 1.0
|
||||||
|
/// </summary>
|
||||||
|
static class INIFile
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Parse a INI file into a dictionary.
|
||||||
|
/// Values can be accessed like this: dict["section"]["setting"]
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iniFile">INI file to parse</param>
|
||||||
|
/// <param name="lowerCase">INI sections and keys will be converted to lowercase unless this parameter is set to false</param>
|
||||||
|
/// <exception cref="IOException">If failed to read the file</exception>
|
||||||
|
/// <returns>Parsed data from INI file</returns>
|
||||||
|
public static Dictionary<string, Dictionary<string, string>> ParseFile(string iniFile, bool lowerCase = true)
|
||||||
|
{
|
||||||
|
var iniContents = new Dictionary<string, Dictionary<string, string>>();
|
||||||
|
string[] lines = File.ReadAllLines(iniFile, Encoding.UTF8);
|
||||||
|
string iniSection = "default";
|
||||||
|
foreach (string lineRaw in lines)
|
||||||
|
{
|
||||||
|
string line = lineRaw.Split('#')[0].Trim();
|
||||||
|
if (line.Length > 0 && line[0] != ';')
|
||||||
|
{
|
||||||
|
if (line[0] == '[' && line[line.Length - 1] == ']')
|
||||||
|
{
|
||||||
|
iniSection = line.Substring(1, line.Length - 2);
|
||||||
|
if (lowerCase)
|
||||||
|
iniSection = iniSection.ToLower();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string argName = line.Split('=')[0];
|
||||||
|
if (lowerCase)
|
||||||
|
argName = argName.ToLower();
|
||||||
|
if (line.Length > (argName.Length + 1))
|
||||||
|
{
|
||||||
|
string argValue = line.Substring(argName.Length + 1);
|
||||||
|
if (!iniContents.ContainsKey(iniSection))
|
||||||
|
iniContents[iniSection] = new Dictionary<string, string>();
|
||||||
|
iniContents[iniSection][argName] = argValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return iniContents;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Write given data into an INI file
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="iniFile">File to write into</param>
|
||||||
|
/// <param name="contents">Data to put into the file</param>
|
||||||
|
/// <param name="description">INI file description, inserted as a comment on first line of the INI file</param>
|
||||||
|
/// <param name="autoCase">Automatically change first char of section and keys to uppercase</param>
|
||||||
|
public static void WriteFile(string iniFile, Dictionary<string, Dictionary<string, string>> contents, string description = null, bool autoCase = true)
|
||||||
|
{
|
||||||
|
List<string> lines = new List<string>();
|
||||||
|
if (!String.IsNullOrWhiteSpace(description))
|
||||||
|
lines.Add('#' + description);
|
||||||
|
foreach (var section in contents)
|
||||||
|
{
|
||||||
|
if (lines.Count > 0)
|
||||||
|
lines.Add("");
|
||||||
|
if (!String.IsNullOrEmpty(section.Key))
|
||||||
|
{
|
||||||
|
lines.Add("[" + (autoCase ? char.ToUpper(section.Key[0]) + section.Key.Substring(1) : section.Key) + ']');
|
||||||
|
foreach (var item in section.Value)
|
||||||
|
if (!String.IsNullOrEmpty(item.Key))
|
||||||
|
lines.Add((autoCase ? char.ToUpper(item.Key[0]) + item.Key.Substring(1) : item.Key) + '=' + item.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
File.WriteAllLines(iniFile, lines, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert an integer from a string or return 0 if failed to parse
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">String to parse</param>
|
||||||
|
/// <returns>Int value</returns>
|
||||||
|
public static int Str2Int(string str)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Convert.ToInt32(str);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert a 0/1 or True/False value to boolean
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="str">String to parse</param>
|
||||||
|
/// <returns>Boolean value</returns>
|
||||||
|
public static bool Str2Bool(string str)
|
||||||
|
{
|
||||||
|
return str.ToLower() == "true" || str == "1";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -175,6 +175,7 @@ namespace MinecraftClient
|
||||||
if (Settings.AutoAttack_Enabled) { BotLoad(new ChatBots.AutoAttack()); }
|
if (Settings.AutoAttack_Enabled) { BotLoad(new ChatBots.AutoAttack()); }
|
||||||
if (Settings.AutoFishing_Enabled) { BotLoad(new ChatBots.AutoFishing()); }
|
if (Settings.AutoFishing_Enabled) { BotLoad(new ChatBots.AutoFishing()); }
|
||||||
if (Settings.AutoEat_Enabled) { BotLoad(new ChatBots.AutoEat(Settings.AutoEat_hungerThreshold)); }
|
if (Settings.AutoEat_Enabled) { BotLoad(new ChatBots.AutoEat(Settings.AutoEat_hungerThreshold)); }
|
||||||
|
if (Settings.Mailer_Enabled) { BotLoad(new ChatBots.Mailer()); }
|
||||||
if (Settings.AutoCraft_Enabled) { BotLoad(new AutoCraft(Settings.AutoCraft_configFile)); }
|
if (Settings.AutoCraft_Enabled) { BotLoad(new AutoCraft(Settings.AutoCraft_configFile)); }
|
||||||
if (Settings.AutoDrop_Enabled) { BotLoad(new AutoDrop(Settings.AutoDrop_Mode, Settings.AutoDrop_items)); }
|
if (Settings.AutoDrop_Enabled) { BotLoad(new AutoDrop(Settings.AutoDrop_Mode, Settings.AutoDrop_items)); }
|
||||||
|
|
||||||
|
|
@ -751,6 +752,15 @@ namespace MinecraftClient
|
||||||
|
|
||||||
#region Getters: Retrieve data for use in other methods or ChatBots
|
#region Getters: Retrieve data for use in other methods or ChatBots
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get max length for chat messages
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Max length, in characters</returns>
|
||||||
|
public int GetMaxChatMessageLength()
|
||||||
|
{
|
||||||
|
return handler.GetMaxChatMessageLength();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all inventories. ID 0 is the player inventory.
|
/// Get all inventories. ID 0 is the player inventory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,7 @@
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Compile Include="AutoTimeout.cs" />
|
<Compile Include="AutoTimeout.cs" />
|
||||||
<Compile Include="ChatBots\AutoDrop.cs" />
|
<Compile Include="ChatBots\AutoDrop.cs" />
|
||||||
|
<Compile Include="ChatBots\Mailer.cs" />
|
||||||
<Compile Include="Commands\Entitycmd.cs" />
|
<Compile Include="Commands\Entitycmd.cs" />
|
||||||
<Compile Include="ChatBots\Alerts.cs" />
|
<Compile Include="ChatBots\Alerts.cs" />
|
||||||
<Compile Include="ChatBots\AntiAFK.cs" />
|
<Compile Include="ChatBots\AntiAFK.cs" />
|
||||||
|
|
@ -111,6 +112,7 @@
|
||||||
<Compile Include="Commands\Sneak.cs" />
|
<Compile Include="Commands\Sneak.cs" />
|
||||||
<Compile Include="Commands\Useblock.cs" />
|
<Compile Include="Commands\Useblock.cs" />
|
||||||
<Compile Include="Commands\UseItem.cs" />
|
<Compile Include="Commands\UseItem.cs" />
|
||||||
|
<Compile Include="INIFile.cs" />
|
||||||
<Compile Include="Inventory\Container.cs" />
|
<Compile Include="Inventory\Container.cs" />
|
||||||
<Compile Include="Inventory\ContainerType.cs" />
|
<Compile Include="Inventory\ContainerType.cs" />
|
||||||
<Compile Include="Inventory\ContainerTypeExtensions.cs" />
|
<Compile Include="Inventory\ContainerTypeExtensions.cs" />
|
||||||
|
|
|
||||||
|
|
@ -167,18 +167,30 @@ namespace MinecraftClient
|
||||||
//AutoCraft
|
//AutoCraft
|
||||||
public static bool AutoCraft_Enabled = false;
|
public static bool AutoCraft_Enabled = false;
|
||||||
public static string AutoCraft_configFile = @"autocraft\config.ini";
|
public static string AutoCraft_configFile = @"autocraft\config.ini";
|
||||||
|
|
||||||
|
//Mailer
|
||||||
|
public static bool Mailer_Enabled = false;
|
||||||
|
public static string Mailer_DatabaseFile = "MailerDatabase.ini";
|
||||||
|
public static string Mailer_IgnoreListFile = "MailerIgnoreList.ini";
|
||||||
|
public static bool Mailer_PublicInteractions = false;
|
||||||
|
public static int Mailer_MaxMailsPerPlayer = 10;
|
||||||
|
public static int Mailer_MaxDatabaseSize = 10000;
|
||||||
|
public static int Mailer_MailRetentionDays = 30;
|
||||||
|
|
||||||
//AutoDrop
|
//AutoDrop
|
||||||
public static bool AutoDrop_Enabled = false;
|
public static bool AutoDrop_Enabled = false;
|
||||||
public static string AutoDrop_Mode = "include";
|
public static string AutoDrop_Mode = "include";
|
||||||
public static string AutoDrop_items = "";
|
public static string AutoDrop_items = "";
|
||||||
|
|
||||||
|
|
||||||
//Custom app variables and Minecraft accounts
|
//Custom app variables and Minecraft accounts
|
||||||
private static readonly Dictionary<string, object> AppVars = new Dictionary<string, object>();
|
private static readonly Dictionary<string, object> AppVars = new Dictionary<string, object>();
|
||||||
private static readonly Dictionary<string, KeyValuePair<string, string>> Accounts = new Dictionary<string, KeyValuePair<string, string>>();
|
private static readonly Dictionary<string, KeyValuePair<string, string>> Accounts = new Dictionary<string, KeyValuePair<string, string>>();
|
||||||
private static readonly Dictionary<string, KeyValuePair<string, ushort>> Servers = new Dictionary<string, KeyValuePair<string, ushort>>();
|
private static readonly Dictionary<string, KeyValuePair<string, ushort>> Servers = new Dictionary<string, KeyValuePair<string, ushort>>();
|
||||||
|
|
||||||
private enum ParseMode { Default, Main, AppVars, Proxy, MCSettings, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, ChatFormat, AutoRespond, AutoAttack, AutoFishing, AutoEat, AutoCraft, AutoDrop };
|
|
||||||
|
private enum ParseMode { Default, Main, AppVars, Proxy, MCSettings, AntiAFK, Hangman, Alerts, ChatLog, AutoRelog, ScriptScheduler, RemoteControl, ChatFormat, AutoRespond, AutoAttack, AutoFishing, AutoEat, AutoCraft, AutoDrop, Mailer };
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Load settings from the give INI file
|
/// Load settings from the give INI file
|
||||||
|
|
@ -223,7 +235,9 @@ namespace MinecraftClient
|
||||||
case "autofishing": pMode = ParseMode.AutoFishing; break;
|
case "autofishing": pMode = ParseMode.AutoFishing; break;
|
||||||
case "autoeat": pMode = ParseMode.AutoEat; break;
|
case "autoeat": pMode = ParseMode.AutoEat; break;
|
||||||
case "autocraft": pMode = ParseMode.AutoCraft; break;
|
case "autocraft": pMode = ParseMode.AutoCraft; break;
|
||||||
|
case "mailer": pMode = ParseMode.Mailer; break;
|
||||||
case "autodrop": pMode = ParseMode.AutoDrop; break;
|
case "autodrop": pMode = ParseMode.AutoDrop; break;
|
||||||
|
|
||||||
default: pMode = ParseMode.Default; break;
|
default: pMode = ParseMode.Default; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -576,6 +590,19 @@ namespace MinecraftClient
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ParseMode.Mailer:
|
||||||
|
switch (argName.ToLower())
|
||||||
|
{
|
||||||
|
case "enabled": Mailer_Enabled = str2bool(argValue); break;
|
||||||
|
case "database": Mailer_DatabaseFile = argValue; break;
|
||||||
|
case "ignorelist": Mailer_IgnoreListFile = argValue; break;
|
||||||
|
case "publicinteractions": Mailer_PublicInteractions = str2bool(argValue); break;
|
||||||
|
case "maxmailsperplayer": Mailer_MaxMailsPerPlayer = str2int(argValue); break;
|
||||||
|
case "maxdatabasesize": Mailer_MaxDatabaseSize = str2int(argValue); break;
|
||||||
|
case "retentiondays": Mailer_MailRetentionDays = str2int(argValue); break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -735,6 +762,16 @@ namespace MinecraftClient
|
||||||
+ "enabled=false\r\n"
|
+ "enabled=false\r\n"
|
||||||
+ "configfile=autocraft\\config.ini\r\n"
|
+ "configfile=autocraft\\config.ini\r\n"
|
||||||
+ "\r\n"
|
+ "\r\n"
|
||||||
|
+ "[Mailer]\r\n"
|
||||||
|
+ "# Let the bot act like a mail plugin\r\n"
|
||||||
|
+ "enabled=false\r\n"
|
||||||
|
+ "database=MailerDatabase.ini\r\n"
|
||||||
|
+ "ignorelist=MailerIgnoreList.ini\r\n"
|
||||||
|
+ "publicinteractions=false\r\n"
|
||||||
|
+ "maxmailsperplayer=10\r\n"
|
||||||
|
+ "maxdatabasesize=10000\r\n"
|
||||||
|
+ "retentiondays=30\r\n"
|
||||||
|
+ "\r\n"
|
||||||
+ "[AutoDrop]\r\n"
|
+ "[AutoDrop]\r\n"
|
||||||
+ "# Inventory Handling NEED to be enabled first\r\n"
|
+ "# Inventory Handling NEED to be enabled first\r\n"
|
||||||
+ "enabled=false\r\n"
|
+ "enabled=false\r\n"
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,30 @@ Steps for using this bot:
|
||||||
4. Do `/useitem` and you should see "threw a fishing rod"
|
4. Do `/useitem` and you should see "threw a fishing rod"
|
||||||
5. To stop fishing, do `/useitem` again
|
5. To stop fishing, do `/useitem` again
|
||||||
|
|
||||||
|
Using the Mailer
|
||||||
|
------
|
||||||
|
|
||||||
|
The Mailer bot can store and relay mails much like Essential's /mail command.
|
||||||
|
|
||||||
|
* /tell <Bot> mail [RECIPIENT] [MESSAGE]: Save your message for future delivery
|
||||||
|
* /tell <Bot> tellonym [RECIPIENT] [MESSAGE]: Same, but the recipient will receive an anonymous mail
|
||||||
|
|
||||||
|
The bot will automatically deliver the mail when the recipient is online.
|
||||||
|
The bot also offers a /mailer command from the MCC command prompt:
|
||||||
|
|
||||||
|
* /mailer getmails: Show all mails in the console
|
||||||
|
* /mailer addignored [NAME]: Prevent a specific player from sending mails
|
||||||
|
* /mailer removeignored [NAME]: Lift the mailer restriction for this player
|
||||||
|
* /mailer getignored: Show all ignored players
|
||||||
|
|
||||||
|
**CAUTION:** The bot identifies players by their name (Not by UUID!).
|
||||||
|
A nickname plugin or a minecraft rename may cause mails going to the wrong player!
|
||||||
|
Never write something to the bot you wouldn't say in the normal chat (You have been warned!)
|
||||||
|
|
||||||
|
**Mailer Network:** The Mailer bot can relay messages between servers.
|
||||||
|
To set up a network of two or more bots, launch several instances with the bot activated and the same database.
|
||||||
|
If you launch two instances from one .exe they should syncronize automatically to the same file.
|
||||||
|
|
||||||
Disclaimer
|
Disclaimer
|
||||||
------
|
------
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue