Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- //https://github.com/RMSoftware-Development Commit soon.
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- using System.IO;
- using Discord;
- using Discord.WebSocket;
- using System.Reflection;
- using Discord.Commands;
- using System.Threading;
- using Microsoft.Extensions.DependencyInjection;
- using RMSoftware.IO;
- using System.Diagnostics;
- using Newtonsoft.Json;
- using System.Runtime.ExceptionServices;
- namespace RMSoftware.ModularBot
- {
- class Program
- {
- #region STATIC fields & properties
- public static DateTime StartTime;
- public static bool BCMDStarted = false;
- public static bool WizardDebug = false;
- public static bool discon = false;
- public static bool CriticalError = false;
- public static bool RestartRequested = false;
- public static Exception crashException = null;
- static string auth = "";
- static bool CRASH = false;
- public static string[] ARGS = null;
- public static CustomCommandManager ccmg { get; private set; }
- public static CmdRoleManager rolemgt { get; private set; }
- public static char CommandPrefix { get; private set; }
- public static DiscordSocketClient _client;
- static List<SocketMessage> messageQueue = new List<SocketMessage>();
- public static bool LOG_ONLY_MODE = false;//Set by args on start. if true, console header and resets are ignored. Should only be done if hosting the process in a UI.
- public static bool MessagesDisabled = false;
- public static ConsoleLogWriter writer = new ConsoleLogWriter();
- /// <summary>
- /// Application's main configuration file
- /// </summary>
- public static INIFile MainCFG { get; private set;}
- #endregion
- #region Instance fields & properties
- public IServiceCollection serviceCollection;
- public IServiceProvider services;
- public CommandService cmdsvr = new Discord.Commands.CommandService();
- #endregion
- #region STATIC methods
- public static int Main(string[] args)
- {
- ARGS = args;
- try
- {
- foreach (string item in args)
- {
- if (item.ToLower() == "-log_only")
- {
- LOG_ONLY_MODE = true;
- }
- if (item.ToLower() == "-crashed")
- {
- CRASH = true;
- }
- if (item.StartsWith("-auth"))
- {
- auth = item.Split(' ')[1];
- }
- }
- BCMDStarted = false;
- ConsoleGUIReset(ConsoleColor.Green, ConsoleColor.Black, "Welcome", 79, 45);
- Console.Title = "RMSoftware.ModularBOT";
- Console.WriteLine("Oh, Hello! Greetings! Salutations! Stuff is about to happen... Please wait...");
- System.Threading.Thread.Sleep(800);
- ConsoleWriteImage(Prog.res1.Resource1.RMSoftwareICO);
- System.Threading.Thread.Sleep(3000);
- ConsoleGUIReset(ConsoleColor.Cyan, ConsoleColor.Black, "Program Starting");
- ccmg = new CustomCommandManager();
- rolemgt = new CmdRoleManager();
- AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
- //AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;
- SetupWizard();
- if (auth.Length == 0)
- {
- ConsoleGUIReset(ConsoleColor.White, ConsoleColor.DarkBlue, "Initializing");
- Console.WriteLine("You didn't specify an authorization token as parameter....");
- Console.WriteLine("usage: RMSoftwareModularBot.exe <authToken>");
- Console.WriteLine("No big deal though, Will use configuration instead");
- auth = Program.MainCFG.GetCategoryByName("Application").GetEntryByName("botToken").GetAsString();
- }
- //set command prefix
- CommandPrefix = Convert.ToChar(MainCFG.GetCategoryByName("Application").GetEntryByName("cmdPrefix").GetAsInteger());
- Program.LogToConsole(new LogMessage(LogSeverity.Info, "Initialize", $"Using the command prefix: {(char)CommandPrefix}"));
- var prg = new Program();
- prg.MainAsync(auth).GetAwaiter().GetResult();
- Task.Run(new Action(ReadConsole));
- Task.Run(new Action(writer.ProcessStack().GetAwaiter().GetResult));
- SpinWait.SpinUntil(BotShutdown);//Wait until shutdown;
- BCMDStarted = false;
- ConsoleGUIReset(ConsoleColor.White, ConsoleColor.DarkRed, "Disconnected");
- if (CriticalError)
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Critical, "Session", "Failed to resume previous session.",crashException));
- using (FileStream fs = File.Create("CRASH.LOG"))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- LogMessage m = new LogMessage(LogSeverity.Critical, "Session", crashException.Message, crashException);
- sw.WriteLine(m.ToString());
- List<string> restart_args = new List<string>();
- restart_args.AddRange(ARGS);
- if (!restart_args.Contains("-crashed"))
- {
- restart_args.Add("-crashed");
- }
- ARGS = restart_args.ToArray();
- sw.Flush();
- }
- }
- if (!LOG_ONLY_MODE)
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Warning, "Application", "Restarting in 4 seconds..."));
- Thread.Sleep(1000);
- }
- RestartRequested = true;
- _client = null;
- }
- }
- catch (Exception ex)
- {
- crashException = ex;
- ConsoleGUIReset(ConsoleColor.White,ConsoleColor.DarkRed,"Critical Application Error.");
- Program.LogToConsole(new LogMessage(LogSeverity.Critical, "Exception", ex.Message, ex));
- CriticalError = true;
- RestartRequested = true;
- using (FileStream fs = File.Create("CRASH.LOG"))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- LogMessage m = new LogMessage(LogSeverity.Critical, "Session", ex.Message, ex);
- sw.WriteLine(m.ToString());
- List<string> restart_args = new List<string>();
- restart_args.AddRange(ARGS);
- if (!restart_args.Contains("-crashed"))
- {
- restart_args.Add("-crashed");
- }
- ARGS = restart_args.ToArray();
- sw.Flush();
- }
- }
- using (FileStream fs = new FileStream("ERRORS.LOG", FileMode.Append))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- sw.WriteLine(DateTime.Today.ToString("MM/dd/yyyy") + " " + ex.ToString());
- sw.Flush();
- }
- }
- }
- if (RestartRequested)
- {
- Process p = new Process();
- string flattened = "";
- foreach (string item in ARGS)
- {
- flattened += item + " ";
- }
- p.StartInfo = new ProcessStartInfo(Process.GetCurrentProcess().MainModule.FileName, flattened);
- ConsoleGUIReset(ConsoleColor.White, ConsoleColor.DarkRed, "Disconnected");
- writer.WriteEntry(new LogMessage(LogSeverity.Warning, "Program", "Restarting in 3...")).GetAwaiter().GetResult();//using direct writer to try and prevent blanks.
- Thread.Sleep(1000);
- ConsoleGUIReset(ConsoleColor.White, ConsoleColor.DarkRed, "Disconnected");
- writer.WriteEntry(new LogMessage(LogSeverity.Warning, "Program", "Restarting in 2...")).GetAwaiter().GetResult();
- Thread.Sleep(1000);
- ConsoleGUIReset(ConsoleColor.White, ConsoleColor.DarkRed, "Disconnected");
- writer.WriteEntry(new LogMessage(LogSeverity.Warning, "Program", "Restarting in 1...")).GetAwaiter().GetResult();
- Thread.Sleep(1000);
- p.Start();
- return 0x00000c4;
- }
- writer.WriteEntry(new LogMessage(LogSeverity.Warning, "Program", "Termination.")).GetAwaiter().GetResult();
- if (!CriticalError)
- {
- return 4007;//NOT OKAY
- }
- else
- {
- return 200;//OK status
- }
- }
- private static void CurrentDomain_FirstChanceException(object sender, FirstChanceExceptionEventArgs e)
- {
- writer.push(new LogMessage(LogSeverity.Critical, "FirstERR", e.Exception.ToString()));
- }
- static void ReadConsole()
- {
- ulong chID = 0;
- while (true)
- {
- if (discon)
- {
- break;
- }
- string input = Console.ReadLine();
- if (discon)
- {
- if(string.IsNullOrWhiteSpace(input))
- {
- return;
- }
- }
- if (input.ToLower() == "bot.stopbot")
- {
- _client.SetGameAsync("");
- System.Threading.Thread.Sleep(2000);
- _client.SetStatusAsync(UserStatus.Invisible);
- System.Threading.Thread.Sleep(2000);
- Program.BCMDStarted = false;
- _client.StopAsync();
- System.Threading.Thread.Sleep(3000);//Allow the bot to shut down fully before telling Main() to scream at user to finger the keyboard to close the console.
- Program.discon = true;
- break;
- }
- if (input.ToLower() == "cn_term")
- {
- Console.WriteLine("Termination");
- break;
- }
- if (input.ToLower() == "bot.disablecmd")
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Warning, "Console", "Command processing disabled!"));
- _client.SetStatusAsync(UserStatus.DoNotDisturb);
- _client.SetGameAsync("");
- MessagesDisabled = true;
- }
- if (input.ToLower() == "bot.enablecmd")
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Info, "Console", "Command processing enabled."));
- _client.SetStatusAsync(UserStatus.Online);
- _client.SetGameAsync("READY!");
- MessagesDisabled = false;
- }
- if (input.ToLower().StartsWith("bot.status"))
- {
- string status = input.Remove(0, 10).Trim();
- Program.LogToConsole(new LogMessage(LogSeverity.Warning, "Client", "client status changed."));
- _client.SetGameAsync(status);
- }
- if (input.StartsWith("setgch"))
- {
- input = input.Remove(0, 6).Trim();
- if (!ulong.TryParse(input, out chID))
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Error, "Console", "Invalid ULONG."));
- continue;
- }
- }
- if (input.StartsWith("conmsg"))
- {
- input = input.Remove(0, 6).Trim();
- SocketTextChannel Channel = _client.GetChannel(chID) as SocketTextChannel;
- if (Channel == null)
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Warning, "Console", "Invalid channel."));
- continue;
- }
- Channel.SendMessageAsync(input);
- }
- }
- }
- private static void SetupWizard()
- {
- if (InitializeConfig())//If true, do setup.
- {
- #region Page 1
- ConsoleGUIReset(ConsoleColor.Cyan, ConsoleColor.Black, "Welcome");
- Console.WriteLine("Welcome to the initial setup wizard for your new modular discord bot...\r\n Some things to note before we get started:");
- Console.WriteLine("\t- This bot requires a token. If you don't know what that is," +
- " please visit this site first!");
- Console.WriteLine("\t- https://discordapp.com/developers/docs/intro");
- Console.WriteLine("\t- Privacy notice: This application will output any message that mentions the bot, or messages that start with ! to the console.\r\n\t" +
- " THEY DO NOT GET SAVED OR POSTED ANYWHERE ELSE... That would be creepy and probably illegal...");
- Console.WriteLine("\r\nPress ENTER to continue...");
- Console.ReadLine();
- #endregion
- #region Page 2
- ConsoleGUIReset(ConsoleColor.Green, ConsoleColor.Black, "Step 1: Token Configuration");
- Console.WriteLine("As mentioned before, this bot requires a token. It can be added in one of two ways.");
- Console.WriteLine("\t- METHOD 1: Program arguments. Simply launch the program from a batch file,\r\n\t- USAGE: RMSoftwareModularBot.exe <put token here>");
- Console.WriteLine("\t- METHOD 2: Configure it. Actually, let's do that now.");
- Console.WriteLine("Go ahead and find your token and copy/paste* it here, then press enter.");
- Console.WriteLine("*Only if your CMD console will let you... If not, that sucks... You can painfully type it in also...");
- Console.Write("> ");
- string conf_Token = Console.ReadLine();
- if (!WizardDebug)
- {
- MainCFG.CreateCategory("Application");
- MainCFG.CreateEntry("Application", "botToken", conf_Token);
- }
- Console.WriteLine("Okay! Please remember, You can also start the program with a token as an argument.");
- Console.WriteLine("Be advised, the token in the configuration is ignored when using the program parameter.");
- Console.WriteLine("\r\nPress ENTER to continue...");
- Console.ReadLine();
- #endregion
- #region Page 3
- ConsoleGUIReset(ConsoleColor.Green, ConsoleColor.Black, "Step 2: Control Channel & Command prefix");
- Console.WriteLine("Ah, yes... The Control channel...");
- Console.WriteLine("\t- Whenever you start your bot, it will execute AutoStart.bcmd, a script full of commands to prepare for that bot life...");
- Console.WriteLine("\t- However, in order to do this, the bot needs to know where to send these messages and commands...");
- Console.WriteLine("\t- Not doing this now would result in a crashing bot that doesn't know what to do with its life.");
- Console.WriteLine("\t- All I need is the ID of that channel to put into the configuration.");
- Console.WriteLine("\t- If you need a refresher on how to find a channel ID: https://goo.gl/nqAbhw \r\n\t" +
- "(It goes to the discord's official docs)");
- Console.WriteLine("copy/paste or painfully type in your Initialization Channel's id and press enter");
- Console.Write("> ");
- string conf_BotChannel = Console.ReadLine();
- if (!WizardDebug)
- {
- Program.MainCFG.CreateEntry("Application", "botChannel", conf_BotChannel);
- }
- Console.WriteLine("Great! Now that channel will be the bot's main log channel...");
- Console.WriteLine();
- Console.WriteLine("Now... The Command Prefix: Please enter a single character (Recommended: A symbol of some kind), to use as the bot's command prefix");
- Console.Write("> ");
- int conf_cmdPrefix = Console.Read();
- if (!WizardDebug)
- {
- Program.MainCFG.CreateEntry("Application", "cmdPrefix", conf_cmdPrefix);
- Program.MainCFG.SaveConfiguration();//save
- }
- Console.WriteLine("Great! Your bot will use '" + Convert.ToChar(conf_cmdPrefix) + "' [without quotes] as a prefix for it's commands!");
- Console.WriteLine("\r\nPress ENTER to continue...");
- Console.ReadLine();
- #endregion
- #region Page 4
- ConsoleGUIReset(ConsoleColor.Cyan, ConsoleColor.Black, "Step 3: Final Notes & ProTips");
- Console.WriteLine("That is all the configuration for right now! Here are a few more things to know:");
- Console.WriteLine("\t- If you want to re-run this configuration wizard, delete the 'rmsftModBot.ini' file in the program directory.");
- Console.WriteLine("\t- The source code for this bot is available on http://rmsoftware.org");
- Console.WriteLine("\r\nCORE Command usage (in discord):");
- Console.WriteLine("\t- use <prefix>addmgrole [@roles] to add roles to the command user database.");
- Console.WriteLine("\t- usage: <prefix>addcmd <command name> <CmdMgmtOnly[true/false]> <LockToGuild[true/false]> <action>");
- Console.WriteLine("\t- Actions: Any text/emotes with optional formatting.");
- Console.WriteLine("\t- <prefix>addcmd sample1SplitParam false false splitparam 3|" +
- " This is a sample of splitparam. Var1: {0} var2: {1} and var3: {2} all walked into a bar");
- Console.WriteLine("\t- <prefix>addcmd hug false false You hug {params} for a long time");
- Console.WriteLine("\t- More Action parameters: EXEC and CLI_EXEC ");
- Console.WriteLine("\t- <prefix>addcmd exectest falase false EXEC modname.dll ModNameSpace.ModClass StaticMethod {params}");
- Console.WriteLine("\t- <prefix>addcmd exectest falase false CLI_EXEC modname.dll ModNameSpace.ModClass StaticMethod {params}");
- Console.WriteLine("\t - NOTE: splitparam is not supported for EXEC or CLI_EXEC");
- Console.WriteLine("\t - NOTE: EXEC: Allows you to execute a class method for a more advanced command");
- Console.WriteLine("\t - NOTE: CLI_EXEC is the same thing, but it gives the class access to the bot directly...");
- Console.WriteLine("Extra Configuration Options:");
- Console.WriteLine("\t - Adding the line DisableCore=True to the [Application] section of the config file, will disable all core commands.");
- Console.WriteLine("\t - Remember this will disable the ability to manage commands. putting the bot in a sort of 'read-only' state.");
- Console.WriteLine("Override core: ");
- Console.WriteLine("\t - You can create custom commands that use the same name as core commands. This is useful for overriding core commands for even more customization...");
- Console.WriteLine("\r\nPlease visit http://rmsoftware.org/rmsoftwareModularBot for more information and documentation.");
- Console.WriteLine("\r\nPress ENTER to launch the bot!");
- Console.ReadLine();
- #endregion
- }
- }
- private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
- {
- //Exception ex = e.ExceptionObject as Exception;
- //LogToConsole("CritERR", ex.Message);
- //ConsoleColor Last = Console.ForegroundColor;
- //Console.ForegroundColor = ConsoleColor.Gray;
- //LogToConsole("ExStack\r\n\r\n", ex.StackTrace);
- //Console.ForegroundColor = Last;
- CriticalError = true;
- RestartRequested = true;
- crashException = (Exception)e.ExceptionObject;
- using (FileStream fs = File.Create("CRASH.LOG"))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- LogMessage m = new LogMessage(LogSeverity.Critical, "Session", crashException.Message, crashException);
- sw.WriteLine(m.ToString());
- List<string> restart_args = new List<string>();
- restart_args.AddRange(ARGS);
- if (!restart_args.Contains("-crashed"))
- {
- restart_args.Add("-crashed");
- }
- ARGS = restart_args.ToArray();
- sw.Flush();
- }
- }
- using (FileStream fs = new FileStream("ERRORS.LOG", FileMode.Append))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- sw.WriteLine(DateTime.Today.ToString("MM/dd/yyyy") + " " + ((Exception)e.ExceptionObject).ToString());
- sw.Flush();
- }
- }
- }
- static Func<bool> BotShutdown = delegate ()
- {
- return discon;
- };
- /// <summary>
- /// Reset the console layout using specified values
- /// </summary>
- /// <param name="fore">Text color</param>
- /// <param name="back">Background color</param>
- /// <param name="title">Console's header title (not window title)</param>
- public static void ConsoleGUIReset(ConsoleColor fore, ConsoleColor back, string title)
- {
- if(LOG_ONLY_MODE)
- {
- return;
- }
- Console.Clear();
- Console.SetWindowSize(144, 32);
- Console.SetBufferSize(144, 256);
- Console.BackgroundColor = back;
- Console.ForegroundColor = fore;
- Console.Clear();
- Console.BackgroundColor = ConsoleColor.Black;
- Console.ForegroundColor = ConsoleColor.White;
- DecorateTop();
- string WTitle = (""+DateTime.Now.ToString("HH:mm:ss") + " " + title + " - RMSoftwareModularBot v" + Assembly.GetExecutingAssembly().GetName().Version.ToString(4));
- string pTitle = WTitle.PadLeft(71+WTitle.Length/2);
- pTitle += "".PadRight(71-WTitle.Length/2);
- Console.Write("\u2551{0}\u2551", pTitle);
- DecorateBottom();
- Console.BackgroundColor = back;
- Console.ForegroundColor = fore;
- }
- /// <summary>
- /// Reset the console layout using specified values
- /// </summary>
- /// <param name="fore">Text color</param>
- /// <param name="back">Background color</param>
- /// <param name="title">Console's header title (not window title)</param>
- /// <param name="w">Console window & buffer width</param>
- /// <param name="h">Console window & buffer height</param>
- public static void ConsoleGUIReset(ConsoleColor fore, ConsoleColor back, string title,short w, short h)
- {
- if (LOG_ONLY_MODE)
- {
- return;
- }
- Console.Clear();
- Console.SetWindowSize(w, h);
- Console.SetBufferSize(w, h);
- Console.BackgroundColor = back;
- Console.ForegroundColor = fore;
- Console.Clear();
- Console.BackgroundColor = ConsoleColor.Black;
- Console.ForegroundColor = ConsoleColor.White;
- DecorateTop();
- string WTitle = ("" + DateTime.Now.ToString("HH:mm:ss") + " " + title + " - RMSoftwareModularBot v" + Assembly.GetExecutingAssembly().GetName().Version.ToString(4));
- string pTitle = WTitle.PadLeft(((w/2)+2) + WTitle.Length / 2);
- pTitle += "".PadRight(((w / 2)-3) - WTitle.Length / 2);
- Console.Write("\u2551{0}\u2551", pTitle);
- DecorateBottom();
- Console.BackgroundColor = back;
- Console.ForegroundColor = fore;
- }
- private static void DecorateTop()
- {
- for (int i = 0; i < Console.WindowWidth; i++)
- {
- if(i==0)
- {
- Console.Write("\u2554");
- continue;
- }
- if (i == Console.WindowWidth-1)
- {
- Console.Write("\u2557");
- break;
- }
- Console.Write("\u2550");
- }
- }
- private static void DecorateBottom()
- {
- for (int i = 0; i < Console.WindowWidth; i++)
- {
- if (i == 0)
- {
- Console.Write("\u255A");
- continue;
- }
- if (i == Console.WindowWidth - 1)
- {
- Console.Write("\u255D");
- break;
- }
- Console.Write("\u2550");
- }
- }
- public static void LogToConsole(LogMessage msg)
- {
- if(!LOG_ONLY_MODE)
- {
- //Console.WriteLine(l.ToString());
- writer.push(msg);
- }
- else
- {
- Console.WriteLine(JsonConvert.SerializeObject(msg));
- }
- if (msg.Exception != null)
- {
- using (FileStream fs = new FileStream("ERRORS.LOG", FileMode.Append))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- sw.WriteLine(DateTime.Today.ToString("MM/dd/yyyy") + " " + msg.ToString());
- sw.Flush();
- }
- }
- }
- }
- /// <summary>
- /// Initialize configuration.
- /// </summary>
- /// <returns>True if it generated a new file, or has zero categories in said file.</returns>
- private static bool InitializeConfig()
- {
- ConsoleGUIReset(ConsoleColor.Cyan, ConsoleColor.Black, "Initializing Configuration");
- Program.MainCFG = new INIFile("rmsftModBot.ini");
- if (Program.MainCFG.Categories.Count == 0)
- {
- return true;
- }
- else
- {
- if (Program.MainCFG.CheckForCategory("Application"))
- {
- if (Program.MainCFG.GetCategoryByName("Application").CheckForEntry("Dev-ShowWizard"))
- {
- WizardDebug = true;
- return Program.MainCFG.GetCategoryByName("Application").GetEntryByName("Dev-ShowWizard").GetAsBool();
- }
- //REQUIRED entries.
- if (!Program.MainCFG.GetCategoryByName("Application").CheckForEntry("botToken") ||
- !Program.MainCFG.GetCategoryByName("Application").CheckForEntry("botChannel") ||
- !Program.MainCFG.GetCategoryByName("Application").CheckForEntry("cmdPrefix"))
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Warning, "Warning", "Invalid or missing config. Reset all settings."));
- File.Delete("rmsftModBot.ini");
- Program.MainCFG = new INIFile("rmsftModBot.ini");//Re-write from scratch.
- return true;
- }
- }
- }
- return false;//basically the file is found and nothing broke.
- }
- #region Console pixel art - Courtesy of Stackoverflow.com
- static int[] cColors = { 0x000000, 0x000080, 0x008000, 0x008080, 0x800000, 0x800080, 0x808000, 0xC0C0C0, 0x808080, 0x0000FF, 0x00FF00, 0x00FFFF, 0xFF0000, 0xFF00FF, 0xFFFF00, 0xFFFFFF };
- private static bool term;
- public static void ConsoleWritePixel(System.Drawing.Color cValue)
- {
- System.Drawing.Color[] cTable = cColors.Select(x => System.Drawing.Color.FromArgb(x)).ToArray();
- char[] rList = new char[] { (char)9617, (char)9618, (char)9619, (char)9608 }; // 1/4, 2/4, 3/4, 4/4
- int[] bestHit = new int[] { 0, 0, 4, int.MaxValue }; //ForeColor, BackColor, Symbol, Score
- for (int rChar = rList.Length; rChar > 0; rChar--)
- {
- for (int cFore = 0; cFore < cTable.Length; cFore++)
- {
- for (int cBack = 0; cBack < cTable.Length; cBack++)
- {
- int R = (cTable[cFore].R * rChar + cTable[cBack].R * (rList.Length - rChar)) / rList.Length;
- int G = (cTable[cFore].G * rChar + cTable[cBack].G * (rList.Length - rChar)) / rList.Length;
- int B = (cTable[cFore].B * rChar + cTable[cBack].B * (rList.Length - rChar)) / rList.Length;
- int iScore = (cValue.R - R) * (cValue.R - R) + (cValue.G - G) * (cValue.G - G) + (cValue.B - B) * (cValue.B - B);
- if (!(rChar > 1 && rChar < 4 && iScore > 50000)) // rule out too weird combinations
- {
- if (iScore < bestHit[3])
- {
- bestHit[3] = iScore; //Score
- bestHit[0] = cFore; //ForeColor
- bestHit[1] = cBack; //BackColor
- bestHit[2] = rChar; //Symbol
- }
- }
- }
- }
- }
- Console.ForegroundColor = (ConsoleColor)bestHit[0];
- Console.BackgroundColor = (ConsoleColor)bestHit[1];
- Console.Write(rList[bestHit[2] - 1]);
- }
- public static void ConsoleWriteImage(System.Drawing.Bitmap source)
- {
- if (LOG_ONLY_MODE)
- {
- return;
- }
- int sMax = 39;
- decimal percent = Math.Min(decimal.Divide(sMax, source.Width), decimal.Divide(sMax, source.Height));
- System.Drawing.Size dSize = new System.Drawing.Size((int)(source.Width * percent), (int)(source.Height * percent));
- System.Drawing.Bitmap bmpMax = new System.Drawing.Bitmap(source, dSize.Width * 2, dSize.Height);
- for (int i = 0; i < dSize.Height; i++)
- {
- for (int j = 0; j < dSize.Width; j++)
- {
- ConsoleWritePixel(bmpMax.GetPixel(j * 2, i));
- ConsoleWritePixel(bmpMax.GetPixel(j * 2 + 1, i));
- }
- System.Console.WriteLine();
- }
- Console.ResetColor();
- }
- #endregion
- #endregion
- #region Async tasks
- public async Task LoadModules()
- {
- cmdsvr = new CommandService();
- serviceCollection = serviceCollection.AddSingleton(_client);
- serviceCollection = serviceCollection.AddSingleton(cmdsvr);
- foreach (string item in Directory.EnumerateFiles("CMDModules","*.dll",SearchOption.TopDirectoryOnly))
- {
- LogToConsole(new LogMessage(LogSeverity.Info,"Modules", $"Adding commands from module library: {item}"));
- try
- {
- Assembly asmb = Assembly.LoadFile(Path.GetFullPath(item));
- string serviceFilename = $"CMDModules\\services.{Path.GetFileNameWithoutExtension(item)}.ini";
- string servicefilePath = Path.GetFullPath(serviceFilename);
- if(File.Exists(servicefilePath))
- {
- INIFile serviceFile = new INIFile(servicefilePath);
- foreach (INIEntry entryitem in serviceFile.GetCategoryByName("Services").Entries)
- {
- string typename = entryitem.GetAsString();
- LogToConsole(new LogMessage(LogSeverity.Info,"Modules", $"Injecting service: {typename} from {asmb.GetName().Name}"));
- serviceCollection = serviceCollection.AddSingleton(asmb.GetType(typename));
- }
- }
- await cmdsvr.AddModulesAsync(asmb);//ADD EXTERNAL.
- }
- catch (Exception ex)
- {
- Program.LogToConsole(new LogMessage(LogSeverity.Error, "CritERR",ex.Message,ex));
- using (FileStream fs = new FileStream("ERRORS.LOG", FileMode.Append))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- sw.WriteLine(DateTime.Today.ToString("MM/dd/yyyy") + " " + ex.ToString());
- sw.Flush();
- }
- }
- }
- }
- services = serviceCollection.BuildServiceProvider();
- //check cfg for disabled core.
- if(MainCFG.GetCategoryByName("Application").CheckForEntry("disableCore"))
- {
- if(MainCFG.GetCategoryByName("Application").GetEntryByName("disableCore").GetAsBool())
- {
- LogToConsole(new LogMessage(LogSeverity.Warning,"Program", "RMSoftware.ModularBOT CORE was disabled in the configuration."));
- LogToConsole(new LogMessage(LogSeverity.Warning,"Program", "You will not be able to manage existing commands, nor add new ones, via discord."));
- return;//DO NOT LOAD CORE IF THIS IS TRUE.
- }
- }
- await cmdsvr.AddModulesAsync(Assembly.GetEntryAssembly());//ADD CORE.
- }
- public async Task MainAsync(string token)
- {
- try
- {
- ConsoleGUIReset(ConsoleColor.White, ConsoleColor.DarkBlue, "Application Running");
- _client = new DiscordSocketClient();
- _client.Log += Log;
- serviceCollection = new ServiceCollection();
- _client.Ready += _ClientReady;
- _client.Connected += _client_Connected;
- _client.MessageReceived += _client_MessageReceived;
- _client.Disconnected += _client_Disconnected;
- await LoadModules();//ADD CORE AND EXTERNAL MODULES
- await _client.LoginAsync(TokenType.Bot, token);
- await _client.StartAsync();
- }
- catch (Exception ex)
- {
- CriticalError = true;
- RestartRequested = true;
- crashException = ex;
- using (FileStream fs = File.Create("CRASH.LOG"))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- LogMessage m = new LogMessage(LogSeverity.Critical, "Exception", crashException.Message, crashException);
- sw.WriteLine(m.ToString());
- List<string> restart_args = new List<string>();
- restart_args.AddRange(ARGS);
- if (!restart_args.Contains("-crashed"))
- {
- restart_args.Add("-crashed");
- }
- ARGS = restart_args.ToArray();
- sw.Flush();
- }
- }
- using (FileStream fs = new FileStream("ERRORS.LOG", FileMode.Append))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- sw.WriteLine(DateTime.Today.ToString("MM/dd/yyyy") + " " + ex.ToString());
- sw.Flush();
- }
- }
- }
- }
- private Task _client_Connected()
- {
- StartTime = DateTime.Now;
- LogToConsole(new LogMessage(LogSeverity.Info,"Uptime", "Reset uptime to ALL zero."));
- Console.Title = "RMSoftware.ModularBOT -> " + _client.CurrentUser.Username + " | Connected to " + _client.Guilds.Count + " guilds.";
- return Task.Delay(1);
- }
- private Task _client_Disconnected(Exception arg)
- {
- LogToConsole(new LogMessage(LogSeverity.Warning,"Session", "Disconnected: "+ arg.Message,arg));
- Console.Title = "RMSoftware.ModularBot - Disconnected";
- LogToConsole(new LogMessage(LogSeverity.Info,"Uptime", "The client is disconnected."));
- return Task.Delay(3);
- }
- private async Task _ClientReady()
- {
- await Log(new LogMessage(LogSeverity.Info, "TaskMgr", "Running Onstart.bcmd - task"));
- await Task.Run(new Action(OffloadReady));
- Console.Title = "RMSoftware.ModularBOT -> " + _client.CurrentUser.Username + " | Connected to " + _client.Guilds.Count + " guilds.";
- }
- private async void OffloadReady()
- {
- try
- {
- if (!BCMDStarted)
- {
- await _client.SetStatusAsync(UserStatus.DoNotDisturb);
- //PROCESS THE AutoEXEC file
- ulong id = MainCFG.GetCategoryByName("Application").GetEntryByName("botChannel").GetAsUlong();
- using (StreamReader fs = File.OpenText("OnStart.bcmd"))
- {
- while (!fs.EndOfStream)
- {
- string line = await fs.ReadLineAsync();
- if (!string.IsNullOrWhiteSpace(line))
- {
- if (!line.StartsWith(@"\\"))
- {
- IGuildChannel ch = _client.GetChannel(id) as IGuildChannel;
- //line = line.Replace("%p_", CommandPrefix.ToString());
- if (CRASH)
- {
- ConsoleColor last = Console.BackgroundColor;
- Console.BackgroundColor = ConsoleColor.DarkRed;
- LogToConsole(new LogMessage(LogSeverity.Warning,"Program", "The program was auto-restarted due to a crash. Please see CRASH.LOG for details on what happened."));
- Console.BackgroundColor = last;
- await ((IMessageChannel)ch).SendMessageAsync("**WARNING:** `The bot was auto-restarted due to a crash. Please see CRASH.LOG for details on what happened.`");
- CRASH = false;//don't make it happen more than once pls.
- }
- if (!line.StartsWith("%p_"))
- {
- await ((IMessageChannel)ch).SendMessageAsync(line);
- }
- else
- {
- line = line.Replace("%p_", CommandPrefix.ToString());
- if (await ccmg.Process(new PsuedoMessage(line, _client.CurrentUser, ch, MessageSource.User)))
- {
- LogToConsole(new LogMessage(LogSeverity.Info,"OnStart", line));
- LogToConsole(new LogMessage(LogSeverity.Info, "OnStart", "CustomCMD Success..."));
- continue;
- }
- //Damn, I can't be sassy here... If it was a command, but not a ccmg command, then try the context for modules. If THAT didn't work
- //Then it will output the result of the context.
- var context = new CommandContext(_client, new PsuedoMessage(line,_client.CurrentUser,ch,MessageSource.User));
- // Execute the command. (result does not indicate a return value,
- // rather an object stating if the command executed successfully)
- var result = await cmdsvr.ExecuteAsync(context, 1, services);
- LogToConsole(new LogMessage(LogSeverity.Info,"OnStart", line));
- LogToConsole(new LogMessage(LogSeverity.Info,"OnStart", result.ToString()));
- }
- await Task.Delay(250);
- }
- }
- }
- }
- BCMDStarted = true;
- await _client.SetGameAsync("READY!");
- LogToConsole(new LogMessage(LogSeverity.Info,"TaskMgr", "Task is complete."));
- await _client.SetStatusAsync(UserStatus.Online);
- LogToConsole(new LogMessage(LogSeverity.Info,"TaskMgr", "Running Message Queue - task"));
- foreach (var item in messageQueue)
- {
- await _client_MessageReceived(item);
- await Task.Delay(500);
- }
- LogToConsole(new LogMessage(LogSeverity.Info,"TaskMgr", "Task is complete"));
- }
- }
- catch (Exception ex)
- {
- BCMDStarted = false;
- LogToConsole(new LogMessage(LogSeverity.Error,"CritERR", ex.Message,ex));
- }
- }
- private async Task _client_MessageReceived(SocketMessage arg)
- {
- if(MessagesDisabled)
- {
- return;
- }
- if(rolemgt.UserBlacklisted(arg.Author))
- {
- return;
- }
- #region Console Output debug
- //DEBUG: Output the bot-mentioned chat message to the console
- foreach (SocketUser item in arg.MentionedUsers)
- {
- if (item.Mention == _client.CurrentUser.Mention)
- {
- LogToConsole(new LogMessage(LogSeverity.Info,"Mention", "<[" + arg.Channel.Name + "] " + arg.Author.Username + " >: " + arg.Content));
- }
- }
- //DEBUG: output ! prefixed messages to console.
- if (arg.Content.StartsWith(CommandPrefix.ToString()))
- {
- LogToConsole(new LogMessage(LogSeverity.Info,"Command", "<[" + arg.Channel.Name + "] " + arg.Author.Username + " >: " + arg.Content));
- }
- #endregion
- // Don't process the command if it was a System Message
- var message = arg as SocketUserMessage;
- if (message == null) return;
- // Create a number to track where the prefix ends and the command begins
- int argPos = 0;
- // Determine if the message is a command, based on if it starts with 'commandprefix' or a mention prefix. if not, ignore it.
- if (!(message.HasCharPrefix(CommandPrefix, ref argPos) || message.HasMentionPrefix(_client.CurrentUser, ref argPos))) return;
- if (!arg.Author.IsBot && !BCMDStarted)
- {
- messageQueue.Add(arg); //queue it up. The bcmdStarted check should
- //provide PLENTY (if not an excessive amount) of time for modules,and extra commands
- //to be fully loaded by the time it is set to true. Preemptively solving the "hey, you just ignored my commands completely"
- //when the bot starts and doesn't respond to a command at first
- return;
- }
- // Create a Command Context for command modules
- //Process CoreCustom commands
- if (await ccmg.Process(arg))
- {
- return;//If the message contained a custom command from config, No need to continue.
- };
- var context = new CommandContext(_client, message);
- // Execute the command. (result does not indicate a return value,
- // rather an object stating if the command executed successfully)
- var result = await cmdsvr.ExecuteAsync(context, argPos, services);
- //If the result is unsuccessful AND not unknown command, send the error details.
- if (result.Error.HasValue)
- {
- if (!result.Error.Value.HasFlag(CommandError.UnknownCommand) && !result.IsSuccess)
- {
- await arg.Channel.SendMessageAsync(result.ErrorReason);
- }
- if (result.Error.Value.HasFlag(CommandError.BadArgCount))
- {
- await arg.Channel.SendMessageAsync(result.ErrorReason);
- }
- }
- }
- private Task Log(LogMessage msg)
- {
- if(!LOG_ONLY_MODE)
- {
- LogToConsole(msg);
- }
- else
- {
- Console.WriteLine(JsonConvert.SerializeObject(msg));
- }
- if (msg.Message == "Failed to resume previous session")
- {
- _client.StopAsync();
- _client = null;
- crashException = new Exception("Failed to resume previous session. See ERRORS.LOG for any additional information.");
- CriticalError = true;
- discon = true;
- Thread.Sleep(3000);
- }
- if(msg.Exception != null)
- {
- using (FileStream fs = new FileStream("ERRORS.LOG",FileMode.Append))
- {
- using (StreamWriter sw = new StreamWriter(fs))
- {
- sw.WriteLine(DateTime.Today.ToString("MM/dd/yyyy")+" "+msg.ToString());
- sw.Flush();
- }
- }
- }
- return Task.Delay(0);
- }
- #endregion
- }
- #region Retry clause - API error workaround [possibly obsolete] [Stackoverflow.com]
- public static class Retry
- {
- public static void Do(
- Action action,
- TimeSpan retryInterval,
- int maxAttemptCount = 3)
- {
- Do<object>(() =>
- {
- action();
- return null;
- }, retryInterval, maxAttemptCount);
- }
- public static T Do<T>(
- Func<T> action,
- TimeSpan retryInterval,
- int maxAttemptCount = 3)
- {
- var exceptions = new List<Exception>();
- for (int attempted = 0; attempted < maxAttemptCount; attempted++)
- {
- try
- {
- if (attempted > 0)
- {
- Thread.Sleep(retryInterval);
- }
- return action();
- }
- catch (Exception ex)
- {
- exceptions.Add(ex);
- Program.LogToConsole(new LogMessage(LogSeverity.Warning,"API_RETRY", ex.Message,ex));
- Program.LogToConsole(new LogMessage(LogSeverity.Warning,"API_RETRY", "Retrying " + (maxAttemptCount-attempted) + " more time(s)"));
- }
- }
- throw new AggregateException(exceptions);
- }
- }
- #endregion
- #region Advanced Command Processing
- public class CmdRoleManager
- {
- INIFile mgmt;
- INIFile userBlackList;
- public CmdRoleManager()
- {
- mgmt = new INIFile("cmdMgr.ini");
- userBlackList = new INIFile("blacklist.ini");
- if(!userBlackList.CheckForCategory("Blacklist"))
- {
- userBlackList.CreateCategory("Blacklist");
- userBlackList.SaveConfiguration();
- }
- }
- public bool AddUserToBlacklist(SocketUser user)
- {
- string guildCat = "Blacklist";
- bool check = userBlackList.GetCategoryByName(guildCat).CheckForEntry(user.Id.ToString());
- if(!check)
- {
- userBlackList.CreateEntry(guildCat, user.Id.ToString(), user.Username.Replace("=", "_"));
- }
- userBlackList.SaveConfiguration();
- return !check;
- }
- public bool DeleteUserFromBlacklist(SocketUser user)
- {
- string guildCat = "Blacklist";
- bool check = userBlackList.GetCategoryByName(guildCat).CheckForEntry(user.Id.ToString());
- if (check)
- {
- userBlackList.DeleteEntry(guildCat, user.Id.ToString());
- }
- userBlackList.SaveConfiguration();
- return check;
- }
- public void AddCommandManagerRole(SocketRole role)
- {
- string guildCat = role.Guild.Id.ToString();
- bool check = mgmt.CheckForCategory(guildCat);
- int indx = -1;
- if(check)
- {
- indx = mgmt.GetCategoryByName(guildCat).Entries.Count-1;
- mgmt.CreateEntry(guildCat, "role" + (indx + 1), role.Id);
- }
- else
- {
- mgmt.CreateCategory(guildCat);
- indx = mgmt.GetCategoryByName(guildCat).Entries.Count - 1;
- mgmt.CreateEntry(guildCat, "role" + (indx + 1), role.Id);
- }
- mgmt.SaveConfiguration();
- }
- public bool UserBlacklisted(SocketUser user)
- {
- return userBlackList.GetCategoryByName("Blacklist").CheckForEntry(user.Id.ToString());
- }
- public string DeleteCommandManager(SocketRole role)
- {
- string guildCat = role.Guild.Id.ToString();
- bool check = mgmt.CheckForCategory(guildCat);
- int indx = -1;
- if (check)
- {
- indx = mgmt.GetCategoryByName(guildCat).Entries.Count - 1;
- try
- {
- mgmt.DeleteEntry(guildCat, mgmt.GetCategoryByName(guildCat).Entries.Find(x => x.GetAsUlong() == role.Id).Name);
- //Then get all entries and rename them.
- for (int i = 0; i < mgmt.GetCategoryByName(guildCat).Entries.Count; i++)
- {
- mgmt.GetCategoryByName(guildCat).Entries[i].Name = $"role{i}";
- }
- }
- catch (Exception ex)
- {
- return ex.Message;
- }
- }
- else
- {
- return "No results. The guild ID didn't exist in the database.";
- }
- mgmt.SaveConfiguration();
- return "Command Manager database updated.";
- }
- public bool CheckUserRole(SocketGuildUser user)
- {
- string guildcat = user.Guild.Id.ToString();//if the category does not exist, return false... can't have that;
- if(!mgmt.CheckForCategory(guildcat))
- {
- return false;
- }
- foreach (var role in user.Roles)
- {
- ulong id = role.Id;
- if (mgmt.GetCategoryByName(guildcat).Entries.Exists(x => x.GetAsUlong() == id))
- {
- return true;//keep doing it until it returns true.
- }
- }
- return false;//default;
- }
- public SocketRole[] GetRolesForGuild(SocketGuild guild)
- {
- List<SocketRole> items = new List<SocketRole>();
- string guildcat = guild.Id.ToString();
- if (!mgmt.CheckForCategory(guildcat))
- {
- return null;
- }
- foreach (var item in mgmt.GetCategoryByName(guildcat).Entries)
- {
- items.Add(guild.GetRole(item.GetAsUlong()));
- }
- return items.ToArray();
- }
- public SocketRole[] GetAllRoles()
- {
- List<SocketRole> items = new List<SocketRole>();
- foreach (var itemc in mgmt.Categories)
- {
- foreach (var item in itemc.Entries)
- {
- items.Add(Program._client.GetGuild(Convert.ToUInt64(itemc.Name)).GetRole(item.GetAsUlong()));
- }
- }
- return items.ToArray();
- }
- }
- public class PsuedoMessage : IMessage, IUserMessage
- {
- string _content = "";
- SocketUser _author;
- IGuildChannel _c;
- MessageSource _source;
- MessageType _type;
- public PsuedoMessage(string content,SocketUser author,IGuildChannel ch ,MessageSource source)
- {
- _content = content;
- _author = author;
- _c = ch;
- _source = source;
- _type = MessageType.Default;
- }
- IReadOnlyCollection<IAttachment> IMessage.Attachments
- {
- get;
- }
- IUser IMessage.Author
- {
- get { return _author; }
- }
- IMessageChannel IMessage.Channel
- {
- get { return _c as IMessageChannel; }
- }
- string IMessage.Content
- {
- get { return _content; }
- }
- DateTimeOffset ISnowflakeEntity.CreatedAt
- {
- get;
- }
- DateTimeOffset? IMessage.EditedTimestamp
- {
- get;
- }
- IReadOnlyCollection<IEmbed> IMessage.Embeds
- {
- get;
- }
- ulong IEntity<ulong>.Id
- {
- get { return (ulong)new Random().Next(0,int.MaxValue); }
- }
- bool IMessage.IsPinned
- {
- get { return false; }
- }
- bool IMessage.IsTTS
- {
- get { return false; }
- }
- IReadOnlyCollection<ulong> IMessage.MentionedChannelIds
- {
- get;
- }
- IReadOnlyCollection<ulong> IMessage.MentionedRoleIds
- {
- get;
- }
- IReadOnlyCollection<ulong> IMessage.MentionedUserIds
- {
- get;
- }
- MessageSource IMessage.Source
- {
- get { return _source; }
- }
- IReadOnlyCollection<ITag> IMessage.Tags
- {
- get;
- }
- DateTimeOffset IMessage.Timestamp
- {
- get;
- }
- MessageType IMessage.Type
- {
- get { return _type; }
- }
- public IReadOnlyDictionary<IEmote, ReactionMetadata> Reactions
- {
- get
- {
- throw new NotImplementedException();
- }
- }
- Task IDeletable.DeleteAsync(RequestOptions options)
- {
- return Task.Delay(0);
- }
- public Task ModifyAsync(Action<MessageProperties> func, RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
- public Task PinAsync(RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
- public Task UnpinAsync(RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
- public Task AddReactionAsync(IEmote emote, RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
- public Task RemoveReactionAsync(IEmote emote, IUser user, RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
- public Task RemoveAllReactionsAsync(RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
- public Task<IReadOnlyCollection<IUser>> GetReactionUsersAsync(string emoji, int limit = 100, ulong? afterUserId = default(ulong?), RequestOptions options = null)
- {
- throw new NotImplementedException();
- }
- public string Resolve(TagHandling userHandling = TagHandling.Name, TagHandling channelHandling = TagHandling.Name, TagHandling roleHandling = TagHandling.Name, TagHandling everyoneHandling = TagHandling.Ignore, TagHandling emojiHandling = TagHandling.Name)
- {
- throw new NotImplementedException();
- }
- }
- #endregion
- }
Advertisement
Add Comment
Please, Sign In to add comment