public void OnSCP914Activate(SCP914ActivateEvent ev) { /// <summary> /// This is the event handler for when a SCP914 is activated /// </summary> plugin.SendMessageAsync(plugin.GetConfigString("discord_channel_onscp914activate"), plugin.MultiLanguage(43) + ev.KnobSetting + "."); }
public void OnDecideTeamRespawnQueue(DecideRespawnQueueEvent ev) { /// <summary> /// Called at the start, when the team respawn queue is being read. This happens BEFORE it fills it to full with filler_team_id. /// <summary> plugin.SendMessageAsync(plugin.GetConfigString("discord_channel_ondecideteamrespawnqueue"), plugin.MultiLanguage(5)); }
//This is ran once on the first time connecting to the bot public ConnectToBot(SCPDiscordPlugin plugin) { Thread.Sleep(2000); while (!plugin.clientSocket.Connected) { if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Attempting Bot Connection..."); } try { if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Your Bot IP: " + plugin.GetConfigString("discord_bot_ip") + ". Your Bot Port: " + plugin.GetConfigInt("discord_bot_port") + "."); } plugin.clientSocket.Connect(plugin.GetConfigString("discord_bot_ip"), plugin.GetConfigInt("discord_bot_port")); } catch (SocketException e) { if (plugin.GetConfigBool("discord_verbose")) { plugin.Info("Error occured while connecting 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); } } plugin.Info("Connected to Discord bot."); plugin.SendMessageToBot("default", "botmessages.connectedtobot"); plugin.hasConnectedOnce = true; }
public void OnAdminQuery(AdminQueryEvent ev) { ///Triggered whenever an adming uses an admin command, both gui and commandline RA if (ev.Query == "REQUEST_DATA PLAYER_LIST SILENT") { return; } plugin.SendMessageAsync(plugin.GetConfigString("discord_channel_onadminquery"), plugin.MultiLanguage(48) + ev.Admin.Name + " (" + ev.Admin.SteamId + plugin.MultiLanguage(49) + ev.Query + "'."); }
public void OnRoundStart(RoundStartEvent ev) { /// <summary> /// This is the event handler for Round start events (before people are spawned in) /// </summary> plugin.SendMessageToBot(plugin.GetConfigString("discord_channel_onroundstart"), "round.onroundstart"); roundHasStarted = true; }
public void OnDecideTeamRespawnQueue(DecideRespawnQueueEvent ev) { /// <summary> /// Called at the start, when the team respawn queue is being read. This happens BEFORE it fills it to full with filler_team_id. /// <summary> Dictionary <string, string> variables = new Dictionary <string, string> { { "teams", ev.Teams.ToString() }, }; plugin.SendMessageToBot(plugin.GetConfigString("discord_channel_ondecideteamrespawnqueue"), "team.ondecideteamrespawnqueue", variables); }
public void OnRoundStart(RoundStartEvent ev) { /// <summary> /// This is the event handler for Round start events (before people are spawned in) /// </summary> plugin.SendMessageAsync(plugin.GetConfigString("discord_channel_onroundstart"), plugin.MultiLanguage(11)); }
//Multi-language support. public string MultiLanguage(int line) { string multilanguage_path = "/sm_plugins/SCPDiscord/"; bool fodler_exists = Directory.Exists(multilanguage_path); string[] opened_file = new string[150]; if (!fodler_exists) { this.Info("SCPDiscord can't load. Missing translation fodler in sm_plugins folder."); pluginManager.DisablePlugin(this); } if (line > 0) { line = line - 1; } switch (plugin.GetConfigString("discord_bot_language")) { case "rus": opened_file = File.ReadAllLines(@"/sm_plugins/SCPDiscord/Russian.txt"); break; default: opened_file = File.ReadAllLines(@"/sm_plugins/SCPDiscord/English.txt"); break; } string requested_line = opened_file[line]; return(requested_line); }
//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 void OnAdminQuery(AdminQueryEvent ev) { ///Triggered whenever an adming uses an admin command, both gui and commandline RA if (ev.Query == "REQUEST_DATA PLAYER_LIST SILENT") { return; } Dictionary <string, string> variables = new Dictionary <string, string> { { "ipaddress", ev.Admin.IpAddress }, { "name", ev.Admin.Name }, { "playerid", ev.Admin.PlayerId.ToString() }, { "steamid", ev.Admin.SteamId }, { "class", ev.Admin.TeamRole.Role.ToString() }, { "team", ev.Admin.TeamRole.Team.ToString() }, { "handled", ev.Handled.ToString() }, { "output", ev.Output }, { "query", ev.Query }, { "successful", ev.Successful.ToString() } }; plugin.SendMessageToBot(plugin.GetConfigString("discord_channel_onadminquery"), "admin.onadminquery", variables); }
public void ValidateLanguageStrings() { foreach (string node in messageNodes) { try { plugin.language.primary.SelectToken(node + ".message").Value <string>(); } catch (Exception) { plugin.Warn("Your SCPDiscord language file \"" + plugin.GetConfigString("discord_language") + ".yml\" does not contain the node \"" + node + ".message\".\nEither add it to your language file or turn on the discord_overwrite_language config setting to use the default language."); } } }
public void OnUpdate(UpdateEvent ev) { if (DateTime.Now > nextUpdate && plugin.hasConnectedOnce) { // Update player count if (plugin.GetConfigString("discord_activity_playercount") == "on") { plugin.RefreshBotActivity(); } // Update channel topic plugin.RefreshChannelTopic(); nextUpdate = DateTime.Now.AddSeconds(5); } }
public void OnSCP914Activate(SCP914ActivateEvent ev) { /// <summary> /// This is the event handler for when a SCP914 is activated /// </summary> Dictionary <string, string> variables = new Dictionary <string, string> { { "knobsetting", ev.KnobSetting.ToString() } }; plugin.SendMessageToBot(plugin.GetConfigString("discord_channel_onscp914activate"), "environment.onscp914activate", variables); }
public void OnUpdate(UpdateEvent ev) { if (!stopWatch.IsRunning) { stopWatch.Start(); } ticks++; if (stopWatch.ElapsedMilliseconds >= 10000 && plugin.hasConnectedOnce && plugin.clientSocket.Connected) { stopWatch.Reset(); float tps = ticks / 10.0f; ticks = 0; // Update player count if (plugin.GetConfigString("discord_activity_playercount") == "on") { plugin.RefreshBotActivity(); } // Update channel topic plugin.RefreshChannelTopic(tps); } }
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()); } }
public Language(SCPDiscordPlugin plugin) { this.plugin = plugin; plugin.language = this; Thread.Sleep(2500); // Save default language files SaveDefaultLanguages(); // Read primary language file plugin.Info("Loading primary language file..."); try { ReadLanguage(plugin.GetConfigString("discord_language"), false); } catch (Exception e) { if (e is DirectoryNotFoundException) { plugin.Error("Language directory not found."); } else if (e is UnauthorizedAccessException) { plugin.Error("Primary language file access denied."); } else if (e is FileNotFoundException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' was not found."); } else if (e is JsonReaderException || e is YamlException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' formatting error."); } plugin.Error("Error reading language file '" + plugin.GetConfigString("discord_language") + ".yml'. Attempting to initialize backup system..."); plugin.Debug(e.ToString()); } // Read backup language file if not the same as the primary if (plugin.GetConfigString("discord_language") != "english") { plugin.Info("Loading backup language file..."); try { ReadLanguage("english", true); } catch (Exception e) { if (e is DirectoryNotFoundException) { plugin.Error("Language directory not found."); } else if (e is UnauthorizedAccessException) { plugin.Error("Backup language file access denied."); } else if (e is FileNotFoundException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' was not found."); } else if (e is JsonReaderException || e is YamlException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' formatting error."); } plugin.Error("Error reading backup language file 'english.yml'."); plugin.Debug(e.ToString()); } } if (primary == null && backup == null) { plugin.Error("NO LANGUAGE FILE LOADED! DEACTIVATING SCPDISCORD."); plugin.Disable(); } //Runs until the server has connected once Thread connectionThread = new Thread(new ThreadStart(() => new ConnectToBot(plugin))); connectionThread.Start(); //Runs the listener Thread botListenerThread = new Thread(new ThreadStart(() => new BotListener(plugin))); botListenerThread.Start(); //Keeps running to auto-reconnect if needed Thread watchdogThread = new Thread(new ThreadStart(() => new StartConnectionWatchdog(plugin))); watchdogThread.Start(); }
public void OnPlayerHurt(PlayerHurtEvent ev) { /// <summary> /// This is called before the player is going to take damage. /// In case the attacker can't be passed, attacker will be null (fall damage etc) /// This may be broken into two events in the future /// </summary> plugin.SendMessageAsync(plugin.GetConfigString("discord_channel_onplayerhurt"), ev.Player.Name + " (" + ev.Player.SteamId + plugin.MultiLanguage(24) + ev.Attacker.Name + " (" + ev.Attacker.SteamId + plugin.MultiLanguage(25) + ev.DamageType + "."); }
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 void OnPlayerHurt(PlayerHurtEvent ev) { /// <summary> /// This is called before the player is going to take damage. /// In case the attacker can't be passed, attacker will be null (fall damage etc) /// This may be broken into two events in the future /// </summary> if (ev.Player == null || ev.Player.TeamRole.Role == Smod2.API.Role.UNASSIGNED) { return; } if (ev.Attacker == null || ev.Player.PlayerId == ev.Attacker.PlayerId) { Dictionary <string, string> noAttackerVar = new Dictionary <string, string> { { "damage", ev.Damage.ToString() }, { "damagetype", ev.DamageType.ToString() }, { "playeripaddress", ev.Player.IpAddress }, { "playername", ev.Player.Name }, { "playerplayerid", ev.Player.PlayerId.ToString() }, { "playersteamid", ev.Player.SteamId }, { "playerclass", ev.Player.TeamRole.Role.ToString() }, { "playerteam", ev.Player.TeamRole.Team.ToString() } }; plugin.SendMessageToBot(plugin.GetConfigString("discord_channel_onplayerhurt"), "player.onplayerhurt.noattacker", noAttackerVar); return; } Dictionary <string, string> variables = new Dictionary <string, string> { { "damage", ev.Damage.ToString() }, { "damagetype", ev.DamageType.ToString() }, { "attackeripaddress", ev.Attacker.IpAddress }, { "attackername", ev.Attacker.Name }, { "attackerplayerid", ev.Attacker.PlayerId.ToString() }, { "attackersteamid", ev.Attacker.SteamId }, { "attackerclass", ev.Attacker.TeamRole.Role.ToString() }, { "attackerteam", ev.Attacker.TeamRole.Team.ToString() }, { "playeripaddress", ev.Player.IpAddress }, { "playername", ev.Player.Name }, { "playerplayerid", ev.Player.PlayerId.ToString() }, { "playersteamid", ev.Player.SteamId }, { "playerclass", ev.Player.TeamRole.Role.ToString() }, { "playerteam", ev.Player.TeamRole.Team.ToString() } }; if (IsTeamDamage((int)ev.Attacker.TeamRole.Team, (int)ev.Player.TeamRole.Team)) { plugin.SendMessageToBot(plugin.GetConfigString("discord_channel_onplayerhurt"), "player.onplayerhurt.friendlyfire", variables); return; } plugin.SendMessageToBot(plugin.GetConfigString("discord_channel_onplayerhurt"), "player.onplayerhurt", variables); }
public Language(SCPDiscordPlugin plugin) { this.plugin = plugin; plugin.language = this; Thread.Sleep(2500); // Save default language files SaveDefaultLanguages(); // Read primary language file plugin.Info("Loading primary language file..."); try { LoadLanguageFile(plugin.GetConfigString("discord_language"), false); } catch (Exception e) { if (e is DirectoryNotFoundException) { plugin.Error("Language directory not found."); } else if (e is UnauthorizedAccessException) { plugin.Error("Primary language file access denied."); } else if (e is FileNotFoundException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' was not found."); } else if (e is JsonReaderException || e is YamlException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' formatting error."); } plugin.Error("Error reading language file '" + plugin.GetConfigString("discord_language") + ".yml'. Attempting to initialize backup system..."); plugin.Debug(e.ToString()); } // Read backup language file if not the same as the primary if (plugin.GetConfigString("discord_language") != "english") { plugin.Info("Loading backup language file..."); try { LoadLanguageFile("english", true); } catch (Exception e) { if (e is DirectoryNotFoundException) { plugin.Error("Language directory not found."); } else if (e is UnauthorizedAccessException) { plugin.Error("Backup language file access denied."); } else if (e is FileNotFoundException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' was not found."); } else if (e is JsonReaderException || e is YamlException) { plugin.Error("'" + plugin.GetConfigString("discord_language") + ".yml' formatting error."); } plugin.Error("Error reading backup language file 'english.yml'."); plugin.Debug(e.ToString()); } } if (primary == null && backup == null) { plugin.Error("NO LANGUAGE FILE LOADED! DEACTIVATING SCPDISCORD."); plugin.Disable(); } ValidateLanguageStrings(); }