using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; using System.Runtime.CompilerServices; using System.Text; using System.Text.RegularExpressions; using System.Threading; using MinecraftClient.Protocol; using MinecraftClient.Proxy; using Tomlet; using Tomlet.Attributes; using Tomlet.Models; using static MinecraftClient.Settings.AppVarConfigHelper; using static MinecraftClient.Settings.ChatBotConfigHealper; using static MinecraftClient.Settings.ChatFormatConfigHelper; using static MinecraftClient.Settings.ConsoleConfigHealper; using static MinecraftClient.Settings.HeadCommentHealper; using static MinecraftClient.Settings.LoggingConfigHealper; using static MinecraftClient.Settings.MainConfigHealper; using static MinecraftClient.Settings.MainConfigHealper.MainConfig; using static MinecraftClient.Settings.MainConfigHealper.MainConfig.AdvancedConfig; using static MinecraftClient.Settings.MCSettingsConfigHealper; using static MinecraftClient.Settings.SignatureConfigHelper; namespace MinecraftClient { public static class Settings { private const int CommentsAlignPosition = 45; private readonly static Regex CommentRegex = new(@"^(.*)\s?#\s\$([\w\.]+)\$\s*$$", RegexOptions.Compiled); // Other Settings public const string TranslationsFile_Version = "1.19.3"; public const string TranslationsFile_Website_Index = "https://piston-meta.mojang.com/v1/packages/c492375ded5da34b646b8c5c0842a0028bc69cec/2.json"; public const string TranslationsFile_Website_Download = "https://resources.download.minecraft.net"; public const string TranslationProjectUrl = "https://crwd.in/minecraft-console-client"; public static GlobalConfig Config = new(); public static class InternalConfig { public static string ServerIP = String.Empty; public static ushort ServerPort = 25565; public static AccountInfoConfig Account = new(); public static string Username = string.Empty; public static string MinecraftVersion = string.Empty; public static bool InteractiveMode = true; public static bool GravityEnabled = true; public static bool KeepAccountSettings = false; public static bool KeepServerSettings = false; } public class GlobalConfig { [TomlPrecedingComment("$Head$")] public HeadComment Head { get { return HeadCommentHealper.Config; } set { HeadCommentHealper.Config = value; HeadCommentHealper.Config.OnSettingUpdate(); } } public MainConfig Main { get { return MainConfigHealper.Config; } set { MainConfigHealper.Config = value; MainConfigHealper.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$Signature$")] public SignatureConfig Signature { get { return SignatureConfigHelper.Config; } set { SignatureConfigHelper.Config = value; SignatureConfigHelper.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$Logging$")] public LoggingConfig Logging { get { return LoggingConfigHealper.Config; } set { LoggingConfigHealper.Config = value; LoggingConfigHealper.Config.OnSettingUpdate(); } } public ConsoleConfig Console { get { return ConsoleConfigHealper.Config; } set { ConsoleConfigHealper.Config = value; ConsoleConfigHealper.Config.OnSettingUpdate(); } } public AppVarConfig AppVar { get { return AppVarConfigHelper.Config; } set { AppVarConfigHelper.Config = value; AppVarConfigHelper.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$Proxy$")] public ProxyHandler.Configs Proxy { get { return ProxyHandler.Config; } set { ProxyHandler.Config = value; ProxyHandler.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$MCSettings$")] public MCSettingsConfig MCSettings { get { return MCSettingsConfigHealper.Config; } set { MCSettingsConfigHealper.Config = value; MCSettingsConfigHealper.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatFormat$")] public ChatFormatConfig ChatFormat { get { return ChatFormatConfigHelper.Config; } set { ChatFormatConfigHelper.Config = value; ChatFormatConfigHelper.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot$")] public ChatBotConfig ChatBot { get { return ChatBotConfigHealper.Config; } set { ChatBotConfigHealper.Config = value; } } } public static Tuple LoadFromFile(string filepath, bool keepAccountAndServerSettings = false) { bool keepAccountSettings = InternalConfig.KeepAccountSettings; bool keepServerSettings = InternalConfig.KeepServerSettings; if (keepAccountAndServerSettings) InternalConfig.KeepAccountSettings = InternalConfig.KeepServerSettings = true; Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; TomlDocument document; try { document = TomlParser.ParseFile(filepath); Thread.CurrentThread.CurrentCulture = Program.ActualCulture; Config = TomletMain.To(document); } catch (Exception ex) { Thread.CurrentThread.CurrentCulture = Program.ActualCulture; try { // The old configuration file has been backed up as A. string configString = File.ReadAllText(filepath); if (configString.Contains("Some settings missing here after an upgrade?")) { string newFilePath = Path.ChangeExtension(filepath, ".old.ini"); File.Copy(filepath, newFilePath, true); ConsoleIO.WriteLineFormatted("§c" + Translations.mcc_use_new_config); ConsoleIO.WriteLineFormatted("§c" + string.Format(Translations.mcc_backup_old_config, newFilePath)); return new(false, true); } } catch { } ConsoleIO.WriteLineFormatted("§c" + Translations.config_load_fail); ConsoleIO.WriteLine(ex.GetFullMessage()); return new(false, false); } finally { if (!keepAccountSettings) InternalConfig.KeepAccountSettings = false; if (!keepServerSettings) InternalConfig.KeepServerSettings = false; } return new(true, false); } public static void WriteToFile(string filepath, bool backupOldFile) { Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; string tomlString = TomletMain.TomlStringFrom(Config); Thread.CurrentThread.CurrentCulture = Program.ActualCulture; string[] tomlList = tomlString.Split('\n'); StringBuilder newConfig = new(); foreach (string line in tomlList) { Match matchComment = CommentRegex.Match(line); if (matchComment.Success && matchComment.Groups.Count == 3) { string config = matchComment.Groups[1].Value, comment = matchComment.Groups[2].Value; if (config.Length > 0) newConfig.Append(config).Append(' ', Math.Max(1, CommentsAlignPosition - config.Length) - 1); string? comment_trans = ConfigComments.ResourceManager.GetString(comment); if (string.IsNullOrEmpty(comment_trans)) newConfig.Append("# ").AppendLine(comment.ReplaceLineEndings()); else newConfig.Append("# ").AppendLine(comment_trans.Replace("\n", "\n# ").ReplaceLineEndings()); } else { newConfig.AppendLine(line); } } bool needUpdate = true; byte[] newConfigByte = Encoding.UTF8.GetBytes(newConfig.ToString()); if (File.Exists(filepath)) { try { if (new FileInfo(filepath).Length == newConfigByte.Length) if (File.ReadAllBytes(filepath).SequenceEqual(newConfigByte)) needUpdate = false; } catch { } } if (needUpdate) { bool backupSuccessed = true; if (backupOldFile && File.Exists(filepath)) { string backupFilePath = Path.ChangeExtension(filepath, ".backup.ini"); try { File.Copy(filepath, backupFilePath, true); } catch (Exception ex) { backupSuccessed = false; ConsoleIO.WriteLineFormatted("§c" + string.Format(Translations.config_backup_fail, backupFilePath)); ConsoleIO.WriteLine(ex.Message); } } if (backupSuccessed) { try { File.WriteAllBytes(filepath, newConfigByte); } catch (Exception ex) { ConsoleIO.WriteLineFormatted("§c" + string.Format(Translations.config_write_fail, filepath)); ConsoleIO.WriteLine(ex.Message); } } } } /// /// Load settings from the command line /// /// Command-line arguments /// Thrown on invalid arguments public static void LoadArguments(string[] args) { int positionalIndex = 0; bool skipPassword = false; foreach (string argument in args) { if (argument.StartsWith("--")) { //Load settings as --setting=value and --section.setting=value if (!argument.Contains('=')) throw new ArgumentException(string.Format(Translations.error_setting_argument_syntax, argument)); throw new NotImplementedException(); } else if (argument.StartsWith("-") && argument.Length > 1) { //Keep single dash arguments as unsupported for now (future use) throw new ArgumentException(string.Format(Translations.error_setting_argument_syntax, argument)); } else { switch (positionalIndex) { case 0: if (Config.Main.Advanced.AccountList.TryGetValue(argument, out AccountInfoConfig accountInfo)) { InternalConfig.Account = accountInfo; skipPassword = true; } else { InternalConfig.Account.Login = argument; } InternalConfig.KeepAccountSettings = true; break; case 1: if (!skipPassword) InternalConfig.Account.Password = argument; break; case 2: Config.Main.SetServerIP(new MainConfig.ServerInfoConfig(argument), true); InternalConfig.KeepServerSettings = true; break; case 3: // SingleCommand = argument; break; } positionalIndex++; } } } public static class HeadCommentHealper { public static HeadComment Config = new(); [TomlDoNotInlineObject] public class HeadComment { [TomlProperty("Current Version")] public string CurrentVersion { get; set; } = Program.BuildInfo ?? "Development Build"; [TomlProperty("Latest Version")] public string LatestVersion { get; set; } = "Unknown"; public void OnSettingUpdate() { CurrentVersion = Program.BuildInfo ?? "Development Build"; LatestVersion ??= "Unknown"; } } } public static class MainConfigHealper { public static MainConfig Config = new(); [TomlDoNotInlineObject] public class MainConfig { public GeneralConfig General = new(); [TomlPrecedingComment("$Main.Advanced$")] public AdvancedConfig Advanced = new(); [NonSerialized] public static readonly string[] AvailableLang = { "af_za", "ar_sa", "ast_es", "az_az", "ba_ru", "bar", "be_by", "bg_bg", "br_fr", "brb", "bs_ba", "ca_es", "cs_cz", "cy_gb", "da_dk", "de_at", "de_ch", "de_de", "el_gr", "en_au", "en_ca", "en_gb", "en_nz", "en_pt", "en_ud", "en_us", "enp", "enws", "eo_uy", "es_ar", "es_cl", "es_ec", "es_es", "es_mx", "es_uy", "es_ve", "esan", "et_ee", "eu_es", "fa_ir", "fi_fi", "fil_ph", "fo_fo", "fr_ca", "fr_fr", "fra_de", "fur_it", "fy_nl", "ga_ie", "gd_gb", "gl_es", "haw_us", "he_il", "hi_in", "hr_hr", "hu_hu", "hy_am", "id_id", "ig_ng", "io_en", "is_is", "isv", "it_it", "ja_jp", "jbo_en", "ka_ge", "kk_kz", "kn_in", "ko_kr", "ksh", "kw_gb", "la_la", "lb_lu", "li_li", "lmo", "lol_us", "lt_lt", "lv_lv", "lzh", "mk_mk", "mn_mn", "ms_my", "mt_mt", "nah", "nds_de", "nl_be", "nl_nl", "nn_no", "no_no", "oc_fr", "ovd", "pl_pl", "pt_br", "pt_pt", "qya_aa", "ro_ro", "rpr", "ru_ru", "ry_ua", "se_no", "sk_sk", "sl_si", "so_so", "sq_al", "sr_sp", "sv_se", "sxu", "szl", "ta_in", "th_th", "tl_ph", "tlh_aa", "tok", "tr_tr", "tt_ru", "uk_ua", "val_es", "vec_it", "vi_vn", "yi_de", "yo_ng", "zh_cn", "zh_hk", "zh_tw", "zlm_arab" }; /// /// Load server information in ServerIP and ServerPort variables from a "serverip:port" couple or server alias /// /// True if the server IP was valid and loaded, false otherwise public bool SetServerIP(ServerInfoConfig serverInfo, bool checkAlias) { string[] sip = serverInfo.Host.Split(new[] { ":", ":" }, StringSplitOptions.None); string host = ToLowerIfNeed(sip[0]); ushort port = 25565; if (serverInfo.Port.HasValue) { port = serverInfo.Port.Value; } else if (sip.Length > 1) { try { port = Convert.ToUInt16(sip[1]); } catch (FormatException) { return false; } } if (host == "localhost" || host.Contains('.')) { //Server IP (IP or domain names contains at least a dot) if (sip.Length == 1 && !serverInfo.Port.HasValue && host.Contains('.') && host.Any(c => char.IsLetter(c)) && Settings.Config.Main.Advanced.ResolveSrvRecords != ResolveSrvRecordType.no) //Domain name without port may need Minecraft SRV Record lookup ProtocolHandler.MinecraftServiceLookup(ref host, ref port); InternalConfig.ServerIP = host; InternalConfig.ServerPort = port; return true; } else if (checkAlias && Advanced.ServerList.TryGetValue(sip[0], out ServerInfoConfig serverStr2)) { return SetServerIP(serverStr2, false); } return false; } public void OnSettingUpdate() { ConsoleIO.EnableTimestamps = Advanced.Timestamps; InternalConfig.InteractiveMode = !Advanced.ExitOnFailure; General.Account.Login ??= string.Empty; General.Account.Password ??= string.Empty; if (!InternalConfig.KeepAccountSettings) { if (Advanced.AccountList.TryGetValue(General.Account.Login, out AccountInfoConfig account)) InternalConfig.Account = account; else InternalConfig.Account = General.Account; } General.Server.Host ??= string.Empty; if (Advanced.MessageCooldown < 0) Advanced.MessageCooldown = 0; if (Advanced.TcpTimeout < 1) Advanced.TcpTimeout = 1; if (Advanced.MovementSpeed < 1) Advanced.MovementSpeed = 1; if (!Advanced.LoadMccTranslation) { CultureInfo culture = CultureInfo.CreateSpecificCulture("en-US"); CultureInfo.DefaultThreadCurrentCulture = culture; CultureInfo.DefaultThreadCurrentUICulture = culture; Program.ActualCulture = culture; Thread.CurrentThread.CurrentCulture = culture; Thread.CurrentThread.CurrentUICulture = culture; } Advanced.Language = Regex.Replace(Advanced.Language, @"[^-^_^\w^*\d]", string.Empty).Replace('-', '_'); Advanced.Language = ToLowerIfNeed(Advanced.Language); if (!AvailableLang.Contains(Advanced.Language)) { Advanced.Language = GetDefaultGameLanguage(); ConsoleIO.WriteLogLine("[Settings] " + Translations.config_Main_Advanced_language_invaild); } if (!InternalConfig.KeepServerSettings) { if (!string.IsNullOrWhiteSpace(General.Server.Host)) { string[] sip = General.Server.Host.Split(new[] { ":", ":" }, StringSplitOptions.None); General.Server.Host = sip[0]; InternalConfig.ServerIP = General.Server.Host; if (sip.Length > 1) { try { General.Server.Port = Convert.ToUInt16(sip[1]); } catch (FormatException) { } } } if (General.Server.Port.HasValue) InternalConfig.ServerPort = General.Server.Port.Value; else SetServerIP(General.Server, true); } for (int i = 0; i < Advanced.BotOwners.Count; ++i) Advanced.BotOwners[i] = ToLowerIfNeed(Advanced.BotOwners[i]); if (Advanced.MinTerminalWidth < 1) Advanced.MinTerminalWidth = 1; if (Advanced.MinTerminalHeight < 1) Advanced.MinTerminalHeight = 1; if (Advanced.TemporaryFixBadpacket && !Advanced.TerrainAndMovements) { Advanced.TerrainAndMovements = true; ConsoleIO.WriteLineFormatted("§c[Settings]You need to enable TerrainAndMovements before enabling TemporaryFixBadpacket."); } } [TomlDoNotInlineObject] public class GeneralConfig { [TomlInlineComment("$Main.General.account$")] public AccountInfoConfig Account = new(string.Empty, string.Empty); [TomlInlineComment("$Main.General.login$")] public ServerInfoConfig Server = new(string.Empty); [TomlInlineComment("$Main.General.server_info$")] public LoginType AccountType = LoginType.microsoft; [TomlInlineComment("$Main.General.method$")] public LoginMethod Method = LoginMethod.mcc; public enum LoginType { mojang, microsoft }; public enum LoginMethod { mcc, browser }; } [TomlDoNotInlineObject] public class AdvancedConfig { [TomlInlineComment("$Main.Advanced.language$")] public string Language = "en_us"; [TomlInlineComment("$Main.Advanced.LoadMccTrans$")] public bool LoadMccTranslation = true; // [TomlInlineComment("$Main.Advanced.console_title$")] public string ConsoleTitle = "%username%@%serverip% - Minecraft Console Client"; [TomlInlineComment("$Main.Advanced.internal_cmd_char$")] public InternalCmdCharType InternalCmdChar = InternalCmdCharType.slash; [TomlInlineComment("$Main.Advanced.message_cooldown$")] public double MessageCooldown = 1.0; [TomlInlineComment("$Main.Advanced.bot_owners$")] public List BotOwners = new() { "Player1", "Player2" }; [TomlInlineComment("$Main.Advanced.mc_version$")] public string MinecraftVersion = "auto"; [TomlInlineComment("$Main.Advanced.mc_forge$")] public ForgeConfigType EnableForge = ForgeConfigType.no; [TomlInlineComment("$Main.Advanced.brand_info$")] public BrandInfoType BrandInfo = BrandInfoType.mcc; [TomlInlineComment("$Main.Advanced.chatbot_log_file$")] public string ChatbotLogFile = ""; [TomlInlineComment("$Main.Advanced.private_msgs_cmd_name$")] public string PrivateMsgsCmdName = "tell"; [TomlInlineComment("$Main.Advanced.show_system_messages$")] public bool ShowSystemMessages = true; [TomlInlineComment("$Main.Advanced.show_xpbar_messages$")] public bool ShowXPBarMessages = true; [TomlInlineComment("$Main.Advanced.show_chat_links$")] public bool ShowChatLinks = true; [TomlInlineComment("$Main.Advanced.show_inventory_layout$")] public bool ShowInventoryLayout = true; [TomlInlineComment("$Main.Advanced.terrain_and_movements$")] public bool TerrainAndMovements = false; [TomlInlineComment("$Main.Advanced.move_head_while_walking$")] public bool MoveHeadWhileWalking = true; [TomlInlineComment("$Main.Advanced.movement_speed$")] public int MovementSpeed = 2; [TomlInlineComment("$Main.Advanced.temporary_fix_badpacket$")] public bool TemporaryFixBadpacket = false; [TomlInlineComment("$Main.Advanced.inventory_handling$")] public bool InventoryHandling = false; [TomlInlineComment("$Main.Advanced.entity_handling$")] public bool EntityHandling = false; [TomlInlineComment("$Main.Advanced.session_cache$")] public CacheType SessionCache = CacheType.disk; [TomlInlineComment("$Main.Advanced.profilekey_cache$")] public CacheType ProfileKeyCache = CacheType.disk; [TomlInlineComment("$Main.Advanced.resolve_srv_records$")] public ResolveSrvRecordType ResolveSrvRecords = ResolveSrvRecordType.fast; [TomlPrecedingComment("$Main.Advanced.account_list$")] public Dictionary AccountList = new() { { "AccountNikename1", new AccountInfoConfig("playerone@email.com", "thepassword") }, { "AccountNikename2", new AccountInfoConfig("TestBot", "-") }, }; [TomlPrecedingComment("$Main.Advanced.server_list$")] public Dictionary ServerList = new() { { "ServerAlias1", new ServerInfoConfig("mc.awesomeserver.com") }, { "ServerAlias2", new ServerInfoConfig("192.168.1.27", 12345) }, }; [TomlInlineComment("$Main.Advanced.player_head_icon$")] public bool PlayerHeadAsIcon = true; [TomlInlineComment("$Main.Advanced.exit_on_failure$")] public bool ExitOnFailure = false; [TomlInlineComment("$Main.Advanced.script_cache$")] public bool CacheScript = true; [TomlInlineComment("$Main.Advanced.timestamps$")] public bool Timestamps = false; [TomlInlineComment("$Main.Advanced.auto_respawn$")] public bool AutoRespawn = false; [TomlInlineComment("$Main.Advanced.minecraft_realms$")] public bool MinecraftRealms = false; [TomlInlineComment("$Main.Advanced.timeout$")] public int TcpTimeout = 30; [TomlInlineComment("$Main.Advanced.enable_emoji$")] public bool EnableEmoji = true; [TomlInlineComment("$Main.Advanced.MinTerminalWidth$")] public int MinTerminalWidth = 16; [TomlInlineComment("$Main.Advanced.MinTerminalHeight$")] public int MinTerminalHeight = 10; /// /// Load login/password using an account alias /// /// True if the account was found and loaded public bool SetAccount(string accountAlias) { if (AccountList.TryGetValue(accountAlias, out AccountInfoConfig accountInfo)) { InternalConfig.Account = accountInfo; return true; } else { return false; } } public enum InternalCmdCharType { none, slash, backslash }; public enum BrandInfoType { mcc, vanilla, empty }; public enum CacheType { none, memory, disk }; public enum ResolveSrvRecordType { no, fast, yes }; public enum ForgeConfigType { no, auto, force }; } public struct AccountInfoConfig { public string Login = string.Empty, Password = string.Empty; public AccountInfoConfig(string Login) { this.Login = Login; this.Password = "-"; } public AccountInfoConfig(string Login, string Password) { this.Login = Login; this.Password = Password; } } public struct ServerInfoConfig { public string Host = string.Empty; public ushort? Port = null; public ServerInfoConfig(string Host) { string[] sip = Host.Split(new[] { ":", ":" }, StringSplitOptions.None); this.Host = sip[0]; if (sip.Length > 1) { try { this.Port = Convert.ToUInt16(sip[1]); } catch (FormatException) { } } } public ServerInfoConfig(string Host, ushort Port) { this.Host = Host.Split(new[] { ":", ":" }, StringSplitOptions.None)[0]; this.Port = Port; } } } } public static class SignatureConfigHelper { public static SignatureConfig Config = new(); [TomlDoNotInlineObject] public class SignatureConfig { [TomlInlineComment("$Signature.LoginWithSecureProfile$")] public bool LoginWithSecureProfile = true; [TomlInlineComment("$Signature.SignChat$")] public bool SignChat = true; [TomlInlineComment("$Signature.SignMessageInCommand$")] public bool SignMessageInCommand = true; [TomlInlineComment("$Signature.MarkLegallySignedMsg$")] public bool MarkLegallySignedMsg = true; [TomlInlineComment("$Signature.MarkModifiedMsg$")] public bool MarkModifiedMsg = true; [TomlInlineComment("$Signature.MarkIllegallySignedMsg$")] public bool MarkIllegallySignedMsg = true; [TomlInlineComment("$Signature.MarkSystemMessage$")] public bool MarkSystemMessage = true; [TomlInlineComment("$Signature.ShowModifiedChat$")] public bool ShowModifiedChat = true; [TomlInlineComment("$Signature.ShowIllegalSignedChat$")] public bool ShowIllegalSignedChat = true; public void OnSettingUpdate() { } } } public static class LoggingConfigHealper { public static LoggingConfig Config = new(); [TomlDoNotInlineObject] public class LoggingConfig { [TomlInlineComment("$Logging.DebugMessages$")] public bool DebugMessages = false; [TomlInlineComment("$Logging.ChatMessages$")] public bool ChatMessages = true; [TomlInlineComment("$Logging.InfoMessages$")] public bool InfoMessages = true; [TomlInlineComment("$Logging.WarningMessages$")] public bool WarningMessages = true; [TomlInlineComment("$Logging.ErrorMessages$")] public bool ErrorMessages = true; [TomlInlineComment("$Logging.ChatFilter$")] public string ChatFilterRegex = @".*"; [TomlInlineComment("$Logging.DebugFilter$")] public string DebugFilterRegex = @".*"; [TomlInlineComment("$Logging.FilterMode$")] public FilterModeEnum FilterMode = FilterModeEnum.disable; [TomlInlineComment("$Logging.LogToFile$")] public bool LogToFile = false; [TomlInlineComment("$Logging.LogFile$")] public string LogFile = @"console-log.txt"; [TomlInlineComment("$Logging.PrependTimestamp$")] public bool PrependTimestamp = false; [TomlInlineComment("$Logging.SaveColorCodes$")] public bool SaveColorCodes = false; public void OnSettingUpdate() { } public enum FilterModeEnum { disable, blacklist, whitelist } } } public static class ConsoleConfigHealper { public static ConsoleConfig Config = new(); [TomlDoNotInlineObject] public class ConsoleConfig { public MainConfig General = new(); [TomlPrecedingComment("$Console.CommandSuggestion$")] public CommandSuggestionConfig CommandSuggestion = new(); public void OnSettingUpdate() { // Reader ConsoleInteractive.ConsoleReader.DisplayUesrInput = General.Display_Input; // Writer ConsoleInteractive.ConsoleWriter.EnableColor = General.ConsoleColorMode != ConsoleColorModeType.disable; ConsoleInteractive.ConsoleWriter.UseVT100ColorCode = General.ConsoleColorMode != ConsoleColorModeType.legacy_4bit; // Buffer General.History_Input_Records = ConsoleInteractive.ConsoleBuffer.SetBackreadBufferLimit(General.History_Input_Records); // Suggestion if (General.ConsoleColorMode == ConsoleColorModeType.disable) CommandSuggestion.Enable_Color = false; ConsoleInteractive.ConsoleSuggestion.EnableColor = CommandSuggestion.Enable_Color; ConsoleInteractive.ConsoleSuggestion.Enable24bitColor = General.ConsoleColorMode == ConsoleColorModeType.vt100_24bit; ConsoleInteractive.ConsoleSuggestion.UseBasicArrow = CommandSuggestion.Use_Basic_Arrow; CommandSuggestion.Max_Suggestion_Width = ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionLength(CommandSuggestion.Max_Suggestion_Width); CommandSuggestion.Max_Displayed_Suggestions = ConsoleInteractive.ConsoleSuggestion.SetMaxSuggestionCount(CommandSuggestion.Max_Displayed_Suggestions); // Suggestion color settings { if (!CheckColorCode(CommandSuggestion.Text_Color)) { ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TextColor", CommandSuggestion.Text_Color)); CommandSuggestion.Text_Color = "#f8fafc"; } if (!CheckColorCode(CommandSuggestion.Text_Background_Color)) { ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TextBackgroundColor", CommandSuggestion.Text_Background_Color)); CommandSuggestion.Text_Background_Color = "#64748b"; } if (!CheckColorCode(CommandSuggestion.Highlight_Text_Color)) { ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTextColor", CommandSuggestion.Highlight_Text_Color)); CommandSuggestion.Highlight_Text_Color = "#334155"; } if (!CheckColorCode(CommandSuggestion.Highlight_Text_Background_Color)) { ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTextBackgroundColor", CommandSuggestion.Highlight_Text_Background_Color)); CommandSuggestion.Highlight_Text_Background_Color = "#fde047"; } if (!CheckColorCode(CommandSuggestion.Tooltip_Color)) { ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.TooltipColor", CommandSuggestion.Tooltip_Color)); CommandSuggestion.Tooltip_Color = "#7dd3fc"; } if (!CheckColorCode(CommandSuggestion.Highlight_Tooltip_Color)) { ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.HighlightTooltipColor", CommandSuggestion.Highlight_Tooltip_Color)); CommandSuggestion.Highlight_Tooltip_Color = "#3b82f6"; } if (!CheckColorCode(CommandSuggestion.Arrow_Symbol_Color)) { ConsoleIO.WriteLine(string.Format(Translations.config_commandsuggestion_illegal_color, "CommandSuggestion.ArrowSymbolColor", CommandSuggestion.Arrow_Symbol_Color)); CommandSuggestion.Arrow_Symbol_Color = "#d1d5db"; } ConsoleInteractive.ConsoleSuggestion.SetColors( CommandSuggestion.Text_Color, CommandSuggestion.Text_Background_Color, CommandSuggestion.Highlight_Text_Color, CommandSuggestion.Highlight_Text_Background_Color, CommandSuggestion.Tooltip_Color, CommandSuggestion.Highlight_Tooltip_Color, CommandSuggestion.Arrow_Symbol_Color); } } private static bool CheckColorCode(string? input) { if (string.IsNullOrWhiteSpace(input)) return false; if (input.Length < 6 || input.Length > 7) return false; if (input.Length == 6 && input[0] == '#') return false; if (input.Length == 7 && input[0] != '#') return false; try { Convert.ToInt32(input.Length == 7 ? input[1..] : input, 16); return true; } catch { return false; } } [TomlDoNotInlineObject] public class MainConfig { [TomlInlineComment("$Console.General.ConsoleColorMode$")] public ConsoleColorModeType ConsoleColorMode = ConsoleColorModeType.vt100_24bit; [TomlInlineComment("$Console.General.Display_Input$")] public bool Display_Input = true; [TomlInlineComment("$Console.General.History_Input_Records$")] public int History_Input_Records = 32; } [TomlDoNotInlineObject] public class CommandSuggestionConfig { [TomlInlineComment("$Console.CommandSuggestion.Enable$")] public bool Enable = true; public bool Enable_Color = true; [TomlInlineComment("$Console.CommandSuggestion.Use_Basic_Arrow$")] public bool Use_Basic_Arrow = false; public int Max_Suggestion_Width = 30; public int Max_Displayed_Suggestions = 6; public string Text_Color = "#f8fafc"; public string Text_Background_Color = "#64748b"; public string Highlight_Text_Color = "#334155"; public string Highlight_Text_Background_Color = "#fde047"; public string Tooltip_Color = "#7dd3fc"; public string Highlight_Tooltip_Color = "#3b82f6"; public string Arrow_Symbol_Color = "#d1d5db"; } public enum ConsoleColorModeType { disable, legacy_4bit, vt100_4bit, vt100_8bit, vt100_24bit }; } } public static class AppVarConfigHelper { public static AppVarConfig Config = new(); [TomlDoNotInlineObject] public class AppVarConfig { [TomlPrecedingComment("$AppVars.Variables$")] private readonly Dictionary VarStirng = new() { { "your_var", "your_value" }, { "your var 2", "your value 2" }, }; public void OnSettingUpdate() { } [NonSerialized] private readonly Dictionary VarObject = new(); [NonSerialized] readonly object varLock = new(); /// /// Set a custom %variable% which will be available through expandVars() /// /// Name of the variable /// Value of the variable /// True if the parameters were valid public bool SetVar(string varName, object varData) { varName = Settings.ToLowerIfNeed(new string(varName.TakeWhile(char.IsLetterOrDigit).ToArray())); if (varName.Length > 0) { bool isString = varData.GetType() == typeof(string); lock (varLock) { if (isString) { if (VarObject.ContainsKey(varName)) VarObject.Remove(varName); VarStirng[varName] = (string)varData; } else { if (VarStirng.ContainsKey(varName)) VarStirng.Remove(varName); VarObject[varName] = varData; } } return true; } else { return false; } } /// /// Get a custom %variable% or null if the variable does not exist /// /// Variable name /// The value or null if the variable does not exists public object? GetVar(string varName) { if (VarStirng.TryGetValue(varName, out string? valueString)) return valueString; else if (VarObject.TryGetValue(varName, out object? valueObject)) return valueObject; else return null; } /// /// Get a custom %variable% or null if the variable does not exist /// /// Variable name /// The value or null if the variable does not exists public bool TryGetVar(string varName, [NotNullWhen(true)] out object? varData) { if (VarStirng.TryGetValue(varName, out string? valueString)) { varData = valueString; return true; } else if (VarObject.TryGetValue(varName, out object? valueObject)) { varData = valueObject; return true; } else { varData = null; return false; } } /// /// Get a dictionary containing variables (names and value) /// /// A IDictionary containing a name and a vlaue key pairs of variables public Dictionary GetVariables() { Dictionary res = new(VarObject); foreach ((string varName, string varData) in VarStirng) res.Add(varName, varData); return res; } /// /// Replace %variables% with their value from global AppVars /// /// String to parse /// Optional local variables overriding global variables /// Modifier string public string ExpandVars(string str, Dictionary? localVars = null) { StringBuilder result = new(); for (int i = 0; i < str.Length; i++) { if (str[i] == '%') { bool varname_ok = false; StringBuilder var_name = new(); for (int j = i + 1; j < str.Length; j++) { if (!char.IsLetterOrDigit(str[j]) && str[j] != '_') { if (str[j] == '%') varname_ok = var_name.Length > 0; break; } else var_name.Append(str[j]); } if (varname_ok) { string varname = var_name.ToString(); string varname_lower = Settings.ToLowerIfNeed(varname); i = i + varname.Length + 1; switch (varname_lower) { case "username": result.Append(InternalConfig.Username); break; case "login": result.Append(InternalConfig.Account.Login); break; case "serverip": result.Append(InternalConfig.ServerIP); break; case "serverport": result.Append(InternalConfig.ServerPort); break; case "datetime": DateTime time = DateTime.Now; result.Append(String.Format("{0}-{1}-{2} {3}:{4}:{5}", time.Year.ToString("0000"), time.Month.ToString("00"), time.Day.ToString("00"), time.Hour.ToString("00"), time.Minute.ToString("00"), time.Second.ToString("00"))); break; default: if (localVars != null && localVars.ContainsKey(varname_lower)) result.Append(localVars[varname_lower].ToString()); else if (TryGetVar(varname_lower, out object? var_value)) result.Append(var_value.ToString()); else result.Append("%" + varname + '%'); break; } } else result.Append(str[i]); } else result.Append(str[i]); } return result.ToString(); } } } public static class MCSettingsConfigHealper { public static MCSettingsConfig Config = new(); [TomlDoNotInlineObject] public class MCSettingsConfig { [TomlInlineComment("$MCSettings.Enabled$")] public bool Enabled = true; [TomlInlineComment("$MCSettings.Locale$")] public string Locale = "en_US"; [TomlInlineComment("$MCSettings.RenderDistance$")] public byte RenderDistance = 8; [TomlInlineComment("$MCSettings.Difficulty$")] public DifficultyType Difficulty = DifficultyType.peaceful; [TomlInlineComment("$MCSettings.ChatMode$")] public ChatModeType ChatMode = ChatModeType.enabled; [TomlInlineComment("$MCSettings.ChatColors$")] public bool ChatColors = true; [TomlInlineComment("$MCSettings.MainHand$")] public MainHandType MainHand = MainHandType.left; public SkinInfo Skin = new(); public void OnSettingUpdate() { } public enum DifficultyType { peaceful, easy, normal, difficult }; public enum ChatModeType { enabled, commands, disabled }; public enum MainHandType { left, right }; public struct SkinInfo { public bool Cape = true, Hat = true, Jacket = false; public bool Sleeve_Left = false, Sleeve_Right = false; public bool Pants_Left = false, Pants_Right = false; public SkinInfo() { } public SkinInfo(bool Cape, bool Hat, bool Jacket, bool Sleeve_Left, bool Sleeve_Right, bool Pants_Left, bool Pants_Right) { this.Cape = Cape; this.Hat = Hat; this.Jacket = Jacket; this.Sleeve_Left = Sleeve_Left; this.Sleeve_Right = Sleeve_Right; this.Pants_Left = Pants_Left; this.Pants_Right = Pants_Right; } public byte GetByte() { return (byte)( ((Cape ? 1 : 0) << 0) | ((Jacket ? 1 : 0) << 1) | ((Sleeve_Left ? 1 : 0) << 2) | ((Sleeve_Right ? 1 : 0) << 3) | ((Pants_Left ? 1 : 0) << 4) | ((Pants_Right ? 1 : 0) << 5) | ((Hat ? 1 : 0) << 6) ); } } } } public static class ChatFormatConfigHelper { public static ChatFormatConfig Config = new(); [TomlDoNotInlineObject] public class ChatFormatConfig { [TomlInlineComment("$ChatFormat.Builtins$")] public bool Builtins = true; [TomlInlineComment("$ChatFormat.UserDefined$")] public bool UserDefined = false; public string Public = @"^<([a-zA-Z0-9_]+)> (.+)$"; public string Private = @"^([a-zA-Z0-9_]+) whispers to you: (.+)$"; public string TeleportRequest = @"^([a-zA-Z0-9_]+) has requested (?:to|that you) teleport to (?:you|them)\.$"; public void OnSettingUpdate() { if (UserDefined) { bool checkResult = true; try { _ = new Regex(Public); } catch (ArgumentException) { checkResult = false; ConsoleIO.WriteLineFormatted("§c[Settings]Illegal regular expression: ChatFormat.Public = " + Public); } try { _ = new Regex(Private); } catch (ArgumentException) { checkResult = false; ConsoleIO.WriteLineFormatted("§c[Settings]Illegal regular expression: ChatFormat.Private = " + Private); } try { _ = new Regex(TeleportRequest); } catch (ArgumentException) { checkResult = false; ConsoleIO.WriteLineFormatted("§c[Settings]Illegal regular expression: ChatFormat.TeleportRequest = " + TeleportRequest); } if (!checkResult) { UserDefined = false; ConsoleIO.WriteLineFormatted("§c[Settings]ChatFormat: User-defined regular expressions are disabled."); } } } } } public static class ChatBotConfigHealper { public static ChatBotConfig Config = new(); [TomlDoNotInlineObject] public class ChatBotConfig { [TomlPrecedingComment("$ChatBot.Alerts$")] public ChatBots.Alerts.Configs Alerts { get { return ChatBots.Alerts.Config; } set { ChatBots.Alerts.Config = value; ChatBots.Alerts.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AntiAfk$")] public ChatBots.AntiAFK.Configs AntiAFK { get { return ChatBots.AntiAFK.Config; } set { ChatBots.AntiAFK.Config = value; ChatBots.AntiAFK.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoAttack$")] public ChatBots.AutoAttack.Configs AutoAttack { get { return ChatBots.AutoAttack.Config; } set { ChatBots.AutoAttack.Config = value; ChatBots.AutoAttack.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoCraft$")] public ChatBots.AutoCraft.Configs AutoCraft { get { return ChatBots.AutoCraft.Config; } set { ChatBots.AutoCraft.Config = value; ChatBots.AutoCraft.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoDig$")] public ChatBots.AutoDig.Configs AutoDig { get { return ChatBots.AutoDig.Config; } set { ChatBots.AutoDig.Config = value; ChatBots.AutoDig.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoDrop$")] public ChatBots.AutoDrop.Configs AutoDrop { get { return ChatBots.AutoDrop.Config; } set { ChatBots.AutoDrop.Config = value; ChatBots.AutoDrop.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoEat$")] public ChatBots.AutoEat.Configs AutoEat { get { return ChatBots.AutoEat.Config; } set { ChatBots.AutoEat.Config = value; ChatBots.AutoEat.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoFishing$")] public ChatBots.AutoFishing.Configs AutoFishing { get { return ChatBots.AutoFishing.Config; } set { ChatBots.AutoFishing.Config = value; ChatBots.AutoFishing.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoRelog$")] public ChatBots.AutoRelog.Configs AutoRelog { get { return ChatBots.AutoRelog.Config; } set { ChatBots.AutoRelog.Config = value; ChatBots.AutoRelog.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.AutoRespond$")] public ChatBots.AutoRespond.Configs AutoRespond { get { return ChatBots.AutoRespond.Config; } set { ChatBots.AutoRespond.Config = value; ChatBots.AutoRespond.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.ChatLog$")] public ChatBots.ChatLog.Configs ChatLog { get { return ChatBots.ChatLog.Config; } set { ChatBots.ChatLog.Config = value; ChatBots.ChatLog.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.DiscordBridge$")] public ChatBots.DiscordBridge.Configs DiscordBridge { get { return ChatBots.DiscordBridge.Config; } set { ChatBots.DiscordBridge.Config = value; ChatBots.DiscordBridge.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.Farmer$")] public ChatBots.Farmer.Configs Farmer { get { return ChatBots.Farmer.Config; } set { ChatBots.Farmer.Config = value; ChatBots.Farmer.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.FollowPlayer$")] public ChatBots.FollowPlayer.Configs FollowPlayer { get { return ChatBots.FollowPlayer.Config; } set { ChatBots.FollowPlayer.Config = value; ChatBots.FollowPlayer.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.HangmanGame$")] public ChatBots.HangmanGame.Configs HangmanGame { get { return ChatBots.HangmanGame.Config; } set { ChatBots.HangmanGame.Config = value; ChatBots.HangmanGame.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.Mailer$")] public ChatBots.Mailer.Configs Mailer { get { return ChatBots.Mailer.Config; } set { ChatBots.Mailer.Config = value; ChatBots.Mailer.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.Map$")] public ChatBots.Map.Configs Map { get { return ChatBots.Map.Config; } set { ChatBots.Map.Config = value; ChatBots.Map.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.PlayerListLogger$")] public ChatBots.PlayerListLogger.Configs PlayerListLogger { get { return ChatBots.PlayerListLogger.Config; } set { ChatBots.PlayerListLogger.Config = value; ChatBots.PlayerListLogger.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.RemoteControl$")] public ChatBots.RemoteControl.Configs RemoteControl { get { return ChatBots.RemoteControl.Config; } set { ChatBots.RemoteControl.Config = value; ChatBots.RemoteControl.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.ReplayCapture$")] public ChatBots.ReplayCapture.Configs ReplayCapture { get { return ChatBots.ReplayCapture.Config; } set { ChatBots.ReplayCapture.Config = value; ChatBots.ReplayCapture.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.ScriptScheduler$")] public ChatBots.ScriptScheduler.Configs ScriptScheduler { get { return ChatBots.ScriptScheduler.Config; } set { ChatBots.ScriptScheduler.Config = value; ChatBots.ScriptScheduler.Config.OnSettingUpdate(); } } [TomlPrecedingComment("$ChatBot.TelegramBridge$")] public ChatBots.TelegramBridge.Configs TelegramBridge { get { return ChatBots.TelegramBridge.Config; } set { ChatBots.TelegramBridge.Config = value; ChatBots.TelegramBridge.Config.OnSettingUpdate(); } } } } public static string GetDefaultGameLanguage() { string gameLanguage = "en_us"; string systemLanguage = string.IsNullOrWhiteSpace(Program.ActualCulture.Name) ? Program.ActualCulture.Parent.Name : Program.ActualCulture.Name; switch (systemLanguage) { case "af": case "af-ZA": gameLanguage = "af_za"; break; case "ar": case "ar-AE": case "ar-BH": case "ar-DZ": case "ar-EG": case "ar-IQ": case "ar-JO": case "ar-KW": case "ar-LB": case "ar-LY": case "ar-MA": case "ar-OM": case "ar-QA": case "ar-SA": case "ar-SY": case "ar-TN": case "ar-YE": gameLanguage = "ar_sa"; break; case "az": case "az-Cyrl-AZ": case "az-Latn-AZ": gameLanguage = "az_az"; break; case "be": case "be-BY": gameLanguage = "be_by"; break; case "bg": case "bg-BG": gameLanguage = "bg_bg"; break; case "bs-Latn-BA": gameLanguage = "bs_ba"; break; case "ca": case "ca-ES": gameLanguage = "ca_es"; break; case "cs": case "cs-CZ": gameLanguage = "cs_cz"; break; case "cy-GB": gameLanguage = "cy_gb"; break; case "da": case "da-DK": gameLanguage = "da_dk"; break; case "de": case "de-DE": case "de-LI": case "de-LU": gameLanguage = "de_de"; break; case "de-AT": gameLanguage = "de_at"; break; case "de-CH": gameLanguage = "de_ch"; break; case "dv": case "dv-MV": break; case "el": case "el-GR": gameLanguage = "el_gr"; break; case "en": case "en-029": case "en-BZ": case "en-IE": case "en-JM": case "en-PH": case "en-TT": case "en-ZA": case "en-ZW": case "en-US": gameLanguage = "en_us"; break; case "en-GB": gameLanguage = "en_gb"; break; case "en-AU": gameLanguage = "en_au"; break; case "en-CA": gameLanguage = "en_ca"; break; case "en-NZ": gameLanguage = "en_nz"; break; case "es": case "es-BO": case "es-CO": case "es-CR": case "es-DO": case "es-ES": case "es-GT": case "es-HN": case "es-NI": case "es-PA": case "es-PE": case "es-PR": case "es-PY": case "es-SV": gameLanguage = "es_es"; break; case "es-AR": gameLanguage = "es_ar"; break; case "es-CL": gameLanguage = "es_cl"; break; case "es-EC": gameLanguage = "es_ec"; break; case "es-MX": gameLanguage = "es_mx"; break; case "es-UY": gameLanguage = "es_uy"; break; case "es-VE": gameLanguage = "es_ve"; break; case "et": case "et-EE": gameLanguage = "et_ee"; break; case "eu": case "eu-ES": gameLanguage = "eu_es"; break; case "fa": case "fa-IR": gameLanguage = "fa_ir"; break; case "fi": case "fi-FI": gameLanguage = "fi_fi"; break; case "fo": case "fo-FO": gameLanguage = "fo_fo"; break; case "fr": case "fr-BE": case "fr-FR": case "fr-CH": case "fr-LU": case "fr-MC": gameLanguage = "fr_fr"; break; case "fr-CA": gameLanguage = "fr_ca"; break; case "gl": case "gl-ES": gameLanguage = "gl_es"; break; case "gu": case "gu-IN": break; case "he": case "he-IL": gameLanguage = "he_il"; break; case "hi": case "hi-IN": gameLanguage = "hi_in"; break; case "hr": case "hr-BA": case "hr-HR": gameLanguage = "hr_hr"; break; case "hu": case "hu-HU": gameLanguage = "hu_hu"; break; case "hy": case "hy-AM": gameLanguage = "hy_am"; break; case "id": case "id-ID": gameLanguage = "id_id"; break; case "is": case "is-IS": gameLanguage = "is_is"; break; case "it": case "it-CH": case "it-IT": gameLanguage = "it_it"; break; case "ja": case "ja-JP": gameLanguage = "ja_jp"; break; case "ka": case "ka-GE": gameLanguage = "ka_ge"; break; case "kk": case "kk-KZ": gameLanguage = "kk_kz"; break; case "kn": case "kn-IN": gameLanguage = "kn_in"; break; case "kok": case "kok-IN": break; case "ko": case "ko-KR": gameLanguage = "ko_kr"; break; case "ky": case "ky-KG": break; case "lt": case "lt-LT": gameLanguage = "lt_lt"; break; case "lv": case "lv-LV": gameLanguage = "lv_lv"; break; case "mi-NZ": break; case "mk": case "mk-MK": gameLanguage = "mk_mk"; break; case "mn": case "mn-MN": gameLanguage = "mn_mn"; break; case "mr": case "mr-IN": break; case "ms": case "ms-BN": case "ms-MY": gameLanguage = "ms_my"; break; case "mt-MT": gameLanguage = "mt_mt"; break; case "nb-NO": break; case "nl": case "nl-NL": gameLanguage = "nl_nl"; break; case "nl-BE": gameLanguage = "nl_be"; break; case "nn-NO": gameLanguage = "nn_no"; break; case "no": gameLanguage = "no_no‌"; break; case "ns-ZA": break; case "pa": case "pa-IN": break; case "pl": case "pl-PL": gameLanguage = "pl_pl‌"; break; case "pt": case "pt-PT": gameLanguage = "pt_pt‌"; break; case "pt-BR": gameLanguage = "pt_br‌"; break; case "quz-BO": break; case "quz-EC": break; case "quz-PE": break; case "ro": case "ro-RO": gameLanguage = "ro_ro‌"; break; case "ru": case "ru-RU": gameLanguage = "ru_ru"; break; case "sa": case "sa-IN": break; case "se-FI": case "se-NO": case "se-SE": gameLanguage = "se_no"; break; case "sk": case "sk-SK": gameLanguage = "sk_sk"; break; case "sl": case "sl-SI": gameLanguage = "sl_si"; break; case "sma-NO": break; case "sma-SE": break; case "smj-NO": break; case "smj-SE": break; case "smn-FI": break; case "sms-FI": break; case "sq": case "sq-AL": gameLanguage = "sq_al"; break; case "sr": case "sr-Cyrl-BA": case "sr-Cyrl-CS": case "sr-Latn-BA": case "sr-Latn-CS": gameLanguage = "sr_sp"; break; case "sv": case "sv-FI": case "sv-SE": gameLanguage = "sv_se"; break; case "sw": case "sw-KE": break; case "syr": case "syr-SY": break; case "ta": case "ta-IN": gameLanguage = "ta_in"; break; case "te": case "te-IN": break; case "th": case "th-TH": gameLanguage = "th_th"; break; case "tn-ZA": break; case "tr": case "tr-TR": gameLanguage = "tr_tr"; break; case "tt": case "tt-RU": gameLanguage = "tt_ru"; break; case "uk": case "uk-UA": gameLanguage = "uk_ua"; break; case "ur": case "ur-PK": break; case "uz": case "uz-Cyrl-UZ": case "uz-Latn-UZ": break; case "vi": case "vi-VN": gameLanguage = "vi_vn"; break; case "xh-ZA": break; case "zh-Hans": /* CurrentCulture.Parent.Name */ case "zh": case "zh-CN": case "zh-CHS": case "zh-SG": gameLanguage = "zh_cn"; break; case "zh-Hant": /* CurrentCulture.Parent.Name */ case "zh-HK": case "zh-CHT": case "zh-MO": gameLanguage = "zh_hk"; break; case "zh-TW": gameLanguage = "zh_tw"; break; case "zu-ZA": break; } return gameLanguage; } [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)] public static string ToLowerIfNeed(string str) { const string lookupStringL = "---------------------------------!-#$%&-()*+,-./0123456789:;<=>?@abcdefghijklmnopqrstuvwxyz[-]^_`abcdefghijklmnopqrstuvwxyz{|}~-"; bool needLower = false; foreach (Char c in str) { if (Char.IsUpper(c)) { needLower = true; break; } } if (needLower) { StringBuilder sb = new(str); for (int i = 0; i < str.Length; ++i) if (char.IsUpper(sb[i])) sb[i] = lookupStringL[sb[i]]; return sb.ToString(); } else { return str; } } public static int DoubleToTick(double time) { time = Math.Min(int.MaxValue / 10, time); return (int)Math.Round(time * 10); } } public static class InternalCmdCharTypeExtensions { public static char ToChar(this InternalCmdCharType type) { return type switch { InternalCmdCharType.none => ' ', InternalCmdCharType.slash => '/', InternalCmdCharType.backslash => '\\', _ => '/', }; } public static string ToLogString(this InternalCmdCharType type) { return type switch { InternalCmdCharType.none => string.Empty, InternalCmdCharType.slash => @"/", InternalCmdCharType.backslash => @"\", _ => @"/", }; } } public static class BrandInfoTypeExtensions { public static string? ToBrandString(this BrandInfoType info) { return info switch { BrandInfoType.mcc => "Minecraft-Console-Client/" + Program.Version, BrandInfoType.vanilla => "vanilla", BrandInfoType.empty => null, _ => null, }; } } public static class ExceptionExtensions { public static string GetFullMessage(this Exception ex) { string msg = ex.Message.Replace("+", "->"); return ex.InnerException == null ? msg : msg + "\n --> " + ex.InnerException.GetFullMessage(); } } }