From c2efe55058a9ebeef6ea9a55e75379666d779fcb Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Wed, 20 Dec 2023 18:45:36 +1100 Subject: [PATCH] Start moving towards invariant integer number parsing It turns out that some languages use a unicode character such as \u2212 for the negative sign --- .../Bots/Instructions/MoveInstructions.cs | 9 +-- MCGalaxy/Commands/CPE/CustomBlockCommand.cs | 2 +- MCGalaxy/Commands/Command.Helpers.cs | 2 +- MCGalaxy/Commands/CommandParser.cs | 8 +-- MCGalaxy/Commands/Information/CmdRankInfo.cs | 7 +- MCGalaxy/Commands/Moderation/ModActionCmd.cs | 2 +- MCGalaxy/Commands/World/CmdPause.cs | 2 +- MCGalaxy/Commands/building/CmdCalculate.cs | 4 +- MCGalaxy/Commands/building/CmdSpin.cs | 2 +- MCGalaxy/Commands/building/CmdTree.cs | 2 +- MCGalaxy/Config/NumberAttributes.cs | 8 +-- .../Config/Permissions/CommandExtraPerms.cs | 4 +- MCGalaxy/Config/Permissions/ItemPerms.cs | 4 +- MCGalaxy/Database/Database.cs | 9 ++- MCGalaxy/Database/PlayerData.cs | 2 +- MCGalaxy/Economy/Economy.DB.cs | 2 +- MCGalaxy/Economy/Item.cs | 2 +- MCGalaxy/Economy/RankItem.cs | 2 +- MCGalaxy/Entity/ModelInfo.cs | 2 +- MCGalaxy/Generator/MapGen.cs | 5 +- MCGalaxy/Levels/Hacks.cs | 2 +- MCGalaxy/Levels/LevelEnv.cs | 2 +- MCGalaxy/Levels/LevelInfo.cs | 2 +- MCGalaxy/Levels/LevelOperations.cs | 2 +- MCGalaxy/MCGalaxy_.csproj | 1 + .../Modules/Compiling/CompilerBackends.cs | 4 +- .../Modules/Relay/Discord/DiscordApiClient.cs | 4 +- .../Modules/Relay/Discord/DiscordWebsocket.cs | 8 +-- MCGalaxy/Modules/Warps/Warp.cs | 6 +- MCGalaxy/Player/Ban.cs | 9 ++- MCGalaxy/Player/Player.Login.cs | 6 +- MCGalaxy/Server/Tasks/UpgradeTasks.cs | 13 ++-- MCGalaxy/util/Formatting/Paginator.cs | 2 +- MCGalaxy/util/NumberUtils.cs | 65 +++++++++++++++++++ MCGalaxy/util/UIHelpers.cs | 6 +- MCGalaxy/util/Utils.cs | 36 ++-------- 36 files changed, 151 insertions(+), 97 deletions(-) create mode 100644 MCGalaxy/util/NumberUtils.cs diff --git a/MCGalaxy/Bots/Instructions/MoveInstructions.cs b/MCGalaxy/Bots/Instructions/MoveInstructions.cs index 260a75b67..aca290f27 100644 --- a/MCGalaxy/Bots/Instructions/MoveInstructions.cs +++ b/MCGalaxy/Bots/Instructions/MoveInstructions.cs @@ -36,9 +36,9 @@ namespace MCGalaxy.Bots public override InstructionData Parse(string[] args) { Coords coords; - coords.X = int.Parse(args[1]); - coords.Y = int.Parse(args[2]); - coords.Z = int.Parse(args[3]); + coords.X = NumberUtils.ParseInt32(args[1]); + coords.Y = NumberUtils.ParseInt32(args[2]); + coords.Z = NumberUtils.ParseInt32(args[3]); coords.RotX = byte.Parse(args[4]); coords.RotY = byte.Parse(args[5]); @@ -51,7 +51,8 @@ namespace MCGalaxy.Bots w.WriteLine(Name + " " + p.Pos.X + " " + p.Pos.Y + " " + p.Pos.Z + " " + p.Rot.RotY + " " + p.Rot.HeadX); } - protected struct Coords { + protected struct Coords + { public int X, Y, Z; public byte RotX, RotY; } diff --git a/MCGalaxy/Commands/CPE/CustomBlockCommand.cs b/MCGalaxy/Commands/CPE/CustomBlockCommand.cs index 74e27a814..dc2207a01 100644 --- a/MCGalaxy/Commands/CPE/CustomBlockCommand.cs +++ b/MCGalaxy/Commands/CPE/CustomBlockCommand.cs @@ -692,7 +692,7 @@ namespace MCGalaxy.Commands.CPE int max = Block.MaxRaw; // Check for block names (can't use standard parsing behaviour) - if (!int.TryParse(arg, out raw)) { + if (!NumberUtils.TryParseInt32(arg, out raw)) { BlockDefinition def = BlockDefinition.ParseName(arg, args.defs); if (def == null) { diff --git a/MCGalaxy/Commands/Command.Helpers.cs b/MCGalaxy/Commands/Command.Helpers.cs index b262f87e8..9630ad6af 100644 --- a/MCGalaxy/Commands/Command.Helpers.cs +++ b/MCGalaxy/Commands/Command.Helpers.cs @@ -81,7 +81,7 @@ namespace MCGalaxy protected static bool IsListModifier(string str) { int ignored; - return str.CaselessEq("all") || int.TryParse(str, out ignored); + return str.CaselessEq("all") || NumberUtils.TryParseInt32(str, out ignored); } public static bool IsCreateAction(string str) { diff --git a/MCGalaxy/Commands/CommandParser.cs b/MCGalaxy/Commands/CommandParser.cs index 782bb1cf2..97fcb1a62 100644 --- a/MCGalaxy/Commands/CommandParser.cs +++ b/MCGalaxy/Commands/CommandParser.cs @@ -98,7 +98,7 @@ namespace MCGalaxy.Commands public static bool GetInt(Player p, string input, string argName, ref int result, int min = int.MinValue, int max = int.MaxValue) { int value; - if (!int.TryParse(input, out value)) { + if (!NumberUtils.TryParseInt32(input, out value)) { p.Message("&W\"{0}\" is not a valid integer.", input); return false; } @@ -110,7 +110,7 @@ namespace MCGalaxy.Commands public static bool GetReal(Player p, string input, string argName, ref float result, float min = float.NegativeInfinity, float max = float.MaxValue) { float value; - if (!Utils.TryParseSingle(input, out value)) { + if (!NumberUtils.TryParseSingle(input, out value)) { p.Message("&W\"{0}\" is not a valid number.", input); return false; } @@ -268,8 +268,8 @@ namespace MCGalaxy.Commands bits = input.Split(new char[] { '-' }, 2); int tmp; - return int.TryParse(bits[0], out tmp) - && int.TryParse(bits[1], out tmp); + return NumberUtils.TryParseInt32(bits[0], out tmp) + && NumberUtils.TryParseInt32(bits[1], out tmp); } } } diff --git a/MCGalaxy/Commands/Information/CmdRankInfo.cs b/MCGalaxy/Commands/Information/CmdRankInfo.cs index ad7153ab6..0d32cda47 100644 --- a/MCGalaxy/Commands/Information/CmdRankInfo.cs +++ b/MCGalaxy/Commands/Information/CmdRankInfo.cs @@ -57,8 +57,11 @@ namespace MCGalaxy.Commands.Info offset = 5; } else { // Backwards compatibility with old format - int min = int.Parse(args[2]), hour = int.Parse(args[3]); - int day = int.Parse(args[4]), month = int.Parse(args[5]), year = int.Parse(args[6]); + int min = NumberUtils.ParseInt32(args[2]); + int hour = NumberUtils.ParseInt32(args[3]); + int day = NumberUtils.ParseInt32(args[4]); + int month = NumberUtils.ParseInt32(args[5]); + int year = NumberUtils.ParseInt32(args[6]); delta = DateTime.Now - new DateTime(year, month, day, hour, min, 0); newRank = args[7]; oldRank = args[8]; diff --git a/MCGalaxy/Commands/Moderation/ModActionCmd.cs b/MCGalaxy/Commands/Moderation/ModActionCmd.cs index 595a2e6e8..44251de6f 100644 --- a/MCGalaxy/Commands/Moderation/ModActionCmd.cs +++ b/MCGalaxy/Commands/Moderation/ModActionCmd.cs @@ -45,7 +45,7 @@ namespace MCGalaxy.Commands.Moderation { if (reason.Length == 0 || reason[0] != '@') return reason; reason = reason.Substring(1); - if (!int.TryParse(reason, out ruleNum)) return "@" + reason; + if (!NumberUtils.TryParseInt32(reason, out ruleNum)) return "@" + reason; // Treat @num as a shortcut for rule #num Dictionary sections = GetRuleSections(); diff --git a/MCGalaxy/Commands/World/CmdPause.cs b/MCGalaxy/Commands/World/CmdPause.cs index 6e1db89b5..4c16c870e 100644 --- a/MCGalaxy/Commands/World/CmdPause.cs +++ b/MCGalaxy/Commands/World/CmdPause.cs @@ -31,7 +31,7 @@ namespace MCGalaxy.Commands.World { if (message.Length > 0) { string[] parts = message.SplitSpaces(); if (parts.Length == 1) { - if (!int.TryParse(parts[0], out seconds)) { + if (!NumberUtils.TryParseInt32(parts[0], out seconds)) { seconds = 30; lvl = Matcher.FindLevels(p, parts[0]); if (lvl == null) return; diff --git a/MCGalaxy/Commands/building/CmdCalculate.cs b/MCGalaxy/Commands/building/CmdCalculate.cs index 05b6245d3..d835beb13 100644 --- a/MCGalaxy/Commands/building/CmdCalculate.cs +++ b/MCGalaxy/Commands/building/CmdCalculate.cs @@ -32,7 +32,7 @@ namespace MCGalaxy.Commands.Building double n1 = 0, n2 = 0, result = 0; string r1 = args[0], op = args[1], r2 = null, format = null; - if (!Utils.TryParseDouble(r1, out n1)) { + if (!NumberUtils.TryParseDouble(r1, out n1)) { p.Message("&W\"{0}\" is not a valid number.", r1); return; } @@ -41,7 +41,7 @@ namespace MCGalaxy.Commands.Building if (args.Length == 2 ||op.Length > 1) { Help(p); return; } r2 = args[2]; - if (!Utils.TryParseDouble(r2, out n2)) { + if (!NumberUtils.TryParseDouble(r2, out n2)) { p.Message("&W\"{0}\" is not a valid number.", r2); return; } diff --git a/MCGalaxy/Commands/building/CmdSpin.cs b/MCGalaxy/Commands/building/CmdSpin.cs index df62a8244..d6cabce53 100644 --- a/MCGalaxy/Commands/building/CmdSpin.cs +++ b/MCGalaxy/Commands/building/CmdSpin.cs @@ -69,7 +69,7 @@ namespace MCGalaxy.Commands.Building { int value; if (arg == "x" || arg == "y" || arg == "z") { axis = char.ToUpper(arg[0]); return true; - } else if (int.TryParse(arg, out value)) { + } else if (NumberUtils.TryParseInt32(arg, out value)) { // Clamp to [0, 360) value %= 360; if (value < 0) value += 360; diff --git a/MCGalaxy/Commands/building/CmdTree.cs b/MCGalaxy/Commands/building/CmdTree.cs index 7d053c348..7871b6c9e 100644 --- a/MCGalaxy/Commands/building/CmdTree.cs +++ b/MCGalaxy/Commands/building/CmdTree.cs @@ -34,7 +34,7 @@ namespace MCGalaxy.Commands.Building { if (tree == null) tree = new NormalTree(); int size; - if (args.Length > 1 && int.TryParse(args[1], out size)) { + if (args.Length > 1 && NumberUtils.TryParseInt32(args[1], out size)) { Player p = dArgs.Player; string opt = args[0] + " tree size"; if (!CommandParser.GetInt(p, args[1], opt, ref size, tree.MinSize, tree.MaxSize)) return null; diff --git a/MCGalaxy/Config/NumberAttributes.cs b/MCGalaxy/Config/NumberAttributes.cs index af064eb83..f0bfe8c8d 100644 --- a/MCGalaxy/Config/NumberAttributes.cs +++ b/MCGalaxy/Config/NumberAttributes.cs @@ -28,7 +28,7 @@ namespace MCGalaxy.Config // separate function to avoid boxing in derived classes protected int ParseInteger(string raw, int def, int min, int max) { int value; - if (!int.TryParse(raw, out value)) { + if (!NumberUtils.TryParseInt32(raw, out value)) { Logger.Log(LogType.Warning, "Config key \"{0}\" has invalid integer '{2}', using default of {1}", Name, def, raw); value = def; } @@ -101,7 +101,7 @@ namespace MCGalaxy.Config protected double ParseReal(string raw, double def, double min, double max) { double value; - if (!Utils.TryParseDouble(raw, out value)) { + if (!NumberUtils.TryParseDouble(raw, out value)) { Logger.Log(LogType.Warning, "Config key \"{0}\" has invalid number '{2}', using default of {1}", Name, def, raw); value = def; } @@ -118,8 +118,8 @@ namespace MCGalaxy.Config } public override string Serialise(object value) { - if (value is float) return Utils.StringifyDouble((float)value); - if (value is double) return Utils.StringifyDouble((double)value); + if (value is float) return NumberUtils.StringifyDouble((float)value); + if (value is double) return NumberUtils.StringifyDouble((double)value); return base.Serialise(value); } } diff --git a/MCGalaxy/Config/Permissions/CommandExtraPerms.cs b/MCGalaxy/Config/Permissions/CommandExtraPerms.cs index 15e228753..273b19efc 100644 --- a/MCGalaxy/Config/Permissions/CommandExtraPerms.cs +++ b/MCGalaxy/Config/Permissions/CommandExtraPerms.cs @@ -124,13 +124,13 @@ namespace MCGalaxy.Commands // Old format - Name:Num : Lowest : Description if (IsDescription(args[3])) { - min = (LevelPermission)int.Parse(args[2]); + min = (LevelPermission)NumberUtils.ParseInt32(args[2]); allowed = null; disallowed = null; } else { Deserialise(args, 2, out min, out allowed, out disallowed); } - perms = GetOrAdd(args[0], int.Parse(args[1]), min); + perms = GetOrAdd(args[0], NumberUtils.ParseInt32(args[1]), min); perms.Init(min, allowed, disallowed); } catch (Exception ex) { Logger.Log(LogType.Warning, "Hit an error on the extra command perms " + line); diff --git a/MCGalaxy/Config/Permissions/ItemPerms.cs b/MCGalaxy/Config/Permissions/ItemPerms.cs index 2fb521d23..808ec14fc 100644 --- a/MCGalaxy/Config/Permissions/ItemPerms.cs +++ b/MCGalaxy/Config/Permissions/ItemPerms.cs @@ -128,7 +128,7 @@ namespace MCGalaxy protected static void Deserialise(string[] args, int idx, out LevelPermission min, out List allowed, out List disallowed) { - min = (LevelPermission)int.Parse(args[idx]); + min = (LevelPermission)NumberUtils.ParseInt32(args[idx]); disallowed = ExpandPerms(args[idx + 1]); allowed = ExpandPerms(args[idx + 2]); } @@ -139,7 +139,7 @@ namespace MCGalaxy List perms = new List(); foreach (string perm in input.SplitComma()) { - perms.Add((LevelPermission)int.Parse(perm)); + perms.Add((LevelPermission)NumberUtils.ParseInt32(perm)); } return perms; } diff --git a/MCGalaxy/Database/Database.cs b/MCGalaxy/Database/Database.cs index 368dd9085..f6d3b0f6c 100644 --- a/MCGalaxy/Database/Database.cs +++ b/MCGalaxy/Database/Database.cs @@ -234,8 +234,13 @@ namespace MCGalaxy.SQL internal static TimeSpan ParseOldDBTimeSpent(string value) { string[] parts = value.SplitSpaces(); - return new TimeSpan(int.Parse(parts[0]), int.Parse(parts[1]), - int.Parse(parts[2]), int.Parse(parts[3])); + + int days = NumberUtils.ParseInt32(parts[0]); + int hours = NumberUtils.ParseInt32(parts[1]); + int mins = NumberUtils.ParseInt32(parts[2]); + int secs = NumberUtils.ParseInt32(parts[3]); + + return new TimeSpan(days, hours, mins, secs); } public static DateTime ParseDBDate(string value) { diff --git a/MCGalaxy/Database/PlayerData.cs b/MCGalaxy/Database/PlayerData.cs index ae0cc9c53..0ee90a28f 100644 --- a/MCGalaxy/Database/PlayerData.cs +++ b/MCGalaxy/Database/PlayerData.cs @@ -141,7 +141,7 @@ namespace MCGalaxy.DB } internal static int ParseInt(string value) { - return (value.Length == 0 || value.CaselessEq("null")) ? 0 : int.Parse(value); + return (value.Length == 0 || value.CaselessEq("null")) ? 0 : NumberUtils.ParseInt32(value); } internal static string ParseColor(string raw) { diff --git a/MCGalaxy/Economy/Economy.DB.cs b/MCGalaxy/Economy/Economy.DB.cs index 1e7271168..4c1cc4a69 100644 --- a/MCGalaxy/Economy/Economy.DB.cs +++ b/MCGalaxy/Economy/Economy.DB.cs @@ -60,7 +60,7 @@ namespace MCGalaxy.Eco public static string FindMatches(Player p, string name, out int money) { string[] match = PlayerDB.MatchValues(p, name, "Name,Money"); - money = match == null ? 0 : int.Parse(match[1]); + money = match == null ? 0 : NumberUtils.ParseInt32(match[1]); return match == null ? null : match[0]; } diff --git a/MCGalaxy/Economy/Item.cs b/MCGalaxy/Economy/Item.cs index 860d2f533..c60351e78 100644 --- a/MCGalaxy/Economy/Item.cs +++ b/MCGalaxy/Economy/Item.cs @@ -47,7 +47,7 @@ namespace MCGalaxy.Eco if (prop.CaselessEq("enabled")) { Enabled = value.CaselessEq("true"); } else if (prop.CaselessEq("purchaserank")) { - PurchaseRank = (LevelPermission)int.Parse(value); + PurchaseRank = (LevelPermission)NumberUtils.ParseInt32(value); } else { Parse(prop, value); } diff --git a/MCGalaxy/Economy/RankItem.cs b/MCGalaxy/Economy/RankItem.cs index de4aa70d5..d3a10f524 100644 --- a/MCGalaxy/Economy/RankItem.cs +++ b/MCGalaxy/Economy/RankItem.cs @@ -46,7 +46,7 @@ namespace MCGalaxy.Eco if (perm == LevelPermission.Null) return; RankEntry rank = GetOrAdd(perm); - rank.Price = int.Parse(args[1]); + rank.Price = NumberUtils.ParseInt32(args[1]); } public override void Serialise(List cfg) { diff --git a/MCGalaxy/Entity/ModelInfo.cs b/MCGalaxy/Entity/ModelInfo.cs index 44cdc7cd1..01c5a9ab8 100644 --- a/MCGalaxy/Entity/ModelInfo.cs +++ b/MCGalaxy/Entity/ModelInfo.cs @@ -69,7 +69,7 @@ namespace MCGalaxy string str = sep == -1 ? null : model.Substring(sep + 1); float scale; - if (!Utils.TryParseSingle(str, out scale)) scale = 1.0f; + if (!NumberUtils.TryParseSingle(str, out scale)) scale = 1.0f; if (scale < 0.01f) scale = 0.01f; // backwards compatibility for giant model diff --git a/MCGalaxy/Generator/MapGen.cs b/MCGalaxy/Generator/MapGen.cs index f8d5e0aeb..e808540bc 100644 --- a/MCGalaxy/Generator/MapGen.cs +++ b/MCGalaxy/Generator/MapGen.cs @@ -47,7 +47,7 @@ namespace MCGalaxy.Generator if (ArgFilter(arg)) { if (!ArgParser(arg)) return false; - } else if (int.TryParse(arg, out Seed)) { + } else if (NumberUtils.TryParseInt32(arg, out Seed)) { gotSeed = true; } else { if (!CommandParser.GetEnum(p, arg, "Seed", ref Biome)) return false; @@ -87,7 +87,8 @@ namespace MCGalaxy.Generator if (seed.Length == 0) return new Random(); int value; - if (!int.TryParse(seed, out value)) value = seed.GetHashCode(); + if (!NumberUtils.TryParseInt32(seed, out value)) + value = seed.GetHashCode(); return new Random(value); } // TODO move to CmdMaze diff --git a/MCGalaxy/Levels/Hacks.cs b/MCGalaxy/Levels/Hacks.cs index be5c6bd54..f876f7f00 100644 --- a/MCGalaxy/Levels/Hacks.cs +++ b/MCGalaxy/Levels/Hacks.cs @@ -82,7 +82,7 @@ namespace MCGalaxy { if (!part.CaselessStarts("jumpheight=")) continue; string heightPart = part.Substring(part.IndexOf('=') + 1); float value; - if (Utils.TryParseSingle(heightPart, out value)) + if (NumberUtils.TryParseSingle(heightPart, out value)) maxJump = (short)(value * 32); } return Packet.HackControl(fly, noclip, speed, respawn, thirdPerson, maxJump); diff --git a/MCGalaxy/Levels/LevelEnv.cs b/MCGalaxy/Levels/LevelEnv.cs index 535d769e9..0f4d8c30c 100644 --- a/MCGalaxy/Levels/LevelEnv.cs +++ b/MCGalaxy/Levels/LevelEnv.cs @@ -146,7 +146,7 @@ namespace MCGalaxy { p.Message("Reset weather for {0} &Sto 0 (Sun)", area); weather = EnvConfig.ENV_USE_DEFAULT; } else { - if (int.TryParse(value, out weather)) { + if (NumberUtils.TryParseInt32(value, out weather)) { } else if (value.CaselessEq("sun")) { weather = 0; } else if (value.CaselessEq("rain")) { weather = 1; } else if (value.CaselessEq("snow")) { weather = 2; diff --git a/MCGalaxy/Levels/LevelInfo.cs b/MCGalaxy/Levels/LevelInfo.cs index 19a95440a..eaf953f91 100644 --- a/MCGalaxy/Levels/LevelInfo.cs +++ b/MCGalaxy/Levels/LevelInfo.cs @@ -103,7 +103,7 @@ namespace MCGalaxy { string backupName = BackupNameFrom(path); int num; - if (!int.TryParse(backupName, out num)) continue; + if (!NumberUtils.TryParseInt32(backupName, out num)) continue; latest = Math.Max(num, latest); } return latest; diff --git a/MCGalaxy/Levels/LevelOperations.cs b/MCGalaxy/Levels/LevelOperations.cs index 0ea20db64..5a8a4ae24 100644 --- a/MCGalaxy/Levels/LevelOperations.cs +++ b/MCGalaxy/Levels/LevelOperations.cs @@ -48,7 +48,7 @@ namespace MCGalaxy { string restore = LevelInfo.BackupNameFrom(path); int num; - if (int.TryParse(restore, out num)) continue; + if (NumberUtils.TryParseInt32(restore, out num)) continue; count++; custom.Append(", " + restore); diff --git a/MCGalaxy/MCGalaxy_.csproj b/MCGalaxy/MCGalaxy_.csproj index c9968a570..9f48c4c5e 100644 --- a/MCGalaxy/MCGalaxy_.csproj +++ b/MCGalaxy/MCGalaxy_.csproj @@ -660,6 +660,7 @@ + diff --git a/MCGalaxy/Modules/Compiling/CompilerBackends.cs b/MCGalaxy/Modules/Compiling/CompilerBackends.cs index 7417b454e..33c0fe629 100644 --- a/MCGalaxy/Modules/Compiling/CompilerBackends.cs +++ b/MCGalaxy/Modules/Compiling/CompilerBackends.cs @@ -183,8 +183,8 @@ namespace MCGalaxy.Modules.Compiling if (full) { ce.FileName = m.Groups[2].Value; - ce.Line = int.Parse(m.Groups[4].Value, CultureInfo.InvariantCulture); - ce.Column = int.Parse(m.Groups[5].Value, CultureInfo.InvariantCulture); + ce.Line = NumberUtils.ParseInt32(m.Groups[4].Value); + ce.Column = NumberUtils.ParseInt32(m.Groups[5].Value); } ce.IsWarning = m.Groups[full ? 6 : 1].Value.CaselessEq("warning"); diff --git a/MCGalaxy/Modules/Relay/Discord/DiscordApiClient.cs b/MCGalaxy/Modules/Relay/Discord/DiscordApiClient.cs index 0b1961b1e..924a80349 100644 --- a/MCGalaxy/Modules/Relay/Discord/DiscordApiClient.cs +++ b/MCGalaxy/Modules/Relay/Discord/DiscordApiClient.cs @@ -146,9 +146,9 @@ namespace MCGalaxy.Modules.Relay.Discord string retryAfter = res.Headers["Retry-After"]; float delay; - if (Utils.TryParseSingle(resetAfter, out delay) && delay > 0) { + if (NumberUtils.TryParseSingle(resetAfter, out delay) && delay > 0) { // Prefer Discord "X-RateLimit-Reset-After" (millisecond precision) - } else if (Utils.TryParseSingle(retryAfter, out delay) && delay > 0) { + } else if (NumberUtils.TryParseSingle(retryAfter, out delay) && delay > 0) { // Fallback to general "Retry-After" header } else { // No recommended retry delay.. 30 seconds is a good bet diff --git a/MCGalaxy/Modules/Relay/Discord/DiscordWebsocket.cs b/MCGalaxy/Modules/Relay/Discord/DiscordWebsocket.cs index 789e5a8ae..453672df2 100644 --- a/MCGalaxy/Modules/Relay/Discord/DiscordWebsocket.cs +++ b/MCGalaxy/Modules/Relay/Discord/DiscordWebsocket.cs @@ -161,7 +161,7 @@ namespace MCGalaxy.Modules.Relay.Discord JsonObject obj = (JsonObject)ctx.Parse(); if (obj == null) return; - int opcode = int.Parse((string)obj["op"]); + int opcode = NumberUtils.ParseInt32((string)obj["op"]); DispatchPacket(opcode, obj); } @@ -187,7 +187,7 @@ namespace MCGalaxy.Modules.Relay.Discord void HandleHello(JsonObject obj) { JsonObject data = (JsonObject)obj["d"]; string interval = (string)data["heartbeat_interval"]; - int msInterval = int.Parse(interval); + int msInterval = NumberUtils.ParseInt32(interval); heartbeat = Server.Heartbeats.QueueRepeat(SendHeartbeat, null, TimeSpan.FromMilliseconds(msInterval)); @@ -249,7 +249,7 @@ namespace MCGalaxy.Modules.Relay.Discord obj["op"] = OPCODE_HEARTBEAT; if (Session.LastSeq != null) { - obj["d"] = int.Parse(Session.LastSeq); + obj["d"] = NumberUtils.ParseInt32(Session.LastSeq); } else { obj["d"] = null; } @@ -275,7 +275,7 @@ namespace MCGalaxy.Modules.Relay.Discord { { "token", Token }, { "session_id", Session.ID }, - { "seq", int.Parse(Session.LastSeq) } + { "seq", NumberUtils.ParseInt32(Session.LastSeq) } }; } diff --git a/MCGalaxy/Modules/Warps/Warp.cs b/MCGalaxy/Modules/Warps/Warp.cs index d15c16611..55e8f77c8 100644 --- a/MCGalaxy/Modules/Warps/Warp.cs +++ b/MCGalaxy/Modules/Warps/Warp.cs @@ -109,9 +109,9 @@ namespace MCGalaxy.Modules.Warps try { warp.Name = parts[0]; warp.Level = parts[1]; - warp.Pos.X = int.Parse(parts[2]); - warp.Pos.Y = int.Parse(parts[3]); - warp.Pos.Z = int.Parse(parts[4]); + warp.Pos.X = NumberUtils.ParseInt32(parts[2]); + warp.Pos.Y = NumberUtils.ParseInt32(parts[3]); + warp.Pos.Z = NumberUtils.ParseInt32(parts[4]); warp.Yaw = byte.Parse(parts[5]); warp.Pitch = byte.Parse(parts[6]); warps.Add(warp); diff --git a/MCGalaxy/Player/Ban.cs b/MCGalaxy/Player/Ban.cs index c1d26a0ca..7513cca73 100644 --- a/MCGalaxy/Player/Ban.cs +++ b/MCGalaxy/Player/Ban.cs @@ -133,9 +133,12 @@ namespace MCGalaxy string[] date = raw.SplitSpaces(); string[] minuteHour = date[5].Split(':'); - int hour = int.Parse(minuteHour[0]), minute = int.Parse(minuteHour[1]); - int day = int.Parse(date[1]), month = int.Parse(date[2]), year = int.Parse(date[3]); - return new DateTime(year, month, day, hour, minute, 0).ToUniversalTime(); + int hour = NumberUtils.ParseInt32(minuteHour[0]); + int min = NumberUtils.ParseInt32(minuteHour[1]); + int day = NumberUtils.ParseInt32(date[1]); + int month = NumberUtils.ParseInt32(date[2]); + int year = NumberUtils.ParseInt32(date[3]); + return new DateTime(year, month, day, hour, min, 0).ToUniversalTime(); } diff --git a/MCGalaxy/Player/Player.Login.cs b/MCGalaxy/Player/Player.Login.cs index 940f35645..45f541630 100644 --- a/MCGalaxy/Player/Player.Login.cs +++ b/MCGalaxy/Player/Player.Login.cs @@ -194,9 +194,9 @@ namespace MCGalaxy string modelScales = Server.modelScales.Get(name); if (!string.IsNullOrEmpty(modelScales)) { string[] bits = modelScales.SplitSpaces(3); - Utils.TryParseSingle(bits[0], out ScaleX); - Utils.TryParseSingle(bits[1], out ScaleY); - Utils.TryParseSingle(bits[2], out ScaleZ); + NumberUtils.TryParseSingle(bits[0], out ScaleX); + NumberUtils.TryParseSingle(bits[1], out ScaleY); + NumberUtils.TryParseSingle(bits[2], out ScaleZ); } string rotations = Server.rotations.Get(name); diff --git a/MCGalaxy/Server/Tasks/UpgradeTasks.cs b/MCGalaxy/Server/Tasks/UpgradeTasks.cs index c6459bb7f..de4014b72 100644 --- a/MCGalaxy/Server/Tasks/UpgradeTasks.cs +++ b/MCGalaxy/Server/Tasks/UpgradeTasks.cs @@ -53,10 +53,15 @@ namespace MCGalaxy.Tasks { string[] args = lines[i].SplitSpaces(); if (args.Length < 9) continue; - int min = int.Parse(args[4]), hour = int.Parse(args[5]); - int day = int.Parse(args[6]), month = int.Parse(args[7]), year = int.Parse(args[8]); - int periodH = int.Parse(args[3]), periodM = 0; - if (args.Length > 10) periodM = int.Parse(args[10]); + int min = NumberUtils.ParseInt32(args[4]); + int hour = NumberUtils.ParseInt32(args[5]); + int day = NumberUtils.ParseInt32(args[6]); + int month = NumberUtils.ParseInt32(args[7]); + int year = NumberUtils.ParseInt32(args[8]); + + int periodH = NumberUtils.ParseInt32(args[3]); + int periodM = 0; + if (args.Length > 10) periodM = NumberUtils.ParseInt32(args[10]); DateTime assigned = new DateTime(year, month, day, hour, min, 0); DateTime expiry = assigned.AddHours(periodH).AddMinutes(periodM); diff --git a/MCGalaxy/util/Formatting/Paginator.cs b/MCGalaxy/util/Formatting/Paginator.cs index 60057830c..b1d1369ff 100644 --- a/MCGalaxy/util/Formatting/Paginator.cs +++ b/MCGalaxy/util/Formatting/Paginator.cs @@ -51,7 +51,7 @@ namespace MCGalaxy } else if (modifier.CaselessEq("all")) { OutputItems(p, items, 0, items.Count, formatter, printer); p.Message("Showing {0} 1-{1} (out of {1})", type, items.Count); - } else if (!int.TryParse(modifier, out page)) { + } else if (!NumberUtils.TryParseInt32(modifier, out page)) { p.Message("Input must be either \"all\" or an integer."); } else { OutputPage(p, items, formatter, printer, cmd, type, page, perPage); diff --git a/MCGalaxy/util/NumberUtils.cs b/MCGalaxy/util/NumberUtils.cs new file mode 100644 index 000000000..2c0ca76d5 --- /dev/null +++ b/MCGalaxy/util/NumberUtils.cs @@ -0,0 +1,65 @@ +/* + Copyright 2015 MCGalaxy + + Dual-licensed under the Educational Community License, Version 2.0 and + the GNU General Public License, Version 3 (the "Licenses"); you may + not use this file except in compliance with the Licenses. You may + obtain a copy of the Licenses at + + https://opensource.org/license/ecl-2-0/ + https://www.gnu.org/licenses/gpl-3.0.html + + Unless required by applicable law or agreed to in writing, + software distributed under the Licenses are distributed on an "AS IS" + BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express + or implied. See the Licenses for the specific language governing + permissions and limitations under the Licenses. + */ +using System; +using System.Globalization; + +namespace MCGalaxy +{ + public static class NumberUtils + { + const NumberStyles DECIMAL_STYLE = NumberStyles.Integer | NumberStyles.AllowDecimalPoint; + const NumberStyles INTEGER_STYLE = NumberStyles.Integer; + + + // Not all languages use . as their decimal point separator + public static bool TryParseSingle(string s, out float result) { + if (s != null && s.IndexOf(',') >= 0) s = s.Replace(',', '.'); + result = 0; float temp; + + if (!Single.TryParse(s, DECIMAL_STYLE, NumberFormatInfo.InvariantInfo, out temp)) return false; + if (Single.IsInfinity(temp) || Single.IsNaN(temp)) return false; + result = temp; + return true; + } + + public static bool TryParseDouble(string s, out double result) { + if (s != null && s.IndexOf(',') >= 0) s = s.Replace(',', '.'); + result = 0; double temp; + + if (!Double.TryParse(s, DECIMAL_STYLE, NumberFormatInfo.InvariantInfo, out temp)) return false; + if (Double.IsInfinity(temp) || Double.IsNaN(temp)) return false; + result = temp; + return true; + } + + // in JSON we must use . instead of , + public static string StringifyDouble(double value) { + return value.ToString(CultureInfo.InvariantCulture); + } + + + // Some languages don't have - as the negative sign symbol + public static bool TryParseInt32(string s, out int result) { + return int.TryParse(s, INTEGER_STYLE, NumberFormatInfo.InvariantInfo, out result); + } + + public static int ParseInt32(string s) { + return int.Parse(s, INTEGER_STYLE, NumberFormatInfo.InvariantInfo); + } + } +} diff --git a/MCGalaxy/util/UIHelpers.cs b/MCGalaxy/util/UIHelpers.cs index 1c2eaea74..bae80ec38 100644 --- a/MCGalaxy/util/UIHelpers.cs +++ b/MCGalaxy/util/UIHelpers.cs @@ -68,7 +68,8 @@ namespace MCGalaxy.UI Logger.Log(LogType.CommandUsage, "(console): /{0} can only be used in-game.", cmd.name); return; } - Thread thread = new Thread( + Thread thread; + Server.StartThread(out thread, "ConsoleCMD_" + name, () => { try { cmd.Use(Player.Console, args); @@ -82,9 +83,6 @@ namespace MCGalaxy.UI Logger.Log(LogType.CommandUsage, "(console): FAILED COMMAND"); } }); - thread.Name = "ConsoleCMD_" + name; - thread.IsBackground = true; - thread.Start(); } public static string Format(string message) { diff --git a/MCGalaxy/util/Utils.cs b/MCGalaxy/util/Utils.cs index 23c413c75..263912faa 100644 --- a/MCGalaxy/util/Utils.cs +++ b/MCGalaxy/util/Utils.cs @@ -21,9 +21,10 @@ using System.Globalization; using System.IO; using System.Text; -namespace MCGalaxy { - public static class Utils { - +namespace MCGalaxy +{ + public static class Utils + { public static string Hex(byte r, byte g, byte b) { return "#" + r.ToString("X2") + g.ToString("X2") + b.ToString("X2"); } @@ -64,35 +65,6 @@ namespace MCGalaxy { /// Divides by 16, rounding up if there is a remainder. public static int CeilDiv16(int x) { return (x + 15) / 16; } - - const NumberStyles style = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite - | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint; - - // Not all languages use . as their decimal point separator - public static bool TryParseSingle(string s, out float result) { - if (s != null && s.IndexOf(',') >= 0) s = s.Replace(',', '.'); - result = 0; float temp; - - if (!Single.TryParse(s, style, NumberFormatInfo.InvariantInfo, out temp)) return false; - if (Single.IsInfinity(temp) || Single.IsNaN(temp)) return false; - result = temp; - return true; - } - - public static bool TryParseDouble(string s, out double result) { - if (s != null && s.IndexOf(',') >= 0) s = s.Replace(',', '.'); - result = 0; double temp; - - if (!Double.TryParse(s, style, NumberFormatInfo.InvariantInfo, out temp)) return false; - if (Double.IsInfinity(temp) || Double.IsNaN(temp)) return false; - result = temp; - return true; - } - - // in JSON we must use . instead of , - public static string StringifyDouble(double value) { - return value.ToString(CultureInfo.InvariantCulture); - } public static List ReadAllLinesList(string path) {