/// <summary> /// Gets a string from the primary or backup language file /// </summary> /// <param name="path">The path to the node</param> /// <returns></returns> public string GetString(string path) { if (primary == null && backup == null) { throw new ArgumentNullException(); } try { return(plugin.language.primary.SelectToken(path).Value <string>()); } // This exception means the node does not exist in the language file, the plugin attempts to find it in the backup file catch (Exception primaryException) { if (primaryException is NullReferenceException || primaryException is ArgumentNullException || primaryException is InvalidCastException || primaryException is JsonException) { plugin.Warn("Error reading dictionary '" + path + "' from primary language file, switching to backup..."); try { return(plugin.language.backup.SelectToken(path).Value <string>()); } // The node also does not exist in the backup file catch (NullReferenceException e) { plugin.Error("Error: Language config node '" + path + "' does not exist. Message can not be sent." + e); throw; } catch (ArgumentNullException e) { plugin.Error("Error: Language config node '" + path + "' does not exist. Message can not be sent." + e); throw; } catch (InvalidCastException e) { plugin.Error(e.ToString()); throw; } catch (JsonException e) { plugin.Error(e.ToString()); throw; } } else { plugin.Error(primaryException.ToString()); throw; } } }
//This is a loop that keeps running and checks if the bot has been disconnected public StartConnectionWatchdog(SCPDiscordPlugin plugin) { while (true) { Thread.Sleep(2000); if (!plugin.clientSocket.Connected && plugin.hasConnectedOnce) { plugin.clientSocket.Close(); plugin.Info("Not connected, trying to reconnect"); if (plugin.GetConfigBool("discord_verbose")) { plugin.Warn("Discord bot connection issue detected, attempting reconnect..."); } try { plugin.clientSocket = new TcpClient(plugin.GetConfigString("discord_bot_ip"), plugin.GetConfigInt("discord_bot_port")); plugin.Info("Reconnected to Discord bot."); plugin.SendMessageToBot("default", "botmessages.reconnectedtobot"); } catch (SocketException e) { if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Error occured while reconnecting to discord bot server."); plugin.Debug(e.ToString()); } Thread.Sleep(5000); } catch (ObjectDisposedException e) { if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("TCP client was unexpectedly closed."); plugin.Debug(e.ToString()); } Thread.Sleep(5000); } catch (ArgumentOutOfRangeException e) { if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Invalid port."); plugin.Debug(e.ToString()); } Thread.Sleep(5000); } catch (ArgumentNullException e) { if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("IP address is null."); plugin.Debug(e.ToString()); } Thread.Sleep(5000); } } } }
public AsyncMessage(SCPDiscordPlugin plugin, string channelID, string message) { if (message != null && message != "") { if (channelID == "default") { channelID = "000000000000000000"; } // Reconnect feature try { NetworkStream serverStream = plugin.clientSocket.GetStream(); byte[] outStream = System.Text.Encoding.ASCII.GetBytes(channelID + message + '\0'); serverStream.Write(outStream, 0, outStream.Length); plugin.Info("Sent message '" + message + "' to discord."); } catch (SocketException e) { plugin.Info("Error occured while connecting to discord bot server.\n" + e.Message); plugin.Info("Restarting plugin..."); plugin.clientSocket.Close(); plugin.OnEnable(); } catch (ObjectDisposedException e) { plugin.Info("TCP client was unexpectedly closed.\n" + e.Message); plugin.Info("Restarting plugin..."); plugin.clientSocket.Close(); plugin.OnEnable(); } } else { plugin.Warn("Tried to send empty message to discord."); } }
public RefreshBotActivity(SCPDiscordPlugin plugin) { var message = (plugin.pluginManager.Server.NumPlayers - 1) + " / " + plugin.GetConfigString("max_players"); if (plugin.clientSocket == null || !plugin.clientSocket.Connected) { if (plugin.hasConnectedOnce && plugin.GetConfigBool("discord_verbose")) { plugin.Warn("Error sending message '" + message + "' to bot: Not connected."); } return; } // Try to send the message to the bot try { NetworkStream serverStream = plugin.clientSocket.GetStream(); byte[] outStream = System.Text.Encoding.UTF8.GetBytes("botactivity" + message + '\0'); serverStream.Write(outStream, 0, outStream.Length); if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Sent activity '" + message + "' to bot."); } } catch (InvalidOperationException e) { plugin.Error("Error sending activity '" + message + "' to bot."); plugin.Debug(e.ToString()); } catch (ArgumentNullException e) { plugin.Error("Error sending activity '" + message + "' to bot."); plugin.Debug(e.ToString()); } }
/// <summary> /// Saves all default language files included in the .dll /// </summary> public static void SaveDefaultLanguages() { foreach (KeyValuePair <string, string> language in defaultLanguages) { if (!File.Exists(languagesPath + language.Key + ".yml")) { plugin.Info("Creating language file " + language.Key + ".yml..."); try { File.WriteAllText((languagesPath + language.Key + ".yml"), language.Value); } catch (DirectoryNotFoundException) { plugin.Warn("Could not create language file: Language directory does not exist, attempting to create it... "); Directory.CreateDirectory(languagesPath); plugin.Info("Creating language file " + language.Key + ".yml..."); File.WriteAllText((languagesPath + language.Key + ".yml"), language.Value); } } } }
public RefreshChannelTopic(SCPDiscordPlugin plugin, string channelID) { Dictionary <string, string> variables = new Dictionary <string, string>(); try { Server server = plugin.pluginManager.Server; Dictionary <string, string> serverVariables; if (server != null) { serverVariables = new Dictionary <string, string> { { "players", (server.NumPlayers - 1) + "" }, { "maxplayers", plugin.GetConfigString("max_players") }, { "ip", server.IpAddress }, { "port", server.Port + "" }, { "isvisible", server.Visible + "" }, { "isverified", server.Verified + "" }, { "uptime", (plugin.serverStartTime.ElapsedMilliseconds / 1000 / 60) + "" } }; } else { serverVariables = new Dictionary <string, string> { { "players", "0" }, { "maxplayers", "0" }, { "ip", "---.---.---.---" }, { "port", "----" }, { "isvisible", "False" }, { "isverified", "False" }, { "uptime", "0" } }; } Dictionary <string, string> mapVariables; if (server != null && server.Map != null) { mapVariables = new Dictionary <string, string> { { "warheaddetonated", server.Map.WarheadDetonated + "" }, { "decontaminated", server.Map.LCZDecontaminated + "" } }; } else { mapVariables = new Dictionary <string, string> { { "warheaddetonated", "False" }, { "decontaminated", "False" } }; } Dictionary <string, string> roundVariables; if (server != null && server.Round != null) { roundVariables = new Dictionary <string, string> { { "roundduration", (server.Round.Duration / 60) + "" }, { "dclassalive", server.Round.Stats.ClassDAlive + "" }, { "dclassdead", server.Round.Stats.ClassDDead + "" }, { "dclassescaped", server.Round.Stats.ClassDEscaped + "" }, { "dclassstart", server.Round.Stats.ClassDStart + "" }, { "mtfalive", server.Round.Stats.NTFAlive + "" }, { "scientistsalive", server.Round.Stats.ScientistsAlive + "" }, { "scientistsdead", server.Round.Stats.ScientistsDead + "" }, { "scientistsescaped", server.Round.Stats.ScientistsEscaped + "" }, { "scientistsstart", server.Round.Stats.ScientistsStart + "" }, { "scpalive", server.Round.Stats.SCPAlive + "" }, { "scpdead", server.Round.Stats.SCPDead + "" }, { "scpkills", server.Round.Stats.SCPKills + "" }, { "scpstart", server.Round.Stats.SCPStart + "" }, //{ "warheaddetonated", server.Round.Stats.WarheadDetonated + "" }, { "zombies", server.Round.Stats.Zombies + "" } }; } else { roundVariables = new Dictionary <string, string> { { "roundduration", "0" }, { "dclassalive", "0" }, { "dclassdead", "0" }, { "dclassescaped", "0" }, { "dclassstart", "0" }, { "mtfalive", "0" }, { "scientistsalive", "0" }, { "scientistsdead", "0" }, { "scientistsescaped", "0" }, { "scientistsstart", "0" }, { "scpalive", "0" }, { "scpdead", "0" }, { "scpkills", "0" }, { "scpstart", "0" }, //{ "warheaddetonated", "0" }, { "zombies", "0" } }; } foreach (var entry in serverVariables) { variables.Add(entry.Key, entry.Value); } foreach (var entry in mapVariables) { variables.Add(entry.Key, entry.Value); } foreach (var entry in roundVariables) { variables.Add(entry.Key, entry.Value); } var topic = plugin.GetConfigString("discord_server_status"); topic = topic.Replace("\n", ""); // Variable insertion foreach (KeyValuePair <string, string> variable in variables) { topic = topic.Replace("<var:" + variable.Key + ">", variable.Value); } // Regex replacements Dictionary <string, string> regex = plugin.GetConfigDict("discord_server_status_regex"); // Run the regex replacements foreach (KeyValuePair <string, string> entry in regex) { topic = topic.Replace(entry.Key, entry.Value); } // Change the default keyword to the bot's representation of it if (channelID == "default") { channelID = "000000000000000000"; } // Try to send the message to the bot try { NetworkStream serverStream = plugin.clientSocket.GetStream(); byte[] outStream = System.Text.Encoding.UTF8.GetBytes("channeltopic" + channelID + topic + '\0'); serverStream.Write(outStream, 0, outStream.Length); if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Sent channel topic '" + topic + "' to bot."); } } catch (InvalidOperationException e) { plugin.Error("Error sending channel topic '" + topic + "' to bot."); plugin.Debug(e.ToString()); } catch (ArgumentNullException e) { plugin.Error("Error sending channel topic '" + topic + "' to bot."); plugin.Debug(e.ToString()); } } catch (Exception e) { if (plugin.GetConfigBool("discord_verbose")) { plugin.Warn(e.ToString()); } } }
public SendMessageToBot(SCPDiscordPlugin plugin, string channelID, string messagePath, Dictionary <string, string> variables = null) { // Get unparsed message from config string message = ""; try { message = plugin.language.GetString(messagePath + ".message"); } catch (Exception e) { if (!(e is NullReferenceException)) { plugin.Error("Error reading base message" + e); } return; } // Abort on empty message if (message == null || message == "" || message == " " || message == ".") { plugin.Error("Tried to send empty message " + messagePath + " to discord. Verify your language file."); return; } // Abort if client is dead if (plugin.clientSocket == null || !plugin.clientSocket.Connected) { if (plugin.hasConnectedOnce && plugin.GetConfigBool("discord_verbose")) { plugin.Warn("Error sending message '" + message + "' to bot: Not connected."); } return; } // Add time stamp if (plugin.GetConfigString("discord_formatting_date") != "off") { message = "[" + DateTime.Now.ToString(plugin.GetConfigString("discord_formatting_date")) + "]: " + message; } // Change the default keyword to the bot's representation of it if (channelID == "default") { channelID = "000000000000000000"; } // Re-add newlines message = message.Replace("\\n", "\n"); // Add variables ////////////////////////////// if (variables != null) { // Variable insertion foreach (KeyValuePair <string, string> variable in variables) { // Wait until after the regex replacements to add the player names if (variable.Key == "servername" || variable.Key == "name" || variable.Key == "attackername" || variable.Key == "playername" || variable.Key == "adminname" || variable.Key == "feedback") { continue; } message = message.Replace("<var:" + variable.Key + ">", variable.Value); } } /////////////////////////////////////////////// // Global regex replacements ////////////////// Dictionary <string, string> globalRegex = new Dictionary <string, string>(); try { globalRegex = plugin.language.GetRegexDictionary("global_regex"); } catch (Exception e) { plugin.Error("Error reading global regex" + e); return; } // Run the global regex replacements foreach (KeyValuePair <string, string> entry in globalRegex) { message = message.Replace(entry.Key, entry.Value); } /////////////////////////////////////////////// // Local regex replacements /////////////////// Dictionary <string, string> localRegex = new Dictionary <string, string>(); try { localRegex = plugin.language.GetRegexDictionary(messagePath + ".regex"); } catch (Exception e) { plugin.Error("Error reading local regex" + e); return; } // Run the local regex replacements foreach (KeyValuePair <string, string> entry in localRegex) { message = message.Replace(entry.Key, entry.Value); } /////////////////////////////////////////////// if (variables != null) { // Add names/command feedback to the message // foreach (KeyValuePair <string, string> variable in variables) { if (variable.Key == "servername" || variable.Key == "name" || variable.Key == "attackername" || variable.Key == "playername" || variable.Key == "adminname" || variable.Key == "feedback") { message = message.Replace("<var:" + variable.Key + ">", EscapeDiscordFormatting(variable.Value)); } } /////////////////////////////////////////////// // Final regex replacements /////////////////// Dictionary <string, string> finalRegex = new Dictionary <string, string>(); try { finalRegex = plugin.language.GetRegexDictionary("final_regex"); } catch (Exception e) { plugin.Error("Error reading final regex" + e); return; } // Run the final regex replacements foreach (KeyValuePair <string, string> entry in finalRegex) { message = message.Replace(entry.Key, entry.Value); } /////////////////////////////////////////////// } // Try to send the message to the bot try { NetworkStream serverStream = plugin.clientSocket.GetStream(); byte[] outStream = System.Text.Encoding.UTF8.GetBytes(channelID + message + '\0'); serverStream.Write(outStream, 0, outStream.Length); if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Sent message '" + message + "' to bot."); } } catch (InvalidOperationException e) { plugin.Error("Error sending message '" + message + "' to bot."); plugin.Debug(e.ToString()); } catch (ArgumentNullException e) { plugin.Error("Error sending message '" + message + "' to bot."); plugin.Debug(e.ToString()); } }
public BotListener(SCPDiscordPlugin plugin) { this.plugin = plugin; while (true) { //Listen for connections if (plugin.clientSocket.Connected && plugin.hasConnectedOnce) { Thread.Sleep(200); try { //Discord messages can be up to 2000 chars long, UTF8 chars can be up to 4 bytes long. byte[] data = new byte[8000]; NetworkStream stream = null; try { stream = plugin.clientSocket.GetStream(); } catch (Exception ex) { if (ex is IOException) { plugin.Error("Could not get stream from socket."); } else { plugin.Error("BotListener Error: " + ex.ToString()); } } if (stream == null) { return; } string incomingData = ""; try { int lengthOfData = stream.Read(data, 0, data.Length); incomingData = Encoding.UTF8.GetString(data, 0, lengthOfData); } catch (Exception ex) { if (ex is IOException) { plugin.Error("Could not read from socket."); } else { plugin.Error("BotListener Error: " + ex.ToString()); } } List <string> messages = new List <string>(incomingData.Split('\n')); //If several messages come in at the same time, process all of them while (messages.Count > 0) { if (messages[0].Length == 0) { messages.RemoveAt(0); continue; } string[] words = messages[0].Split(' '); bool isCommand = words[0] == "command"; string command = words[1]; string[] arguments = new string[0]; if (words.Length >= 3) { arguments = words.Skip(2).ToArray(); } //A verification that message is a command and not some left over string in the socket if (isCommand) { if (command == "ban") { //Check if the command has enough arguments if (arguments.Length >= 2) { BanCommand(arguments[0], arguments[1], MergeReason(arguments.Skip(2).ToArray())); } else { Dictionary <string, string> variables = new Dictionary <string, string> { { "command", messages[0] } }; plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.missingarguments", variables); } } else if (command == "kick") { //Check if the command has enough arguments if (arguments.Length >= 1) { KickCommand(arguments[0], MergeReason(arguments.Skip(1).ToArray())); } else { Dictionary <string, string> variables = new Dictionary <string, string> { { "command", messages[0] } }; plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.missingarguments", variables); } } else if (command == "kickall") { KickallCommand(MergeReason(arguments)); } else if (command == "unban") { //Check if the command has enough arguments if (arguments.Length >= 1) { UnbanCommand(arguments[0]); } else { Dictionary <string, string> variables = new Dictionary <string, string> { { "command", messages[0] } }; plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.missingarguments", variables); } } else if (command == "list") { var message = "```md\n# Players online:\n"; foreach (Player player in plugin.Server.GetPlayers()) { string line = player.Name.PadRight(32); line += player.SteamId; line += "\n"; } message += "```"; if (plugin.clientSocket == null || !plugin.clientSocket.Connected) { if (plugin.hasConnectedOnce && Config.settings.verbose) { plugin.Warn("Error sending message '" + message + "' to bot: Not connected."); } return; } // Try to send the message to the bot try { NetworkStream serverStream = plugin.clientSocket.GetStream(); byte[] outStream = System.Text.Encoding.UTF8.GetBytes("000000000000000000" + message + '\0'); serverStream.Write(outStream, 0, outStream.Length); if (Config.settings.verbose) { plugin.Info("Sent activity '" + message + "' to bot."); } } catch (InvalidOperationException e) { plugin.Error("Error sending activity '" + message + "' to bot."); plugin.Debug(e.ToString()); } catch (ArgumentNullException e) { plugin.Error("Error sending activity '" + message + "' to bot."); plugin.Debug(e.ToString()); } } else if (command == "exit") { plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.exit"); } else if (command == "help") { plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.help"); } else if (command == "hidetag" || command == "showtag") { if (plugin.pluginManager.GetEnabledPlugin("karlofduty.toggletag") != null) { if (arguments.Length > 0) { command = "console_" + command; string response = ConsoleCommand(plugin.pluginManager.Server, command, arguments); Dictionary <string, string> variables = new Dictionary <string, string> { { "feedback", response } }; plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.consolecommandfeedback", variables); } else { Dictionary <string, string> variables = new Dictionary <string, string> { { "command", command } }; plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.missingarguments", variables); } } else { plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.toggletag.notinstalled"); } } else if (command == "vs_enable" || command == "vs_disable" || command == "vs_whitelist" || command == "vs_reload") { if (plugin.pluginManager.GetEnabledPlugin("karlofduty.vpnshield") != null) { string response = ConsoleCommand(plugin.pluginManager.Server, command, arguments); Dictionary <string, string> variables = new Dictionary <string, string> { { "feedback", response } }; plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.consolecommandfeedback", variables); } else { plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.vpnshield.notinstalled"); } } else { string response = ConsoleCommand(plugin.pluginManager.Server, command, arguments); Dictionary <string, string> variables = new Dictionary <string, string> { { "feedback", response } }; plugin.SendMessageToBot(Config.channels.statusmessages, "botresponses.consolecommandfeedback", variables); } } plugin.Info("From discord: " + messages[0]); messages.RemoveAt(0); } } catch (Exception ex) { if (ex is IOException) { plugin.Error("BotListener Error: " + ex.ToString()); } plugin.Error("BotListener Error: " + ex.ToString()); } } else { Thread.Sleep(2000); } } }