diff --git a/Application/Application.csproj b/Application/Application.csproj index 95623f247..8a9554a8b 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -5,7 +5,7 @@ netcoreapp2.0 false RaidMax.IW4MAdmin.Application - 2.0.0 + 2.1.0 RaidMax Forever None IW4MAdmin @@ -37,17 +37,17 @@ - + True True - Resources.resx + IW4MAdmin.en-US.resx - + ResXFileCodeGenerator - Resources.Designer.cs + IW4MAdmin.en-US.Designer.cs @@ -55,6 +55,9 @@ Always + + PreserveNewest + diff --git a/Application/ConfigurationGenerator.cs b/Application/ConfigurationGenerator.cs index 5886c4fea..b86614c33 100644 --- a/Application/ConfigurationGenerator.cs +++ b/Application/ConfigurationGenerator.cs @@ -14,14 +14,14 @@ namespace IW4MAdmin.Application public static List GenerateServerConfig(List configList) { + var loc = Utilities.CurrentLocalization.LocalizationSet; var newConfig = new ServerConfiguration(); while (string.IsNullOrEmpty(newConfig.IPAddress)) { try { - Console.Write("Enter server IP Address: "); - string input = Console.ReadLine(); + string input = Utilities.PromptString(loc["SETUP_SERVER_IP"]); IPAddress.Parse(input); newConfig.IPAddress = input; } @@ -36,8 +36,7 @@ namespace IW4MAdmin.Application { try { - Console.Write("Enter server port: "); - newConfig.Port = Int16.Parse(Console.ReadLine()); + newConfig.Port = Int16.Parse(Utilities.PromptString(loc["SETUP_SERVER_PORT"])); } catch (Exception) @@ -46,17 +45,15 @@ namespace IW4MAdmin.Application } } - Console.Write("Enter server RCON password: "); - newConfig.Password = Console.ReadLine(); + newConfig.Password = Utilities.PromptString(loc["SETUP_SERVER_RCON"]); newConfig.AutoMessages = new List(); newConfig.Rules = new List(); - newConfig.UseT6MParser = Utilities.PromptBool("Use T6M parser"); + newConfig.UseT6MParser = Utilities.PromptBool(loc["SETUP_SERVER_USET6M"]); configList.Add(newConfig); - Console.Write("Configuration saved, add another? [y/n]:"); - if (Console.ReadLine().ToLower().First() == 'y') + if (Utilities.PromptBool(loc["SETUP_SERVER_SAVE"])) GenerateServerConfig(configList); return configList; diff --git a/Application/Localization/Configure.cs b/Application/Localization/Configure.cs new file mode 100644 index 000000000..3933b8ba3 --- /dev/null +++ b/Application/Localization/Configure.cs @@ -0,0 +1,33 @@ +using SharedLibraryCore; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; + +namespace IW4MAdmin.Application.Localization +{ + public class Configure + { + public static void Initialize() + { + string currentLocal = CultureInfo.CurrentCulture.Name; + string localizationFile = $"Localization{Path.DirectorySeparatorChar}IW4MAdmin.{currentLocal}.json"; + string localizationContents; + + if (File.Exists(localizationFile)) + { + localizationContents = File.ReadAllText(localizationFile); + + } + + else + { + localizationFile = $"Localization{Path.DirectorySeparatorChar}IW4MAdmin.en-US.json"; + localizationContents = File.ReadAllText(localizationFile); + } + + Utilities.CurrentLocalization = Newtonsoft.Json.JsonConvert.DeserializeObject(localizationContents); + } + } +} diff --git a/Application/Localization/IW4MAdmin.en-US.json b/Application/Localization/IW4MAdmin.en-US.json new file mode 100644 index 000000000..b9ad8c23a --- /dev/null +++ b/Application/Localization/IW4MAdmin.en-US.json @@ -0,0 +1,109 @@ +{ + "LocalizationName": "en-US", + "LocalizationSet": { + "MANAGER_VERSION_FAIL": "Could not get latest IW4MAdmin version", + "MANAGER_VERSION_UPDATE": "has an update. Latest version is", + "MANAGER_VERSION_CURRENT": "Your version is", + "MANAGER_VERSION_SUCCESS": "IW4MAdmin is up to date", + "MANAGER_INIT_FAIL": "Fatal error during initialization", + "MANAGER_EXIT": "Press any key to exit...", + "SETUP_ENABLE_WEBFRONT": "Enable webfront", + "SETUP_ENABLE_MULTIOWN": "Enable multiple owners", + "SETUP_ENABLE_STEPPEDPRIV": "Enable stepped privilege hierarchy", + "SETUP_ENABLE_CUSTOMSAY": "Enable custom say name", + "SETUP_SAY_NAME": "Enter custom say name", + "SETUP_USE_CUSTOMENCODING": "Use custom encoding parser", + "SETUP_ENCODING_STRING": "Enter encoding string", + "SETUP_ENABLE_VPNS": "Enable client VPNs", + "SETUP_IPHUB_KEY": "Enter iphub.info api key", + "SETUP_DISPLAY_DISCORD": "Display discord link on webfront", + "SETUP_DISCORD_INVITE": "Enter discord invite link", + "SETUP_SERVER_USET6M": "Use T6M parser", + "SETUP_SERVER_IP": "Enter server IP Address", + "SETUP_SERVER_PORT": "Enter server port", + "SETUP_SERVER_RCON": "Enter server RCon password", + "SETUP_SERVER_SAVE": "Configuration saved, add another", + "SERVER_KICK_VPNS_NOTALLOWED": "VPNs are not allowed on this server", + "SERVER_KICK_TEXT": "You were kicked", + "SERVER_KICK_MINNAME": "Your name must contain at least 3 characters", + "SERVER_KICK_NAME_INUSE": "Your name is being used by someone else", + "SERVER_KICK_GENERICNAME": "Please change your name using /name", + "SERVER_KICK_CONTROLCHARS": "Your name cannot contain control characters", + "SERVER_TB_TEXT": "You're temporarily banned", + "SERVER_TB_REMAIN": "You are temporarily banned", + "SERVER_BAN_TEXT": "You're banned", + "SERVER_BAN_PREV": "Previously banned for", + "SERVER_BAN_APPEAL": "appeal at", + "SERVER_REPORT_COUNT": "There are ^5{0} ^7recent reports", + "SERVER_WARNLIMT_REACHED": "Too many warnings", + "SERVER_WARNING": "Warning", + "SERVER_WEBSITE_GENERIC": "this server's website", + "BROADCAST_ONLINE": "^5IW4MADMIN ^7is now ^2ONLINE", + "BROADCAST_OFFLINE": "IW4MAdmin is going offline", + "COMMAND_HELP_SYNTAX": "syntax:", + "COMMAND_HELP_OPTIONAL": "optional", + "COMMAND_UNKNOWN": "You entered an unknown command", + "COMMAND_NOACCESS": "You do not have access to that command", + "COMMAND_NOTAUTHORIZED": "You are not authorized to execute that command", + "COMMAND_MISSINGARGS": "Not enough arguments supplied", + "COMMAND_TARGET_MULTI": "Multiple players match that name", + "COMMAND_TARGET_NOTFOUND": "Unable to find specified player", + "PLUGIN_IMPORTER_NOTFOUND": "No plugins found to load", + "PLUGIN_IMPORTER_REGISTERCMD": "Registered command", + "COMMANDS_OWNER_SUCCESS": "Congratulations, you have claimed ownership of this server!", + "COMMANDS_OWNER_FAIL": "This server already has an owner", + "COMMANDS_WARN_FAIL": "You do not have the required privileges to warn", + "COMMANDS_WARNCLEAR_SUCCESS": "All warning cleared for", + "COMMANDS_KICK_SUCCESS": "has been kicked", + "COMMANDS_KICK_FAIL": "You do not have the required privileges to kick", + "COMMANDS_TEMPBAN_SUCCESS": "has been temporarily banned for", + "COMMANDS_TEMPBAN_FAIL": "You cannot temporarily ban", + "COMMANDS_BAN_SUCCESS": "has been permanently banned", + "COMMANDS_BAN_FAIL": "You cannot ban", + "COMMANDS_UNBAN_SUCCESS": "Successfully unbanned", + "COMMANDS_UNBAN_FAIL": "is not banned", + "COMMANDS_HELP_NOTFOUND": "Could not find that command", + "COMMANDS_HELP_MOREINFO": "Type !help to get command usage syntax", + "COMMANDS_FASTRESTART_UNMASKED": "fast restarted the map", + "COMMANDS_FASTRESTART_MASKED": "The map has been fast restarted", + "COMMANDS_MAPROTATE": "Map rotating in ^55 ^7seconds", + "COMMANDS_SETLEVEL_SELF": "You cannot change your own level", + "COMMANDS_SETLEVEL_OWNER": "There can only be 1 owner. Modify your settings if multiple owners are required", + "COMMANDS_SETLEVEL_STEPPEDDISABLED": "This server does not allow you to promote", + "COMMANDS_SETLEVEL_LEVELTOOHIGH": "You can only promote ^5{0} ^7to ^5{1} ^7or lower privilege", + "COMMANDS_SETLEVEL_SUCCESS_TARGET": "Congratulations! You have been promoted to", + "COMMANDS_SETLEVEL_SUCCESS": "was successfully promoted", + "COMMANDS_SETLEVEL_FAIL": "Invalid group specified", + "COMMANDS_ADMINS_NONE": "No visible administrators online", + "COMMANDS_MAP_SUCCESS": "Changing to map", + "COMMANDS_MAP_UKN": "Attempting to change to unknown map", + "COMMANDS_FIND_MIN": "Please enter at least 3 characters", + "COMMANDS_FIND_EMPTY": "No players found", + "COMMANDS_RULES_NONE": "The server owner has not set any rules", + "COMMANDS_FLAG_SUCCESS": "You have flagged", + "COMMANDS_FLAG_UNFLAG": "You have unflagged", + "COMMANDS_FLAG_FAIL": "You cannot flag", + "COMMANDS_REPORT_FAIL_CAMP": "You cannot report an player for camping", + "COMMANDS_REPORT_FAIL_DUPLICATE": "You have already reported this player", + "COMMANDS_REPORT_FAIL_SELF": "You cannot report yourself", + "COMMANDS_REPORT_FAIL": "You cannot report", + "COMMANDS_REPORT_SUCCESS": "Thank you for your report, an administrator has been notified", + "COMMANDS_REPORTS_CLEAR_SUCCESS": "Reports successfully cleared", + "COMMANDS_REPORTS_NONE": "No players reported yet", + "COMMANDS_MASK_ON": "You are now masked", + "COMMANDS_MASK_OFF": "You are now unmasked", + "COMMANDS_BANINFO_NONE": "No active ban was found for that player", + "COMMANDS_BANINO_SUCCESS": "was banned by ^5{0} ^7for:", + "COMMANDS_ALIAS_ALIASES": "Aliases", + "COMMANDS_ALIAS_IPS": "IPs", + "COMMANDS_RCON_SUCCESS": "Successfully sent RCon command", + "COMMANDS_PLUGINS_LOADED": "Loaded Plugins", + "COMMANDS_IP_SUCCESS": "Your external IP is", + "COMMANDS_PRUNE_FAIL": "Invalid number of inactive days", + "COMMANDS_PRUNE_SUCCESS": "inactive privileged users were pruned", + "COMMANDS_PASSWORD_FAIL": "Your password must be at least 5 characters long", + "COMMANDS_PASSWORD_SUCCESS": "Your password has been set successfully", + "COMMANDS_PING_TARGET": "ping is", + "COMMANDS_PING_SELF": "Your ping is" + } +} \ No newline at end of file diff --git a/Application/Main.cs b/Application/Main.cs index 475181582..3e3d3650e 100644 --- a/Application/Main.cs +++ b/Application/Main.cs @@ -19,6 +19,8 @@ namespace IW4MAdmin.Application { AppDomain.CurrentDomain.SetData("DataDirectory", OperatingDirectory); System.Diagnostics.Process.GetCurrentProcess().PriorityClass = System.Diagnostics.ProcessPriorityClass.BelowNormal; + Localization.Configure.Initialize(); + var loc = Utilities.CurrentLocalization.LocalizationSet; Version = Assembly.GetExecutingAssembly().GetName().Version.Major + Assembly.GetExecutingAssembly().GetName().Version.Minor / 10.0f; @@ -50,7 +52,7 @@ namespace IW4MAdmin.Application catch (Exception e) { - ServerManager.Logger.WriteWarning($"Could not get latest IW4MAdmin version"); + ServerManager.Logger.WriteWarning(loc["MANAGER_VERSION_FAIL"]); while (e.InnerException != null) { e = e.InnerException; @@ -62,7 +64,7 @@ namespace IW4MAdmin.Application if (version.CurrentVersionStable == 99.99f) { Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine("Could not get latest IW4MAdmin version."); + Console.WriteLine(loc["MANAGER_VERSION_FAIL"]); Console.ForegroundColor = ConsoleColor.White; } @@ -70,23 +72,23 @@ namespace IW4MAdmin.Application else if (version.CurrentVersionStable > Version) { Console.ForegroundColor = ConsoleColor.DarkYellow; - Console.WriteLine($"IW4MAdmin has an update. Latest version is [v{version.CurrentVersionStable.ToString("0.0")}]"); - Console.WriteLine($"Your version is [v{Version.ToString("0.0")}]"); + Console.WriteLine($"IW4MAdmin {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionStable.ToString("0.0")}]"); + Console.WriteLine($"{loc["MANAGER_VERSION_CURRENT"]} [v{Version.ToString("0.0")}]"); Console.ForegroundColor = ConsoleColor.White; } #else else if (version.CurrentVersionPrerelease > Version) { Console.ForegroundColor = ConsoleColor.DarkYellow; - Console.WriteLine($"IW4MAdmin-Prerelease has an update. Latest version is [v{version.CurrentVersionPrerelease.ToString("0.0")}-pr]"); - Console.WriteLine($"Your version is [v{Version.ToString("0.0")}-pr]"); + Console.WriteLine($"IW4MAdmin-Prerelease {loc["MANAGER_VERSION_UPDATE"]} [v{version.CurrentVersionPrerelease.ToString("0.0")}-pr]"); + Console.WriteLine($"{loc["MANAGER_VERSION_CURRENT"]} [v{Version.ToString("0.0")}-pr]"); Console.ForegroundColor = ConsoleColor.White; } #endif else { Console.ForegroundColor = ConsoleColor.Green; - Console.WriteLine("IW4MAdmin is up to date."); + Console.WriteLine(loc["MANAGER_VERSION_SUCCESS"]); Console.ForegroundColor = ConsoleColor.White; } @@ -130,13 +132,13 @@ namespace IW4MAdmin.Application catch (Exception e) { - Console.WriteLine($"Fatal Error during initialization"); + Console.WriteLine(loc["MANAGER_INIT_FAIL"]); while (e.InnerException != null) { e = e.InnerException; } Console.WriteLine($"Exception: {e.Message}"); - Console.WriteLine("Press any key to exit..."); + Console.WriteLine(loc["MANAGER_EXIT"]); Console.ReadKey(); } } diff --git a/Application/Manager.cs b/Application/Manager.cs index 5bbbc33e9..f2b2bd1db 100644 --- a/Application/Manager.cs +++ b/Application/Manager.cs @@ -163,7 +163,7 @@ namespace IW4MAdmin.Application throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid"); Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); - Utilities.EncodingType = Encoding.GetEncoding(config.CustomParserEncoding ?? "windows-1252"); + Utilities.EncodingType = Encoding.GetEncoding(!string.IsNullOrEmpty(config.CustomParserEncoding) ? config.CustomParserEncoding : "windows-1252"); #endregion #region PLUGINS @@ -373,7 +373,7 @@ namespace IW4MAdmin.Application } #if !DEBUG foreach (var S in Servers) - S.Broadcast("^1IW4MAdmin going offline!").Wait(); + S.Broadcast(Utilities.CurrentLocalization.LocalizationSet["BROADCAST_OFFLINE"]).Wait(); #endif _servers.Clear(); } diff --git a/Application/Server.cs b/Application/Server.cs index 346bfb5a1..bb3dd07cc 100644 --- a/Application/Server.cs +++ b/Application/Server.cs @@ -25,6 +25,7 @@ namespace IW4MAdmin public class IW4MServer : Server { private CancellationToken cts; + private static Dictionary loc = Utilities.CurrentLocalization.LocalizationSet; public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg) { } @@ -70,7 +71,7 @@ namespace IW4MAdmin if (polledPlayer.Name.Length < 3) { Logger.WriteDebug($"Kicking {polledPlayer} because their name is too short"); - string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, "Your name must contain atleast 3 characters."); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_MINNAME"]); await this.ExecuteCommandAsync(formattedKick); return false; } @@ -78,7 +79,7 @@ namespace IW4MAdmin if (Players.FirstOrDefault(p => p != null && p.Name == polledPlayer.Name) != null) { Logger.WriteDebug($"Kicking {polledPlayer} because their name is already in use"); - string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, "Your name is being used by someone else."); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_NAME_INUSE"]); await this.ExecuteCommandAsync(formattedKick); return false; } @@ -88,15 +89,15 @@ namespace IW4MAdmin polledPlayer.Name == "CHEATER") { Logger.WriteDebug($"Kicking {polledPlayer} because their name is generic"); - string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, "Please change your name using /name."); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_GENERICNAME"]); await this.ExecuteCommandAsync(formattedKick); return false; } if (polledPlayer.Name.Where(c => Char.IsControl(c)).Count() > 0) { - Logger.WriteDebug($"Kicking {polledPlayer} because their contains control characters"); - string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, "Your name cannot contain control characters."); + Logger.WriteDebug($"Kicking {polledPlayer} because their name contains control characters"); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, loc["SERVER_KICK_CONTROLCHARS"]); await this.ExecuteCommandAsync(formattedKick); return false; } @@ -167,14 +168,14 @@ namespace IW4MAdmin if (currentBan.Type == Penalty.PenaltyType.TempBan) { - string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, $"You are temporarily banned. ({(currentBan.Expires - DateTime.UtcNow).TimeSpanText()} left)"); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, polledPlayer.ClientNumber, $"{loc["SERVER_TB_REMAIN"]} ({(currentBan.Expires - DateTime.UtcNow).TimeSpanText()} left)"); await this.ExecuteCommandAsync(formattedKick); } else - await player.Kick($"Previously banned for {currentBan.Offense}", autoKickClient); + await player.Kick($"{loc["SERVER_BAN_PREV"]} {currentBan.Offense}", autoKickClient); if (player.Level != Player.Permission.Banned && currentBan.Type == Penalty.PenaltyType.Ban) - await player.Ban($"Previously banned for {currentBan.Offense}", autoKickClient); + await player.Ban($"{loc["SERVER_BAN_PREV"]} {currentBan.Offense}", autoKickClient); return true; } @@ -186,7 +187,7 @@ namespace IW4MAdmin if (!Manager.GetApplicationSettings().Configuration().EnableClientVPNs && await VPNCheck.UsingVPN(player.IPAddressString, Manager.GetApplicationSettings().Configuration().IPHubAPIKey)) { - await player.Kick("VPNs are not allowed on this server", new Player() { ClientId = 1 }); + await player.Kick(Utilities.CurrentLocalization.LocalizationSet["SERVER_KICK_VPNS_NOTALLOWED"], new Player() { ClientId = 1 }); } return true; @@ -233,7 +234,7 @@ namespace IW4MAdmin if (C == null) { - await E.Origin.Tell("You entered an unknown command"); + await E.Origin.Tell(loc["COMMAND_UNKNOWN"]); throw new CommandException($"{E.Origin} entered unknown command \"{CommandString}\""); } @@ -242,13 +243,13 @@ namespace IW4MAdmin if (E.Origin.Level < C.Permission) { - await E.Origin.Tell("You do not have access to that command"); + await E.Origin.Tell(loc["COMMAND_NOACCESS"]); throw new CommandException($"{E.Origin} does not have access to \"{C.Name}\""); } if (Args.Length < (C.RequiredArgumentCount)) { - await E.Origin.Tell($"Not enough arguments supplied"); + await E.Origin.Tell(loc["COMMAND_MISSINGARGS"]); await E.Origin.Tell(C.Syntax); throw new CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\""); } @@ -297,7 +298,7 @@ namespace IW4MAdmin matchingPlayers = GetClientByName(E.Data.Trim()); if (matchingPlayers.Count > 1) { - await E.Origin.Tell("Multiple players match that name"); + await E.Origin.Tell(loc["COMMAND_TARGET_MULTI"]); throw new CommandException($"{E.Origin} had multiple players found for {C.Name}"); } else if (matchingPlayers.Count == 1) @@ -310,7 +311,7 @@ namespace IW4MAdmin if (E.Data.Length == 0 && C.RequiredArgumentCount > 1) { - await E.Origin.Tell($"Not enough arguments supplied!"); + await E.Origin.Tell(loc["COMMAND_MISSINGARGS"]); await E.Origin.Tell(C.Syntax); throw new CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\""); } @@ -322,7 +323,7 @@ namespace IW4MAdmin matchingPlayers = GetClientByName(Args[0]); if (matchingPlayers.Count > 1) { - await E.Origin.Tell("Multiple players match that name"); + await E.Origin.Tell(loc["COMMAND_TARGET_MULTI"]); foreach (var p in matchingPlayers) await E.Origin.Tell($"[^3{p.ClientNumber}^7] {p.Name}"); throw new CommandException($"{E.Origin} had multiple players found for {C.Name}"); @@ -340,7 +341,7 @@ namespace IW4MAdmin E.Data == String.Empty) && C.RequiresTarget) { - await E.Origin.Tell($"Not enough arguments supplied!"); + await E.Origin.Tell(loc["COMMAND_MISSINGARGS"]); await E.Origin.Tell(C.Syntax); throw new CommandException($"{E.Origin} did not supply enough arguments for \"{C.Name}\""); } @@ -349,7 +350,7 @@ namespace IW4MAdmin if (E.Target == null && C.RequiresTarget) { - await E.Origin.Tell("Unable to find specified player."); + await E.Origin.Tell(loc["COMMAND_TARGET_NOTFOUND"]); throw new CommandException($"{E.Origin} specified invalid player for \"{C.Name}\""); } } @@ -622,7 +623,7 @@ namespace IW4MAdmin catch (DvarException) { - Website = "this server's website"; + Website = loc["SERVER_WEBSITE_GENERIC"]; } InitializeMaps(); @@ -665,7 +666,7 @@ namespace IW4MAdmin { Logger.WriteError($"Gamelog {logPath} does not exist!"); #if !DEBUG - throw new SharedLibraryCore.Exceptions.ServerException($"Invalid gamelog file {logPath}"); + throw new ServerException($"Invalid gamelog file {logPath}"); #endif } else @@ -677,7 +678,7 @@ namespace IW4MAdmin #if DEBUG // LogFile = new RemoteFile("https://raidmax.org/IW4MAdmin/getlog.php"); #else - await Broadcast("IW4M Admin is now ^2ONLINE"); + await Broadcast(loc["BROADCAST_ONLINE"]); #endif } @@ -694,7 +695,7 @@ namespace IW4MAdmin }); if (E.Origin.Level > Player.Permission.Moderator) - await E.Origin.Tell($"There are ^5{Reports.Count} ^7recent reports"); + await E.Origin.Tell(string.Format(loc["SERVER_REPORT_COUNT"], E.Owner.Reports.Count)); } else if (E.Type == GameEvent.EventType.Disconnect) @@ -756,7 +757,7 @@ namespace IW4MAdmin catch (AuthorizationException e) { - await E.Origin.Tell($"You are not authorized to execute that command - {e.Message}"); + await E.Origin.Tell($"{loc["COMMAND_NOTAUTHORIZED"]} - {e.Message}"); } catch (Exception Except) @@ -831,12 +832,12 @@ namespace IW4MAdmin { if (Target.Warnings >= 4) { - await Target.Kick("Too many warnings!", (await Manager.GetClientService().Get(1)).AsPlayer()); + await Target.Kick(loc["SERVER_WARNLIMT_REACHED"], (await Manager.GetClientService().Get(1)).AsPlayer()); return; } Target.Warnings++; - String Message = String.Format("^1WARNING ^7[^3{0}^7]: ^3{1}^7, {2}", Target.Warnings, Target.Name, Reason); + String Message = $"^1{loc["SERVER_WARNING"]} ^7[^3{Target.Warnings}^7]: ^3{Target.Name}^7, {Reason}"; await Target.CurrentServer.Broadcast(Message); } @@ -872,7 +873,7 @@ namespace IW4MAdmin #if !DEBUG else { - string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"You were Kicked - ^5{Reason}^7"); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"{loc["SERVER_KICK_TEXT"]} - ^5{Reason}^7"); await Target.CurrentServer.ExecuteCommandAsync(formattedKick); } #endif @@ -913,7 +914,7 @@ namespace IW4MAdmin #if !DEBUG else { - string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"^7You're Temporarily Banned - ^5{Reason}"); + string formattedKick = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"^7{loc["SERVER_TB_TEXT"]}- ^5{Reason}"); await Target.CurrentServer.ExecuteCommandAsync(formattedKick); } #else @@ -959,7 +960,7 @@ namespace IW4MAdmin // this is set only because they're still in the server. Target.Level = Player.Permission.Banned; #if !DEBUG - string formattedString = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"You're Banned - ^5{Message} ^7(appeal at {Website})^7"); + string formattedString = String.Format(RconParser.GetCommandPrefixes().Kick, Target.ClientNumber, $"{loc["SERVER_BAN_TEXT"]} - ^5{Message} ^7({loc["SERVER_BAN_APPEAL"]} {Website})^7"); await Target.CurrentServer.ExecuteCommandAsync(formattedString); #else await Target.CurrentServer.RemovePlayer(Target.ClientNumber); diff --git a/Master/master/templates/index.html b/Master/master/templates/index.html index 2867a6df2..4f9083d52 100644 --- a/Master/master/templates/index.html +++ b/Master/master/templates/index.html @@ -26,13 +26,14 @@ $.get('/history/' + zoomLevel) .done(function (content) { $('#history_graph').html(content.message); + dataPoints = content.data_points }); } setInterval(updateHistoryGraph, 30000); $('#history_graph_zoom_out').click(function () { // console.log(zoomLevel); - zoomLevel = zoomLevel * 2 < dataPoints ? Math.ceil(zoomLevel * 2) : dataPoints; + zoomLevel = zoomLevel * 2 <= 1440 ? Math.ceil(zoomLevel * 2) : dataPoints; updateHistoryGraph(); }); diff --git a/README.md b/README.md index c10fe2f96..5904252a5 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ _______ ### Setup **IW4MAdmin** requires minimal configuration to run. There is only one prerequisite. -* [.NET Core 2.0 Runtime](https://www.microsoft.com/net/download/dotnet-core/runtime-2.0.5) *or newer* +* [.NET Core 2.0.5 Runtime](https://www.microsoft.com/net/download/dotnet-core/runtime-2.0.5) *or newer* 1. Extract `IW4MAdmin-.zip` 2. Open command prompt or terminal in the extracted folder @@ -132,18 +132,18 @@ _These commands include all shipped plugin commands._ --- #### Player Identification -All players are identified 4 seperate ways +All players are identified 5 separate ways 1. `npID/GUID/XUID` - The ID corresponding to the player's hardware or forum account 2. `IP` - The player's IP Address 3. `Client ID` - The internal reference to a player, generated by **IW4MAdmin** 4. `Name` - The visible player name as it appears in game +5. `Client Number` - The slot the client client occupies on the server. The number ranges between 0 and the max number of clients allowed on the server For most commands players are identified by their `Name` However, if they are currently offline, or their name contains un-typable characters, their `Client ID` must be used The `Client ID` is specified by prefixing a player's reference number with `@`. For example, `@123` would reference the player with a `Client ID` of 123. -While in-game, [layers can also be referenced by `Client Number`, which is simply their slot [0 - 17] **All commands that require a `target` look at the `first argument` for a form of player identification** @@ -225,6 +225,9 @@ ___ `Profile` * Shows a client's information and history +`Web Console` +* Allows logged in privileged users to execute commands as if they are in-game + --- ### Misc diff --git a/SharedLibraryCore/Command.cs b/SharedLibraryCore/Command.cs index 8675371c0..4b46d3c87 100644 --- a/SharedLibraryCore/Command.cs +++ b/SharedLibraryCore/Command.cs @@ -29,7 +29,7 @@ namespace SharedLibraryCore public String Name { get; private set; } public String Description { get; private set; } - public String Syntax => $"syntax: !{Alias} {String.Join(" ", Arguments.Select(a => $"<{(a.Required ? "" : "optional ")}{a.Name}>"))}"; + public String Syntax => $"{Utilities.CurrentLocalization.LocalizationSet["COMMAND_HELP_SYNTAX"]} !{Alias} {String.Join(" ", Arguments.Select(a => $"<{(a.Required ? "" : Utilities.CurrentLocalization.LocalizationSet["COMMAND_HELP_OPTIONAL"] + " ")}{a.Name}>"))}"; public String Alias { get; private set; } public int RequiredArgumentCount => Arguments.Count(c => c.Required); public bool RequiresTarget { get; private set; } diff --git a/SharedLibraryCore/Commands/NativeCommands.cs b/SharedLibraryCore/Commands/NativeCommands.cs index a30d3eaa8..868f2ec9d 100644 --- a/SharedLibraryCore/Commands/NativeCommands.cs +++ b/SharedLibraryCore/Commands/NativeCommands.cs @@ -35,11 +35,11 @@ namespace SharedLibraryCore.Commands if ((await (E.Owner.Manager.GetClientService() as Services.ClientService).GetOwners()).Count == 0) { E.Origin.Level = Player.Permission.Owner; - await E.Origin.Tell("Congratulations, you have claimed ownership of this server!"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_OWNER_SUCCESS"]); await E.Owner.Manager.GetClientService().Update(E.Origin); } else - await E.Origin.Tell("This server already has an owner!"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_OWNER_FAIL"]); } } @@ -64,7 +64,7 @@ namespace SharedLibraryCore.Commands public override async Task ExecuteAsync(GameEvent E) { if (E.Origin.Level <= E.Target.Level) - await E.Origin.Tell($"You do not have the required privileges to warn {E.Target.Name}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_WARN_FAIL"]} {E.Target.Name}"); else await E.Target.Warn(E.Data, E.Origin); } @@ -86,7 +86,7 @@ namespace SharedLibraryCore.Commands public override async Task ExecuteAsync(GameEvent E) { E.Target.Warnings = 0; - String Message = String.Format("All warning cleared for {0}", E.Target.Name); + String Message = $"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_WARNCLEAR_SUCCESS"]} {E.Target.Name}"; await E.Owner.Broadcast(Message); } } @@ -115,10 +115,10 @@ namespace SharedLibraryCore.Commands { await E.Owner.ExecuteEvent(new GameEvent(GameEvent.EventType.Kick, E.Data, E.Origin, E.Target, E.Owner)); await E.Target.Kick(E.Data, E.Origin); - await E.Origin.Tell($"^5{E.Target} ^7has been kicked"); + await E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_KICK_SUCCESS"]}"); } else - await E.Origin.Tell($"You do not have the required privileges to kick {E.Target.Name}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_KICK_FAIL"]} {E.Target.Name}"); } } @@ -174,10 +174,10 @@ namespace SharedLibraryCore.Commands if (E.Origin.Level > E.Target.Level) { await E.Target.TempBan(Message, length, E.Origin); - await E.Origin.Tell($"^5{E.Target} ^7has been temporarily banned for ^5{length.TimeSpanText()}"); + await E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_TEMPBAN_SUCCESS"]} ^5{length.TimeSpanText()}"); } else - await E.Origin.Tell("You cannot temp ban " + E.Target.Name); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_TEMPBAN_FAIL"]} {E.Target.Name}"); } } @@ -204,10 +204,10 @@ namespace SharedLibraryCore.Commands if (E.Origin.Level > E.Target.Level) { await E.Target.Ban(E.Data, E.Origin); - await E.Origin.Tell($"^5{E.Target} ^7has been permanently banned"); + await E.Origin.Tell($"^5{E.Target} ^7{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_BAN_SUCCESS"]}"); } else - await E.Origin.Tell("You cannot ban " + E.Target.Name); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_BAN_FAIL"]} {E.Target.Name}"); } } @@ -235,11 +235,11 @@ namespace SharedLibraryCore.Commands if (penalties.Where(p => p.Type == Penalty.PenaltyType.Ban || p.Type == Penalty.PenaltyType.TempBan).FirstOrDefault() != null) { await E.Owner.Unban(E.Data, E.Target, E.Origin); - await E.Origin.Tell($"Successfully unbanned {E.Target}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_UNBAN_SUCCESS"]} {E.Target}"); } else { - await E.Origin.Tell($"{E.Target} is not banned"); + await E.Origin.Tell($"{E.Target} {Utilities.CurrentLocalization.LocalizationSet["COMMANDS_UNBAN_FAIL"]}"); } } } @@ -324,7 +324,7 @@ namespace SharedLibraryCore.Commands } if (!found) - await E.Origin.Tell("Could not find that command"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_HELP_NOTFOUND"]); } else @@ -351,7 +351,7 @@ namespace SharedLibraryCore.Commands } } await E.Origin.Tell(helpResponse.ToString()); - await E.Origin.Tell("Type !help to get command usage syntax"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_HELP_MOREINFO"]); } } } @@ -367,9 +367,9 @@ namespace SharedLibraryCore.Commands await E.Owner.ExecuteCommandAsync("fast_restart"); if (!E.Origin.Masked) - await E.Owner.Broadcast($"^5{E.Origin.Name} ^7fast restarted the server"); + await E.Owner.Broadcast($"^5{E.Origin.Name} ^7{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FASTRESTART_UNMASKED"]}"); else - await E.Owner.Broadcast($"The server has been fast restarted"); + await E.Owner.Broadcast(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FASTRESTART_MASKED"]); } } @@ -382,9 +382,9 @@ namespace SharedLibraryCore.Commands public override async Task ExecuteAsync(GameEvent E) { if (!E.Origin.Masked) - await E.Owner.Broadcast($"Map rotating in ^55 ^7seconds [^5{E.Origin.Name}^7]"); + await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MAPROTATE"]} [^5{E.Origin.Name}^7]"); else - await E.Owner.Broadcast($"Map rotating in ^55 ^7seconds [^5Masked Admin^7]"); + await E.Owner.Broadcast(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MAPROTATE"]); Task.Delay(5000).Wait(); await E.Owner.ExecuteCommandAsync("map_rotate"); } @@ -412,7 +412,7 @@ namespace SharedLibraryCore.Commands { if (E.Target == E.Origin) { - await E.Origin.Tell("You cannot change your own level"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_SELF"]); return; } @@ -421,14 +421,14 @@ namespace SharedLibraryCore.Commands if (newPerm == Player.Permission.Owner && !E.Owner.Manager.GetApplicationSettings().Configuration().EnableMultipleOwners) { - await E.Origin.Tell("There can only be 1 owner. Modify your settings if multiple owners are required"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_OWNER"]); return; } if (E.Origin.Level < Player.Permission.Owner && !E.Owner.Manager.GetApplicationSettings().Configuration().EnableSteppedHierarchy) { - await E.Origin.Tell($"This server does not allow you to promote ^5{E.Target.Name}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_STEPPEDDISABLED"]} ^5{E.Target.Name}"); return; } @@ -436,6 +436,7 @@ namespace SharedLibraryCore.Commands { if (E.Origin.Level < Player.Permission.Owner) { + await E.Origin.Tell(string.Format(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_LEVELTOOHIGH"], E.Target.Name, (E.Origin.Level - 1).ToString())); await E.Origin.Tell($"You can only promote ^5{E.Target.Name} ^7to ^5{(E.Origin.Level - 1)} ^7or lower privilege"); return; } @@ -449,7 +450,7 @@ namespace SharedLibraryCore.Commands if (ActiveClient != null) { ActiveClient.Level = newPerm; - await ActiveClient.Tell("Congratulations! You have been promoted to ^3" + newPerm); + await ActiveClient.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_SUCCESS_TARGET"]} {newPerm}"); } else @@ -468,11 +469,11 @@ namespace SharedLibraryCore.Commands E.Owner.Manager.GetPrivilegedClients()[E.Target.ClientId] = E.Target; } - await E.Origin.Tell($"{E.Target.Name} was successfully promoted"); + await E.Origin.Tell($"{E.Target.Name} {Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_SUCCESS"]}"); } else - await E.Origin.Tell("Invalid group specified"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_SETLEVEL_FAIL"]); } } @@ -524,7 +525,7 @@ namespace SharedLibraryCore.Commands } if (numOnline == 0) - await E.Origin.Tell("No visible administrators online"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ADMINS_NONE"]); } } @@ -548,14 +549,14 @@ namespace SharedLibraryCore.Commands { if (m.Name.ToLower() == newMap || m.Alias.ToLower() == newMap) { - await E.Owner.Broadcast($"Changing to map ^5{m.Alias}"); + await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MAP_SUCCESS"]} ^5{m.Alias}"); Task.Delay(5000).Wait(); await E.Owner.LoadMap(m.Name); return; } } - await E.Owner.Broadcast($"Attempting to change to unknown map ^5{newMap}"); + await E.Owner.Broadcast($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MAP_UKN"]} ^5{newMap}"); Task.Delay(5000).Wait(); await E.Owner.LoadMap(newMap); } @@ -578,7 +579,7 @@ namespace SharedLibraryCore.Commands { if (E.Data.Length < 3) { - await E.Origin.Tell("Please enter at least 3 characters"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FIND_MIN"]); return; } @@ -589,7 +590,7 @@ namespace SharedLibraryCore.Commands if (db_players.Count == 0) { - await E.Origin.Tell("No players found"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FIND_EMPTY"]); return; } @@ -616,9 +617,9 @@ namespace SharedLibraryCore.Commands E.Owner.ServerConfig.Rules?.Count < 1) { if (E.Message.IsBroadcastCommand()) - await E.Owner.Broadcast("The server owner has not set any rules"); + await E.Owner.Broadcast(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_RULES_NONE"]); else - await E.Origin.Tell("The server owner has not set any rules"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_RULES_NONE"]); } else @@ -687,7 +688,7 @@ namespace SharedLibraryCore.Commands // todo: move unflag to seperate command if (E.Target.Level >= E.Origin.Level) { - await E.Origin.Tell($"You cannot flag {E.Target.Name}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FLAG_FAIL"]} ^5{E.Target.Name}"); return; } @@ -695,7 +696,7 @@ namespace SharedLibraryCore.Commands { E.Target.Level = Player.Permission.User; await E.Owner.Manager.GetClientService().Update(E.Target); - await E.Origin.Tell($"You have ^5unflagged ^7{E.Target.Name}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FLAG_UNFLAG"]} ^5{E.Target.Name}"); } else @@ -716,7 +717,7 @@ namespace SharedLibraryCore.Commands await E.Owner.Manager.GetPenaltyService().Create(newPenalty); await E.Owner.ExecuteEvent(new GameEvent(GameEvent.EventType.Flag, E.Data, E.Origin, E.Target, E.Owner)); - await E.Origin.Tell($"You have flagged ^5{E.Target.Name}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_FLAG_SUCCESS"]} ^5{E.Target.Name}"); } } @@ -744,31 +745,31 @@ namespace SharedLibraryCore.Commands { if (E.Data.ToLower().Contains("camp")) { - await E.Origin.Tell("You cannot report a player for camping"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORT_FAIL_CAMP"]); return; } if (E.Owner.Reports.Find(x => (x.Origin == E.Origin && x.Target.NetworkId == E.Target.NetworkId)) != null) { - await E.Origin.Tell("You have already reported this player"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORT_FAIL_DUPLICATE"]); return; } if (E.Target == E.Origin) { - await E.Origin.Tell("You cannot report yourself"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORT_FAIL_SELF"]); return; } if (E.Target.Level > E.Origin.Level) { - await E.Origin.Tell($"You cannot report {E.Target.Name}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORT_FAIL"]} {E.Target.Name}"); return; } E.Owner.Reports.Add(new Report(E.Target, E.Origin, E.Data)); - await E.Origin.Tell($"Thank you for your report, an administrator has been notified"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORT_SUCCESS"]); await E.Owner.ExecuteEvent(new GameEvent(GameEvent.EventType.Report, E.Data, E.Origin, E.Target, E.Owner)); await E.Owner.ToAdmins(String.Format("^5{0}^7->^1{1}^7: {2}", E.Origin.Name, E.Target.Name, E.Data)); } @@ -792,13 +793,13 @@ namespace SharedLibraryCore.Commands if (E.Data != null && E.Data.ToLower().Contains("clear")) { E.Owner.Reports = new List(); - await E.Origin.Tell("Reports successfully cleared!"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORTS_CLEAR_SUCCESS"]); return; } if (E.Owner.Reports.Count < 1) { - await E.Origin.Tell("No players reported yet"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_REPORTS_NONE"]); return; } @@ -818,12 +819,12 @@ namespace SharedLibraryCore.Commands if (E.Origin.Masked) { E.Origin.Masked = false; - await E.Origin.Tell("You are now unmasked"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MASK_OFF"]); } else { E.Origin.Masked = true; - await E.Origin.Tell("You are now masked"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_MASK_ON"]); } await E.Owner.Manager.GetClientService().Update(E.Origin); @@ -851,12 +852,16 @@ namespace SharedLibraryCore.Commands if (penalty == null) { - await E.Origin.Tell("No active ban was found for that player"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_BANINFO_NONE"]); return; } - await E.Origin.Tell(String.Format("^1{0} ^7was banned by ^5{1} ^7for: {2} {3}", E.Target.Name, penalty.Punisher.Name, penalty.Offense, penalty.Type == Penalty.PenaltyType.TempBan ? $"({(penalty.Expires - DateTime.UtcNow).TimeSpanText()} remaining)" : "")); + string timeRemaining = penalty.Type == Penalty.PenaltyType.TempBan ? $"({(penalty.Expires - DateTime.UtcNow).TimeSpanText()} remaining)" : ""; + string success = Utilities.CurrentLocalization.LocalizationSet["COMMANDS_BANINO_SUCCESS"]; + + await E.Origin.Tell($"^1{E.Target.Name} ^7{string.Format(success, penalty.Punisher.Name)} {penalty.Punisher.Name} {timeRemaining}"); } + } public class CListAlias : Command @@ -880,12 +885,12 @@ namespace SharedLibraryCore.Commands await E.Target.Tell($"[^3{E.Target}^7]"); - message.Append("Aliases: "); + message.Append($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ALIAS_ALIASES"]}: "); message.Append(String.Join(" | ", names)); await E.Origin.Tell(message.ToString()); message.Clear(); - message.Append("IPs: "); + message.Append($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_ALIAS_IPS"]}: "); message.Append(String.Join(" | ", IPs)); await E.Origin.Tell(message.ToString()); } @@ -910,7 +915,7 @@ namespace SharedLibraryCore.Commands foreach (string S in Response) await E.Origin.Tell(S.StripColors()); if (Response.Length == 0) - await E.Origin.Tell("Successfully sent RCON command!"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_RCON_SUCCESS"]); } } @@ -922,7 +927,7 @@ namespace SharedLibraryCore.Commands public override async Task ExecuteAsync(GameEvent E) { - await E.Origin.Tell("^5Loaded Plugins:"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PLUGINS_LOADE"]); foreach (var P in Plugins.PluginImporter.ActivePlugins) { await E.Origin.Tell(String.Format("^3{0} ^7[v^3{1}^7] by ^5{2}^7", P.Name, P.Version, P.Author)); @@ -938,7 +943,7 @@ namespace SharedLibraryCore.Commands public override async Task ExecuteAsync(GameEvent E) { - await E.Origin.Tell($"Your external IP is ^5{E.Origin.IPAddressString}"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_IP_SUCCESS"]} ^5{E.Origin.IPAddressString}"); } } @@ -987,7 +992,7 @@ namespace SharedLibraryCore.Commands inactiveUsers.ForEach(c => c.Level = Player.Permission.User); await context.SaveChangesAsync(); } - await E.Origin.Tell($"Pruned {inactiveUsers.Count} inactive privileged users"); + await E.Origin.Tell($"^5{inactiveUsers.Count} ^7{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PRUNE_SUCCESS"]}"); } } @@ -1008,7 +1013,7 @@ namespace SharedLibraryCore.Commands { if (E.Data.Length < 5) { - await E.Origin.Tell("Your password must be atleast 5 characters long"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PASSWORD_FAIL"]); return; } @@ -1021,7 +1026,7 @@ namespace SharedLibraryCore.Commands E.Owner.Manager.GetPrivilegedClients()[E.Origin.ClientId] = E.Origin; await E.Owner.Manager.GetClientService().Update(E.Origin); - await E.Origin.Tell("Your password has been set successfully"); + await E.Origin.Tell(Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PASSWORD_SUCCESS"]); } } @@ -1095,16 +1100,16 @@ namespace SharedLibraryCore.Commands if (E.Message.IsBroadcastCommand()) { if (E.Target == null) - await E.Owner.Broadcast($"{E.Origin.Name}'s ping is ^5{E.Origin.Ping}^7ms"); + await E.Owner.Broadcast($"{E.Origin.Name}'s {Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PING_TARGET"]} ^5{E.Origin.Ping}^7ms"); else - await E.Owner.Broadcast($"{E.Target.Name}'s ping is ^5{E.Target.Ping}^7ms"); + await E.Owner.Broadcast($"{E.Target.Name}'s {Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PING_TARGET"]} ^5{E.Target.Ping}^7ms"); } else { if (E.Target == null) - await E.Origin.Tell($"Your ping is ^5{E.Origin.Ping}^7ms"); + await E.Origin.Tell($"{Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PING_SELF"]} ^5{E.Origin.Ping}^7ms"); else - await E.Origin.Tell($"{E.Target.Name}'s ping is ^5{E.Target.Ping}^7ms"); + await E.Origin.Tell($"{E.Target.Name}'s {Utilities.CurrentLocalization.LocalizationSet["COMMANDS_PING_TARGET"]} ^5{E.Target.Ping}^7ms"); } } } diff --git a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs index 0915e0cbd..b697107aa 100644 --- a/SharedLibraryCore/Configuration/ApplicationConfiguration.cs +++ b/SharedLibraryCore/Configuration/ApplicationConfiguration.cs @@ -27,30 +27,32 @@ namespace SharedLibraryCore.Configuration public IBaseConfiguration Generate() { + var loc = Utilities.CurrentLocalization.LocalizationSet; Id = Guid.NewGuid().ToString(); - EnableWebFront = Utilities.PromptBool("Enable webfront"); - EnableMultipleOwners = Utilities.PromptBool("Enable multiple owners"); - EnableSteppedHierarchy = Utilities.PromptBool("Enable stepped privilege hierarchy"); - EnableCustomSayName = Utilities.PromptBool("Enable custom say name"); + + EnableWebFront = Utilities.PromptBool(loc["SETUP_ENABLE_WEBFRONT"]); + EnableMultipleOwners = Utilities.PromptBool(loc["SETUP_ENABLE_MULTIOWN"]); + EnableSteppedHierarchy = Utilities.PromptBool(loc["SETUP_ENABLE_STEPPEDPRIV"]); + EnableCustomSayName = Utilities.PromptBool(loc["SETUP_ENABLE_CUSTOMSAY"]); - bool useCustomParserEncoding = Utilities.PromptBool("Use custom encoding parser"); - CustomParserEncoding = useCustomParserEncoding ? Utilities.PromptString("Enter encoding string") : "windows-1252"; + bool useCustomParserEncoding = Utilities.PromptBool(loc["SETUP_USE_CUSTOMENCODING"]); + CustomParserEncoding = useCustomParserEncoding ? Utilities.PromptString(loc["SETUP_ENCODING_STRING"]) : "windows-1252"; WebfrontBindUrl = "http://127.0.0.1:1624"; if (EnableCustomSayName) - CustomSayName = Utilities.PromptString("Enter custom say name"); + CustomSayName = Utilities.PromptString(loc["SETUP_SAY_NAME"]); - EnableClientVPNs = Utilities.PromptBool("Enable client VPNS"); + EnableClientVPNs = Utilities.PromptBool(loc["SETUP_ENABLE_VPNS"]); if (!EnableClientVPNs) - IPHubAPIKey = Utilities.PromptString("Enter iphub.info api key"); + IPHubAPIKey = Utilities.PromptString(loc["SETUP_IPHUB_KEY"]); - EnableDiscordLink = Utilities.PromptBool("Display discord link on webfront"); + EnableDiscordLink = Utilities.PromptBool(loc["SETUP_DISPLAY_DISCORD"]); if (EnableDiscordLink) - DiscordInviteCode = Utilities.PromptString("Enter discord invite link"); + DiscordInviteCode = Utilities.PromptString(loc["SETUP_DISCORD_INVITE"]); return this; } diff --git a/SharedLibraryCore/Configuration/ServerConfiguration.cs b/SharedLibraryCore/Configuration/ServerConfiguration.cs index b73b95960..f8d456fd7 100644 --- a/SharedLibraryCore/Configuration/ServerConfiguration.cs +++ b/SharedLibraryCore/Configuration/ServerConfiguration.cs @@ -14,7 +14,7 @@ namespace SharedLibraryCore.Configuration public IBaseConfiguration Generate() { - UseT6MParser = Utilities.PromptBool("Use T6M parser"); + UseT6MParser = Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationSet["SETUP_SERVER_USET6M"]); return this; } diff --git a/SharedLibraryCore/Database/Importer.cs b/SharedLibraryCore/Database/Importer.cs deleted file mode 100644 index 6bc89cc80..000000000 --- a/SharedLibraryCore/Database/Importer.cs +++ /dev/null @@ -1,212 +0,0 @@ -using Microsoft.EntityFrameworkCore; -using SharedLibraryCore.Database.Models; -using SharedLibraryCore.Objects; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SharedLibraryCore.Database -{ - //https://stackoverflow.com/questions/5940225/fastest-way-of-inserting-in-entity-framework - public static class Importer - { - public static void ImportClients(IList clients) - { - DatabaseContext context = null; - - try - { - context = new DatabaseContext(); - - int count = 0; - foreach (var entityToInsert in clients) - { - ++count; - - var link = new EFAliasLink() { Active = true }; - - var alias = new EFAlias() - { - Active = true, - DateAdded = entityToInsert.LastConnection, - IPAddress = entityToInsert.IPAddress, - Link = link, - Name = entityToInsert.Name, - }; - - var client = new EFClient() - { - Active = true, - AliasLink = link, - Connections = entityToInsert.Connections, - CurrentAlias = alias, - FirstConnection = entityToInsert.LastConnection, - Level = entityToInsert.Level, - LastConnection = entityToInsert.LastConnection, - TotalConnectionTime = entityToInsert.TotalConnectionTime, - Masked = entityToInsert.Masked, - NetworkId = entityToInsert.NetworkId - }; - - context = AddClient(context, client, count, 1000, true); - } - - context.SaveChanges(); - } - finally - { - if (context != null) - context.Dispose(); - } - } - - private static DatabaseContext AddClient(DatabaseContext context, EFClient client, int count, int commitCount, bool recreateContext) - { - context.Clients.Add(client); - if (count % commitCount == 0) - { - try - { - context.SaveChanges(); - } - - catch (Exception) - { - - } - - if (recreateContext) - { - context.Dispose(); - context = new DatabaseContext(); - } - } - - return context; - } - - public static void ImportPenalties(IList penalties) - { - DatabaseContext context = null; - - try - { - context = new DatabaseContext(); - - int count = 0; - foreach (var entityToInsert in penalties) - { - ++count; - var punisher = entityToInsert.Offender.NetworkId == entityToInsert.Punisher.NetworkId ? - context.Clients.SingleOrDefault(c => c.ClientId == 1) : - context.Clients.SingleOrDefault(c => c.NetworkId == entityToInsert.Punisher.NetworkId); - if (punisher == null) - continue; - var offender = context.Clients.Include("AliasLink").SingleOrDefault(c => c.NetworkId == entityToInsert.Offender.NetworkId); - - if (offender == null) - continue; - - - var penalty = new EFPenalty() - { - Active = true, - Expires = entityToInsert.Expires.Year == 9999 ? DateTime.Parse(System.Data.SqlTypes.SqlDateTime.MaxValue.ToString()) : entityToInsert.Expires, - Offender = offender, - Punisher = punisher, - Offense = entityToInsert.Offense, - Type = entityToInsert.Type, - When = entityToInsert.When == DateTime.MinValue ? DateTime.UtcNow : entityToInsert.When, - Link = offender.AliasLink - }; - - context = AddPenalty(context, penalty, count, 1000, true); - } - - context.SaveChanges(); - } - finally - { - if (context != null) - context.Dispose(); - } - } - - private static DatabaseContext AddPenalty(DatabaseContext context, EFPenalty penalty, int count, int commitCount, bool recreateContext) - { - context.Penalties.Add(penalty); - if (count % commitCount == 0) - { - try - { - context.SaveChanges(); - } - - catch (Exception) - { - - } - - if (recreateContext) - { - context.Dispose(); - context = new DatabaseContext(); - } - } - - return context; - } - - public static void ImportSQLite(IList SQLiteData) where T : class - { - DatabaseContext context = null; - - try - { - context = new DatabaseContext(); - - int count = 0; - foreach (var entityToInsert in SQLiteData) - { - ++count; - context = AddSQLite(context, entityToInsert, count, 1000, true); - } - - context.SaveChanges(); - } - finally - { - if (context != null) - context.Dispose(); - } - } - - private static DatabaseContext AddSQLite(DatabaseContext context, T entity, int count, int commitCount, bool recreateContext) where T : class - { - context.Set().Add(entity); - - if (count % commitCount == 0) - { - try - { - context.SaveChanges(); - } - - catch (Exception) - { - - } - - if (recreateContext) - { - context.Dispose(); - context = new DatabaseContext(); - } - } - return context; - } - } -} - diff --git a/SharedLibraryCore/Helpers/ThreadSafe.cs b/SharedLibraryCore/Helpers/ThreadSafe.cs deleted file mode 100644 index 170b937e1..000000000 --- a/SharedLibraryCore/Helpers/ThreadSafe.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace SharedLibraryCore.Helpers -{ - /// - /// Excuse this monstrosity - /// - /// - public class ThreadSafe - { - private bool _lock; - private T instance; - - public ThreadSafe(T instance) - { - this.instance = instance; - _lock = true; - } - - public T Value - { - get - { - // shush - if (_lock) - return Value; - _lock = true; - return instance; - } - - set - { - if (_lock) - { - Value = Value; - return; - } - instance = Value; - } - } - - - } -} diff --git a/SharedLibraryCore/Localization/Layout.cs b/SharedLibraryCore/Localization/Layout.cs new file mode 100644 index 000000000..5f6d6580c --- /dev/null +++ b/SharedLibraryCore/Localization/Layout.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace SharedLibraryCore.Localization +{ + public class Layout + { + public string LocalizationName { get; set; } + public Dictionary LocalizationSet { get; set; } + } +} diff --git a/SharedLibraryCore/PluginImporter.cs b/SharedLibraryCore/PluginImporter.cs index d24ce227b..a187b2662 100644 --- a/SharedLibraryCore/PluginImporter.cs +++ b/SharedLibraryCore/PluginImporter.cs @@ -17,7 +17,7 @@ namespace SharedLibraryCore.Plugins if (dllFileNames.Length == 0) { - Manager.GetLogger().WriteDebug("No plugins found to load"); + Manager.GetLogger().WriteDebug(Utilities.CurrentLocalization.LocalizationSet["PLUGIN_IMPORTER_NOTFOUND"]); return true; } @@ -43,7 +43,7 @@ namespace SharedLibraryCore.Plugins Object commandObject = Activator.CreateInstance(assemblyType); Command newCommand = (Command)commandObject; ActiveCommands.Add(newCommand); - Manager.GetLogger().WriteDebug("Registered command \"" + newCommand.Name + "\""); + Manager.GetLogger().WriteDebug($"{Utilities.CurrentLocalization.LocalizationSet["PLUGIN_IMPORTER_REGISTERCMD"]} \"{newCommand.Name}\""); LoadedCommands++; continue; } diff --git a/SharedLibraryCore/SharedLibraryCore.csproj b/SharedLibraryCore/SharedLibraryCore.csproj index 7afb3d952..52ea8b1f7 100644 --- a/SharedLibraryCore/SharedLibraryCore.csproj +++ b/SharedLibraryCore/SharedLibraryCore.csproj @@ -6,7 +6,7 @@ RaidMax.IW4MAdmin.SharedLibraryCore - 2.0.0 + 2.1.0 RaidMax Forever None Debug;Release;Prerelease @@ -17,6 +17,7 @@ + diff --git a/SharedLibraryCore/Utilities.cs b/SharedLibraryCore/Utilities.cs index 4dce4a886..d2d113799 100644 --- a/SharedLibraryCore/Utilities.cs +++ b/SharedLibraryCore/Utilities.cs @@ -1,5 +1,4 @@ using System; -using System.Threading; using System.Text; using System.Text.RegularExpressions; using System.Linq; @@ -9,10 +8,7 @@ using SharedLibraryCore.Objects; using static SharedLibraryCore.Server; using System.Reflection; using System.IO; -using System.Diagnostics; using System.Threading.Tasks; -using static SharedLibraryCore.RCon.StaticHelpers; -using System.Runtime.InteropServices; namespace SharedLibraryCore { @@ -21,6 +17,7 @@ namespace SharedLibraryCore public static string OperatingDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + Path.DirectorySeparatorChar; public static readonly Task CompletedTask = Task.FromResult(false); public static Encoding EncodingType; + public static Localization.Layout CurrentLocalization; //Get string with specified number of spaces -- really only for visual output public static String GetSpaces(int Num) diff --git a/version.txt b/version.txt index 964fe998c..1381496a8 100644 --- a/version.txt +++ b/version.txt @@ -1,3 +1,7 @@ +Version 2.1: +CHANGELOG: +-add support for localization + Version 2.0: CHANGELOG: -migrated all projects and remaining plugins to .NET Core 2