diff --git a/.editorconfig b/.editorconfig index 9b6d6a510c..5e6d3f6649 100644 --- a/.editorconfig +++ b/.editorconfig @@ -145,7 +145,7 @@ dotnet_diagnostic.IDE0056.severity = warning # IDE0057 Use range operator #csharp_style_prefer_range_operator = true -dotnet_diagnostic.IDE0057.severity = silent # Requires C# 8 - TODO Consider enabling +dotnet_diagnostic.IDE0057.severity = warning # IDE0070 Use 'System.HashCode.Combine' # No options diff --git a/OpenRA.Game/Exts.cs b/OpenRA.Game/Exts.cs index 57ced8a9c3..3fae7d9be1 100644 --- a/OpenRA.Game/Exts.cs +++ b/OpenRA.Game/Exts.cs @@ -590,8 +590,8 @@ namespace OpenRA return true; } - Current = span.Slice(0, index); - str = span.Slice(index + 1); + Current = span[..index]; + str = span[(index + 1)..]; return true; } diff --git a/OpenRA.Game/FileSystem/FileSystem.cs b/OpenRA.Game/FileSystem/FileSystem.cs index e2c598e9ce..16d775310d 100644 --- a/OpenRA.Game/FileSystem/FileSystem.cs +++ b/OpenRA.Game/FileSystem/FileSystem.cs @@ -85,14 +85,14 @@ namespace OpenRA.FileSystem { var optional = name.StartsWith("~", StringComparison.Ordinal); if (optional) - name = name.Substring(1); + name = name[1..]; try { IReadOnlyPackage package; if (name.StartsWith("$", StringComparison.Ordinal)) { - name = name.Substring(1); + name = name[1..]; if (!installedMods.TryGetValue(name, out var mod)) throw new InvalidOperationException($"Could not load mod '{name}'. Available mods: {installedMods.Keys.JoinWith(", ")}"); @@ -211,9 +211,9 @@ namespace OpenRA.FileSystem public bool TryGetPackageContaining(string path, out IReadOnlyPackage package, out string filename) { var explicitSplit = path.IndexOf('|'); - if (explicitSplit > 0 && explicitMounts.TryGetValue(path.Substring(0, explicitSplit), out package)) + if (explicitSplit > 0 && explicitMounts.TryGetValue(path[..explicitSplit], out package)) { - filename = path.Substring(explicitSplit + 1); + filename = path[(explicitSplit + 1)..]; return true; } @@ -228,9 +228,9 @@ namespace OpenRA.FileSystem var explicitSplit = filename.IndexOf('|'); if (explicitSplit > 0) { - if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage)) + if (explicitMounts.TryGetValue(filename[..explicitSplit], out var explicitPackage)) { - s = explicitPackage.GetStream(filename.Substring(explicitSplit + 1)); + s = explicitPackage.GetStream(filename[(explicitSplit + 1)..]); if (s != null) return true; } @@ -263,8 +263,8 @@ namespace OpenRA.FileSystem { var explicitSplit = filename.IndexOf('|'); if (explicitSplit > 0) - if (explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage)) - if (explicitPackage.Contains(filename.Substring(explicitSplit + 1))) + if (explicitMounts.TryGetValue(filename[..explicitSplit], out var explicitPackage)) + if (explicitPackage.Contains(filename[(explicitSplit + 1)..])) return true; return fileIndex.ContainsKey(filename); @@ -279,7 +279,7 @@ namespace OpenRA.FileSystem if (explicitSplit < 0) return false; - if (!explicitMounts.TryGetValue(filename.Substring(0, explicitSplit), out var explicitPackage)) + if (!explicitMounts.TryGetValue(filename[..explicitSplit], out var explicitPackage)) return false; if (installedMods[modID].Package == explicitPackage) @@ -297,8 +297,8 @@ namespace OpenRA.FileSystem var explicitSplit = path.IndexOf('|'); if (explicitSplit > 0 && !path.StartsWith("^")) { - var parent = path.Substring(0, explicitSplit); - var filename = path.Substring(explicitSplit + 1); + var parent = path[..explicitSplit]; + var filename = path[(explicitSplit + 1)..]; var parentPath = manifest.Packages.FirstOrDefault(kv => kv.Value == parent).Key; if (parentPath == null) @@ -306,7 +306,7 @@ namespace OpenRA.FileSystem if (parentPath.StartsWith("$", StringComparison.Ordinal)) { - if (!installedMods.TryGetValue(parentPath.Substring(1), out var mod)) + if (!installedMods.TryGetValue(parentPath[1..], out var mod)) return null; if (!(mod.Package is Folder)) @@ -329,7 +329,7 @@ namespace OpenRA.FileSystem if (resolved == null) return null; - foreach (var name in path.Substring(resolved.Length).Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) + foreach (var name in path[resolved.Length..].Split(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)) { // Filter out paths of the form /foo/bar/./baz if (name == ".") diff --git a/OpenRA.Game/FileSystem/ZipFile.cs b/OpenRA.Game/FileSystem/ZipFile.cs index d5ce5471cc..60356b778c 100644 --- a/OpenRA.Game/FileSystem/ZipFile.cs +++ b/OpenRA.Game/FileSystem/ZipFile.cs @@ -148,7 +148,7 @@ namespace OpenRA.FileSystem public ZipFolder(ReadOnlyZipFile parent, string path) { if (path.EndsWith("/", StringComparison.Ordinal)) - path = path.Substring(0, path.Length - 1); + path = path[..^1]; Name = path; Parent = parent; @@ -168,7 +168,7 @@ namespace OpenRA.FileSystem { if (entry.StartsWith(Name, StringComparison.Ordinal) && entry != Name) { - var filename = entry.Substring(Name.Length + 1); + var filename = entry[(Name.Length + 1)..]; var dirLevels = filename.Split('/').Count(c => !string.IsNullOrEmpty(c)); if (dirLevels == 1) yield return filename; diff --git a/OpenRA.Game/Game.cs b/OpenRA.Game/Game.cs index 8b8a671a48..0f69d542f7 100644 --- a/OpenRA.Game/Game.cs +++ b/OpenRA.Game/Game.cs @@ -416,7 +416,7 @@ namespace OpenRA // Sanitize input from platform-specific launchers // Process.Start requires paths to not be quoted, even if they contain spaces if (launchPath != null && launchPath.First() == '"' && launchPath.Last() == '"') - launchPath = launchPath.Substring(1, launchPath.Length - 2); + launchPath = launchPath[1..^1]; // Metadata registration requires an explicit launch path if (launchPath != null) diff --git a/OpenRA.Game/Input/Hotkey.cs b/OpenRA.Game/Input/Hotkey.cs index 5b4fe62ad7..995887847e 100644 --- a/OpenRA.Game/Input/Hotkey.cs +++ b/OpenRA.Game/Input/Hotkey.cs @@ -42,7 +42,7 @@ namespace OpenRA var mods = Modifiers.None; if (parts.Length >= 2) { - var modString = s.Substring(s.IndexOf(' ')); + var modString = s[s.IndexOf(' ')..]; if (!Enum.TryParse(modString, true, out mods)) return false; } diff --git a/OpenRA.Game/Map/ActorReference.cs b/OpenRA.Game/Map/ActorReference.cs index eb0259123a..090375ccab 100644 --- a/OpenRA.Game/Map/ActorReference.cs +++ b/OpenRA.Game/Map/ActorReference.cs @@ -94,7 +94,7 @@ namespace OpenRA continue; var initTypeName = init.GetType().Name; - var initName = initTypeName.Substring(0, initTypeName.Length - 4); + var initName = initTypeName[..^4]; if (!string.IsNullOrEmpty(init.InstanceName)) initName += ActorInfo.TraitInstanceSeparator + init.InstanceName; diff --git a/OpenRA.Game/Map/MapCache.cs b/OpenRA.Game/Map/MapCache.cs index ccbdefd670..064cdfec1d 100644 --- a/OpenRA.Game/Map/MapCache.cs +++ b/OpenRA.Game/Map/MapCache.cs @@ -99,7 +99,7 @@ namespace OpenRA IReadOnlyPackage package; var optional = name.StartsWith("~", StringComparison.Ordinal); if (optional) - name = name.Substring(1); + name = name[1..]; try { @@ -183,7 +183,7 @@ namespace OpenRA var name = kv.Key; var optional = name.StartsWith("~", StringComparison.Ordinal); if (optional) - name = name.Substring(1); + name = name[1..]; // Don't try to open the map directory in the support directory if it doesn't exist var resolved = Platform.ResolvePath(name); diff --git a/OpenRA.Game/MiniYaml.cs b/OpenRA.Game/MiniYaml.cs index 77ec2ea3e2..4bea7e90ed 100644 --- a/OpenRA.Game/MiniYaml.cs +++ b/OpenRA.Game/MiniYaml.cs @@ -254,7 +254,7 @@ namespace OpenRA } if (commentStart >= 0 && !discardCommentsAndWhitespace) - comment = line.Slice(commentStart); + comment = line[commentStart..]; if (value.Length > 1) { @@ -376,7 +376,7 @@ namespace OpenRA } else if (n.Key.StartsWith("-", StringComparison.Ordinal)) { - var removed = n.Key.Substring(1); + var removed = n.Key[1..]; if (resolved.RemoveAll(r => r.Key == removed) == 0) throw new YamlException($"{n.Location}: There are no elements with key `{removed}` to remove"); } diff --git a/OpenRA.Game/Network/UnitOrders.cs b/OpenRA.Game/Network/UnitOrders.cs index 186b1d1491..33d611fad1 100644 --- a/OpenRA.Game/Network/UnitOrders.cs +++ b/OpenRA.Game/Network/UnitOrders.cs @@ -75,7 +75,7 @@ namespace OpenRA.Network // Cut chat messages to the hard limit to avoid exploits var message = order.TargetString; if (message.Length > ChatMessageMaxLength) - message = order.TargetString.Substring(0, ChatMessageMaxLength); + message = order.TargetString[..ChatMessageMaxLength]; // ExtraData 0 means this is a normal chat order, everything else is team chat if (order.ExtraData == 0) diff --git a/OpenRA.Game/Platform.cs b/OpenRA.Game/Platform.cs index 07b638e0e9..dcfe8afe83 100644 --- a/OpenRA.Game/Platform.cs +++ b/OpenRA.Game/Platform.cs @@ -244,13 +244,13 @@ namespace OpenRA return BinDir; if (path.StartsWith("^SupportDir|", StringComparison.Ordinal)) - path = SupportDir + path.Substring(12); + path = SupportDir + path[12..]; if (path.StartsWith("^EngineDir|", StringComparison.Ordinal)) - path = EngineDir + path.Substring(11); + path = EngineDir + path[11..]; if (path.StartsWith("^BinDir|", StringComparison.Ordinal)) - path = BinDir + path.Substring(8); + path = BinDir + path[8..]; return path; } diff --git a/OpenRA.Game/Primitives/Color.cs b/OpenRA.Game/Primitives/Color.cs index c5210c5670..1d5f79f006 100644 --- a/OpenRA.Game/Primitives/Color.cs +++ b/OpenRA.Game/Primitives/Color.cs @@ -168,13 +168,13 @@ namespace OpenRA.Primitives return false; byte alpha = 255; - if (!byte.TryParse(value.Substring(0, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var red) - || !byte.TryParse(value.Substring(2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var green) - || !byte.TryParse(value.Substring(4, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var blue)) + if (!byte.TryParse(value[0..2], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var red) + || !byte.TryParse(value[2..4], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var green) + || !byte.TryParse(value[4..6], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var blue)) return false; if (value.Length == 8 - && !byte.TryParse(value.Substring(6, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out alpha)) + && !byte.TryParse(value[6..8], NumberStyles.HexNumber, CultureInfo.InvariantCulture, out alpha)) return false; color = FromArgb(alpha, red, green, blue); diff --git a/OpenRA.Game/Settings.cs b/OpenRA.Game/Settings.cs index 008a00a677..87948fea30 100644 --- a/OpenRA.Game/Settings.cs +++ b/OpenRA.Game/Settings.cs @@ -443,7 +443,7 @@ namespace OpenRA // avoid UI glitches if (clean.Length > 16) - clean = clean.Substring(0, 16); + clean = clean[..16]; return clean; } diff --git a/OpenRA.Game/Support/VariableExpression.cs b/OpenRA.Game/Support/VariableExpression.cs index 2906f6a420..77db5a97ea 100644 --- a/OpenRA.Game/Support/VariableExpression.cs +++ b/OpenRA.Game/Support/VariableExpression.cs @@ -354,7 +354,7 @@ namespace OpenRA.Support if (cc != CharClass.Digit) { if (cc != CharClass.Whitespace && cc != CharClass.Operator && cc != CharClass.Mixed) - throw new InvalidDataException($"Number {int.Parse(expression.Substring(start, i - start))} and variable merged at index {start}"); + throw new InvalidDataException($"Number {int.Parse(expression[start..i])} and variable merged at index {start}"); return true; } @@ -369,7 +369,7 @@ namespace OpenRA.Support static TokenType VariableOrKeyword(string expression, int start, ref int i) { if (CharClassOf(expression[i - 1]) == CharClass.Mixed) - throw new InvalidDataException($"Invalid identifier end character at index {i - 1} for `{expression.Substring(start, i - start)}`"); + throw new InvalidDataException($"Invalid identifier end character at index {i - 1} for `{expression[start..i]}`"); return VariableOrKeyword(expression, start, i - start); } @@ -540,10 +540,10 @@ namespace OpenRA.Support switch (type) { case TokenType.Number: - return new NumberToken(start, expression.Substring(start, i - start)); + return new NumberToken(start, expression[start..i]); case TokenType.Variable: - return new VariableToken(start, expression.Substring(start, i - start)); + return new VariableToken(start, expression[start..i]); default: return new Token(type, start); diff --git a/OpenRA.Game/Widgets/WidgetLoader.cs b/OpenRA.Game/Widgets/WidgetLoader.cs index d0938ceb44..3222b3e76d 100644 --- a/OpenRA.Game/Widgets/WidgetLoader.cs +++ b/OpenRA.Game/Widgets/WidgetLoader.cs @@ -28,7 +28,7 @@ namespace OpenRA foreach (var file in modData.Manifest.ChromeLayout.Select(a => MiniYaml.FromStream(modData.DefaultFileSystem.Open(a), a))) foreach (var w in file) { - var key = w.Key.Substring(w.Key.IndexOf('@') + 1); + var key = w.Key[(w.Key.IndexOf('@') + 1)..]; if (widgets.ContainsKey(key)) throw new InvalidDataException($"Widget has duplicate Key `{w.Key}` at {w.Location}"); widgets.Add(key, w); diff --git a/OpenRA.Mods.Cnc/FileFormats/IdxEntry.cs b/OpenRA.Mods.Cnc/FileFormats/IdxEntry.cs index e5a95f841c..ae7fac664c 100644 --- a/OpenRA.Mods.Cnc/FileFormats/IdxEntry.cs +++ b/OpenRA.Mods.Cnc/FileFormats/IdxEntry.cs @@ -27,7 +27,7 @@ namespace OpenRA.Mods.Cnc.FileFormats var name = s.ReadASCII(16); var pos = name.IndexOf('\0'); if (pos != 0) - name = name.Substring(0, pos); + name = name[..pos]; Filename = string.Concat(name, ".wav"); Offset = s.ReadUInt32(); diff --git a/OpenRA.Mods.Cnc/UtilityCommands/Glob.cs b/OpenRA.Mods.Cnc/UtilityCommands/Glob.cs index b11fe898f0..79821d2d5c 100644 --- a/OpenRA.Mods.Cnc/UtilityCommands/Glob.cs +++ b/OpenRA.Mods.Cnc/UtilityCommands/Glob.cs @@ -46,11 +46,11 @@ namespace OpenRA.Mods.Cnc.UtilityCommands var index = filePath.IndexOfAny(DirectorySeparators, startIndex); if (index == -1) { - parts.Add(filePath.Substring(startIndex)); + parts.Add(filePath[startIndex..]); break; } - parts.Add(filePath.Substring(startIndex, index - startIndex + 1)); + parts.Add(filePath[startIndex..index]); startIndex = index + 1; } @@ -106,7 +106,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands else { if (dir[^1] == Path.DirectorySeparatorChar || dir[^1] == Path.AltDirectorySeparatorChar) - dir = dir.Substring(0, dir.Length - 1); + dir = dir[..^1]; foreach (var subDir in Directory.EnumerateDirectories(basePath, dir, SearchOption.TopDirectoryOnly)) foreach (var s in Expand(subDir, dirs, dirIndex + 1, file)) yield return s; diff --git a/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs b/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs index 954e262271..eb77730ad0 100644 --- a/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs +++ b/OpenRA.Mods.Cnc/UtilityCommands/ImportTiberianDawnLegacyMapCommand.cs @@ -165,7 +165,7 @@ namespace OpenRA.Mods.Cnc.UtilityCommands public override void ReadPacks(IniFile file, string filename) { - using (var s = File.OpenRead(filename.Substring(0, filename.Length - 4) + ".bin")) + using (var s = File.OpenRead(filename[..^4] + ".bin")) UnpackTileData(s); ReadOverlay(file); diff --git a/OpenRA.Mods.Common/Commands/ChatCommands.cs b/OpenRA.Mods.Common/Commands/ChatCommands.cs index f18f72303d..53b68a018a 100644 --- a/OpenRA.Mods.Common/Commands/ChatCommands.cs +++ b/OpenRA.Mods.Common/Commands/ChatCommands.cs @@ -36,11 +36,11 @@ namespace OpenRA.Mods.Common.Commands { if (message.StartsWith("/")) { - var name = message.Substring(1).Split(' ')[0].ToLowerInvariant(); + var name = message[1..].Split(' ')[0].ToLowerInvariant(); var command = Commands.FirstOrDefault(x => x.Key == name); if (command.Value != null) - command.Value.InvokeCommand(name.ToLowerInvariant(), message.Substring(1 + name.Length).Trim()); + command.Value.InvokeCommand(name.ToLowerInvariant(), message[(1 + name.Length)..].Trim()); else TextNotificationsManager.Debug(Game.ModData.Translation.GetString(InvalidCommand, Translation.Arguments("name", name))); diff --git a/OpenRA.Mods.Common/FileFormats/IniFile.cs b/OpenRA.Mods.Common/FileFormats/IniFile.cs index 9a2b0838ae..b854479826 100644 --- a/OpenRA.Mods.Common/FileFormats/IniFile.cs +++ b/OpenRA.Mods.Common/FileFormats/IniFile.cs @@ -67,7 +67,7 @@ namespace OpenRA.Mods.Common.FileFormats { var comment = line.IndexOf(';'); if (comment >= 0) - line = line.Substring(0, comment); + line = line[..comment]; line = line.Trim(); if (line.Length == 0) @@ -78,8 +78,8 @@ namespace OpenRA.Mods.Common.FileFormats var eq = line.IndexOf('='); if (eq >= 0) { - key = line.Substring(0, eq).Trim(); - value = line.Substring(eq + 1, line.Length - eq - 1).Trim(); + key = line[..eq].Trim(); + value = line[(eq + 1)..].Trim(); } if (currentSection == null) diff --git a/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs b/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs index da16b070d0..8f72eac535 100644 --- a/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs +++ b/OpenRA.Mods.Common/Lint/CheckChromeHotkeys.cs @@ -40,7 +40,7 @@ namespace OpenRA.Mods.Common.Lint var checkWidgetFields = modData.ObjectCreator.GetTypesImplementing() .SelectMany(w => Utility.GetFields(w) .Where(f => f.FieldType == typeof(HotkeyReference)) - .Select(f => (w.Name.Substring(0, w.Name.Length - 6), f.Name))) + .Select(f => (w.Name[..^6], f.Name))) .ToArray(); var customLintMethods = new Dictionary>(); @@ -52,7 +52,7 @@ namespace OpenRA.Mods.Common.Lint var p = m.GetParameters(); if (p.Length == 3 && p[0].ParameterType == typeof(MiniYamlNode) && p[1].ParameterType == typeof(Action) && p[2].ParameterType == typeof(Action)) - customLintMethods.GetOrAdd(w.Name.Substring(0, w.Name.Length - 6)).Add(m.Name); + customLintMethods.GetOrAdd(w.Name[..^6]).Add(m.Name); } } diff --git a/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs b/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs index 57171dbe38..271ca97777 100644 --- a/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs +++ b/OpenRA.Mods.Common/Lint/CheckUnknownTraitFields.cs @@ -38,7 +38,7 @@ namespace OpenRA.Mods.Common.Lint { var name = key.Split('@')[0]; if (name.StartsWith("-", StringComparison.Ordinal)) - return name.Substring(1); + return name[1..]; return name; } diff --git a/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs b/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs index a8ec77aaee..f0569d4ead 100644 --- a/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs +++ b/OpenRA.Mods.Common/Lint/CheckUnknownWeaponFields.cs @@ -39,7 +39,7 @@ namespace OpenRA.Mods.Common.Lint { var name = key.Split('@')[0]; if (name.StartsWith("-", StringComparison.Ordinal)) - return name.Substring(1); + return name[1..]; return name; } diff --git a/OpenRA.Mods.Common/Traits/Render/ProductionIconOverlayManager.cs b/OpenRA.Mods.Common/Traits/Render/ProductionIconOverlayManager.cs index 78e9f1e3fb..76ecbd9f3a 100644 --- a/OpenRA.Mods.Common/Traits/Render/ProductionIconOverlayManager.cs +++ b/OpenRA.Mods.Common/Traits/Render/ProductionIconOverlayManager.cs @@ -104,7 +104,7 @@ namespace OpenRA.Mods.Common.Traits.Render string GetName(string key) { - return key.Substring(prefix.Length); + return key[prefix.Length..]; } public void PrerequisitesAvailable(string key) diff --git a/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs b/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs index 4e31c4acd5..8eab8427f0 100644 --- a/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs +++ b/OpenRA.Mods.Common/Traits/Render/RenderSprites.cs @@ -240,7 +240,7 @@ namespace OpenRA.Mods.Common.Traits.Render { if (sequence.StartsWith(s.Prefix, StringComparison.Ordinal)) { - sequence = sequence.Substring(s.Prefix.Length); + sequence = sequence[s.Prefix.Length..]; break; } } diff --git a/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs b/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs index d47e089a4e..6030709470 100644 --- a/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs +++ b/OpenRA.Mods.Common/Traits/Render/WithNameTagDecoration.cs @@ -56,7 +56,7 @@ namespace OpenRA.Mods.Common.Traits.Render name = self.Owner.PlayerName; if (name.Length > info.MaxLength) - name = name.Substring(0, info.MaxLength); + name = name[..info.MaxLength]; } protected override IEnumerable RenderDecoration(Actor self, WorldRenderer wr, int2 screenPos) @@ -78,7 +78,7 @@ namespace OpenRA.Mods.Common.Traits.Render name = self.Owner.PlayerName; if (name.Length > Info.MaxLength) - name = name.Substring(0, Info.MaxLength); + name = name[..Info.MaxLength]; } } } diff --git a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs index af3e7c9a84..184a34d48d 100644 --- a/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs +++ b/OpenRA.Mods.Common/Traits/World/EditorActorLayer.cs @@ -201,7 +201,7 @@ namespace OpenRA.Mods.Common.Traits foreach (var kv in mp) { var name = kv.Key; - var index = int.Parse(name.Substring(5)); + var index = int.Parse(name[5..]); if (index >= newCount) { diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs index c07286d0e5..1fbb8d94af 100644 --- a/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20221203/ExplicitSequenceFilenames.cs @@ -359,7 +359,7 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules // Replace removals with masking foreach (var node in sequenceNode.Value.Nodes) if (node.Key?.StartsWith("-") ?? false) - node.Key = node.Key.Substring(1); + node.Key = node.Key[1..]; var combineNode = sequenceNode.LastChildMatching("Combine"); if (combineNode != null) @@ -389,8 +389,8 @@ namespace OpenRA.Mods.Common.UpdateRules.Rules var overrideFilename = filename; if (useTilesetCode) - overrideFilename = filename.Substring(0, 1) + tilesetCodes[sequenceTileset] + - filename.Substring(2, filename.Length - 2); + overrideFilename = filename[..1] + tilesetCodes[sequenceTileset] + + filename[2..]; if (addExtension) overrideFilename += useTilesetExtension ? tilesetExtensions[sequenceTileset] : defaultSpriteExtension; diff --git a/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs b/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs index ae1a7ec6a9..ed520cf127 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdateUtils.cs @@ -327,7 +327,7 @@ namespace OpenRA.Mods.Common.UpdateRules var prefix = includeRemovals && node.IsRemoval() ? "-" : ""; var split = node.Key.IndexOf("@", StringComparison.Ordinal); if (preserveSuffix && split > -1) - node.Key = prefix + newKey + node.Key.Substring(split); + node.Key = prefix + newKey + node.Key[split..]; else node.Key = prefix + newKey; } @@ -391,7 +391,7 @@ namespace OpenRA.Mods.Common.UpdateRules return false; var atPosition = node.Key.IndexOf('@'); - return atPosition > 0 && node.Key.Substring(0, atPosition) == prefix + match; + return atPosition > 0 && node.Key[..atPosition] == prefix + match; } /// Returns true if the node is of the form [match], [match]@[arbitrary suffix] or [arbitrary suffix]@[match]. @@ -401,7 +401,7 @@ namespace OpenRA.Mods.Common.UpdateRules return false; var atPosition = node.Key.IndexOf('@'); - var relevantPart = ignoreSuffix && atPosition > 0 ? node.Key.Substring(0, atPosition) : node.Key; + var relevantPart = ignoreSuffix && atPosition > 0 ? node.Key[..atPosition] : node.Key; if (relevantPart.Contains(match) && (includeRemovals || !node.IsRemoval())) return true; diff --git a/OpenRA.Mods.Common/Util.cs b/OpenRA.Mods.Common/Util.cs index 6f98d43f43..93abb794c1 100644 --- a/OpenRA.Mods.Common/Util.cs +++ b/OpenRA.Mods.Common/Util.cs @@ -229,7 +229,7 @@ namespace OpenRA.Mods.Common public static string InternalTypeName(Type t) { return t.IsGenericType - ? $"{t.Name.Substring(0, t.Name.IndexOf('`'))}<{string.Join(", ", t.GenericTypeArguments.Select(arg => arg.Name))}>" + ? $"{t.Name[..t.Name.IndexOf('`')]}<{string.Join(", ", t.GenericTypeArguments.Select(arg => arg.Name))}>" : t.Name; } diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractEmmyLuaAPI.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractEmmyLuaAPI.cs index 6473838b76..61ad1e1be5 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractEmmyLuaAPI.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractEmmyLuaAPI.cs @@ -129,7 +129,7 @@ namespace OpenRA.Mods.Common.UtilityCommands var localEnums = new List(); foreach (var init in actorInits) { - var name = init.Name.Substring(0, init.Name.Length - 4); + var name = init.Name[..^4]; var parameters = init.GetConstructors().Select(ci => ci.GetParameters()); var parameterString = string.Join(" | ", parameters diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs index c8d130e1d0..bf412a7108 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractTraitDocsCommand.cs @@ -53,7 +53,7 @@ namespace OpenRA.Mods.Common.UtilityCommands .Select(type => new { type.Namespace, - Name = type.Name.EndsWith("Info") ? type.Name.Substring(0, type.Name.Length - 4) : type.Name, + Name = type.Name.EndsWith("Info") ? type.Name[..^4] : type.Name, Description = string.Join(" ", Utility.GetCustomAttributes(type, false).SelectMany(d => d.Lines)), RequiresTraits = RequiredTraitTypes(type) .Select(y => y.Name), @@ -79,7 +79,7 @@ namespace OpenRA.Mods.Common.UtilityCommands .Select(a => { var name = a.AttributeType.Name; - name = name.EndsWith("Attribute") ? name.Substring(0, name.Length - 9) : name; + name = name.EndsWith("Attribute") ? name[..^9] : name; return new { diff --git a/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs index a2a432ba3e..389b5fe9a7 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ExtractWeaponDocsCommand.cs @@ -58,7 +58,7 @@ namespace OpenRA.Mods.Common.UtilityCommands .Select(type => new { type.Namespace, - Name = type.Name.EndsWith("Info") ? type.Name.Substring(0, type.Name.Length - 4) : type.Name, + Name = type.Name.EndsWith("Info") ? type.Name[..^4] : type.Name, Description = string.Join(" ", Utility.GetCustomAttributes(type, false).SelectMany(d => d.Lines)), InheritedTypes = type.BaseTypes() .Select(y => y.Name) @@ -82,7 +82,7 @@ namespace OpenRA.Mods.Common.UtilityCommands .Select(a => { var name = a.AttributeType.Name; - name = name.EndsWith("Attribute") ? name.Substring(0, name.Length - 9) : name; + name = name.EndsWith("Attribute") ? name[..^9] : name; return new { diff --git a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs index 48509f067b..671c528efb 100644 --- a/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs +++ b/OpenRA.Mods.Common/UtilityCommands/ImportLegacyMapCommand.cs @@ -231,7 +231,7 @@ namespace OpenRA.Mods.Common.UtilityCommands static string Truncate(string s, int maxLength) { - return s.Length <= maxLength ? s : s.Substring(0, maxLength); + return s.Length <= maxLength ? s : s[..maxLength]; } static string GetTileset(IniSection mapSection) diff --git a/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs b/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs index 3826b83825..2c7f506cbb 100644 --- a/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs +++ b/OpenRA.Mods.Common/Widgets/LabelWithHighlightWidget.cs @@ -51,13 +51,13 @@ namespace OpenRA.Mods.Common.Widgets if (highlightStart > 0 && highlightEnd > highlightStart) { // Normal line segment before highlight - var lineNormal = line.Substring(0, highlightStart); + var lineNormal = line[..highlightStart]; components.Add((lineNormal, false)); // Highlight line segment - var lineHighlight = line.Substring(highlightStart + 1, highlightEnd - highlightStart - 1); + var lineHighlight = line[(highlightStart + 1)..highlightEnd]; components.Add((lineHighlight, true)); - line = line.Substring(highlightEnd + 1); + line = line[(highlightEnd + 1)..]; } else { diff --git a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs index 37d23f54c0..ba15b1d315 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/AssetBrowserLogic.cs @@ -676,15 +676,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic name = source.Name; var compare = Platform.CurrentPlatform == PlatformType.Windows ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; if (name.StartsWith(modData.Manifest.Package.Name, compare)) - name = "$" + modData.Manifest.Id + "/" + name.Substring(modData.Manifest.Package.Name.Length + 1); + name = "$" + modData.Manifest.Id + "/" + name[(modData.Manifest.Package.Name.Length + 1)..]; else if (name.StartsWith(Platform.EngineDir, compare)) - name = "./" + name.Substring(Platform.EngineDir.Length); + name = "./" + name[Platform.EngineDir.Length..]; else if (name.StartsWith(Platform.SupportDir, compare)) - name = "^" + name.Substring(Platform.SupportDir.Length); + name = "^" + name[Platform.SupportDir.Length..]; } if (name.Length > 18) - name = "..." + name.Substring(name.Length - 15); + name = "..." + name[^15..]; return name; } diff --git a/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs index 62b8ac2c33..0fec9f8e10 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/DirectConnectLogic.cs @@ -35,8 +35,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic } else { - ipField.Text = text.Substring(0, last); - portField.Text = text.Substring(last + 1); + ipField.Text = text[..last]; + portField.Text = text[(last + 1)..]; } var joinButton = panel.Get("JOIN_BUTTON"); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs index 02ac98670e..06cb6b9fa8 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Lobby/LobbyUtils.cs @@ -205,8 +205,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic return (null, null); var split = input.IndexOf(token, StringComparison.Ordinal); - var first = split > 0 ? input.Substring(0, split) : input; - var second = split > 0 ? input.Substring(split + token.Length) : null; + var first = split > 0 ? input[..split] : input; + var second = split > 0 ? input[(split + token.Length)..] : null; return (first, second); } diff --git a/OpenRA.Mods.Common/Widgets/Logic/TabCompletionLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/TabCompletionLogic.cs index 3169f96268..93d1bdcd91 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/TabCompletionLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/TabCompletionLogic.cs @@ -44,7 +44,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic { prefix = "/"; suffix = ""; - toComplete = text.Substring(1); + toComplete = text[1..]; candidates = Commands.Where(x => x.StartsWith(toComplete, StringComparison.InvariantCultureIgnoreCase)).ToList(); } else if (Names != null) @@ -52,9 +52,9 @@ namespace OpenRA.Mods.Common.Widgets.Logic var oneWord = text.Contains(' '); if (oneWord) { - prefix = text.Substring(0, text.LastIndexOf(' ') + 1); + prefix = text[..(text.LastIndexOf(' ') + 1)]; suffix = ""; - toComplete = text.Substring(prefix.Length); + toComplete = text[prefix.Length..]; } else { diff --git a/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs b/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs index 033d62207f..5bc54bb3cf 100644 --- a/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs +++ b/OpenRA.Mods.Common/Widgets/TextFieldWidget.cs @@ -156,7 +156,7 @@ namespace OpenRA.Mods.Common.Widgets var minValue = int.MaxValue; for (var i = 0; i <= apparentText.Length; i++) { - var dist = Math.Abs(start + font.Measure(apparentText.Substring(0, i)).X - x); + var dist = Math.Abs(start + font.Measure(apparentText[..i]).X - x); if (dist > minValue) break; minValue = dist; @@ -168,12 +168,12 @@ namespace OpenRA.Mods.Common.Widgets int GetPrevWhitespaceIndex() { - return Text.Substring(0, CursorPosition).TrimEnd().LastIndexOf(' ') + 1; + return Text[..CursorPosition].TrimEnd().LastIndexOf(' ') + 1; } int GetNextWhitespaceIndex() { - var substr = Text.Substring(CursorPosition); + var substr = Text[CursorPosition..]; var substrTrimmed = substr.TrimStart(); var trimmedSpaces = substr.Length - substrTrimmed.Length; var nextWhitespace = substrTrimmed.IndexOf(' '); @@ -335,7 +335,7 @@ namespace OpenRA.Mods.Common.Widgets if (!isOSX && e.Modifiers.HasModifier(Modifiers.Ctrl) && CursorPosition > 0) { // Write directly to the Text backing field to avoid unnecessary validation - text = text.Substring(CursorPosition); + text = text[CursorPosition..]; CursorPosition = 0; ClearSelection(); OnTextEdited(); @@ -350,7 +350,7 @@ namespace OpenRA.Mods.Common.Widgets { var lowestIndex = selectionStartIndex < selectionEndIndex ? selectionStartIndex : selectionEndIndex; var highestIndex = selectionStartIndex < selectionEndIndex ? selectionEndIndex : selectionStartIndex; - Game.Renderer.SetClipboardText(Text.Substring(lowestIndex, highestIndex - lowestIndex)); + Game.Renderer.SetClipboardText(Text[lowestIndex..highestIndex]); RemoveSelectedText(); } @@ -363,7 +363,7 @@ namespace OpenRA.Mods.Common.Widgets { var lowestIndex = selectionStartIndex < selectionEndIndex ? selectionStartIndex : selectionEndIndex; var highestIndex = selectionStartIndex < selectionEndIndex ? selectionEndIndex : selectionStartIndex; - Game.Renderer.SetClipboardText(Text.Substring(lowestIndex, highestIndex - lowestIndex)); + Game.Renderer.SetClipboardText(Text[lowestIndex..highestIndex]); } break; @@ -377,7 +377,7 @@ namespace OpenRA.Mods.Common.Widgets { // Write directly to the Text backing field to avoid unnecessary validation if ((!isOSX && e.Modifiers.HasModifier(Modifiers.Ctrl)) || (isOSX && e.Modifiers.HasModifier(Modifiers.Alt))) - text = text.Substring(0, CursorPosition) + text.Substring(GetNextWhitespaceIndex()); + text = text[..CursorPosition] + text[GetNextWhitespaceIndex()..]; else if (isOSX && e.Modifiers.HasModifier(Modifiers.Meta)) text = text.Remove(CursorPosition); else @@ -400,12 +400,12 @@ namespace OpenRA.Mods.Common.Widgets if ((!isOSX && e.Modifiers.HasModifier(Modifiers.Ctrl)) || (isOSX && e.Modifiers.HasModifier(Modifiers.Alt))) { var prevWhitespace = GetPrevWhitespaceIndex(); - text = text.Substring(0, prevWhitespace) + text.Substring(CursorPosition); + text = text[..prevWhitespace] + text[CursorPosition..]; CursorPosition = prevWhitespace; } else if (isOSX && e.Modifiers.HasModifier(Modifiers.Meta)) { - text = text.Substring(CursorPosition); + text = text[CursorPosition..]; CursorPosition = 0; } else @@ -432,7 +432,7 @@ namespace OpenRA.Mods.Common.Widgets // Take only the first line of the clipboard contents var nl = clipboardText.IndexOf('\n'); if (nl > 0) - clipboardText = clipboardText.Substring(0, nl); + clipboardText = clipboardText[..nl]; clipboardText = clipboardText.Trim(); if (clipboardText.Length > 0) @@ -479,7 +479,7 @@ namespace OpenRA.Mods.Common.Widgets pasteLength = Math.Min(input.Length, MaxLength - Text.Length); // Write directly to the Text backing field to avoid repeating the invalid character validation - text = text.Insert(CursorPosition, input.Substring(0, pasteLength)); + text = text.Insert(CursorPosition, input[..pasteLength]); CursorPosition += pasteLength; ClearSelection(); OnTextEdited(); @@ -551,7 +551,7 @@ namespace OpenRA.Mods.Common.Widgets var pos = RenderOrigin; var textSize = font.Measure(apparentText); - var cursorPosition = font.Measure(apparentText.Substring(0, CursorPosition)); + var cursorPosition = font.Measure(apparentText[..CursorPosition]); var disabled = IsDisabled(); var hover = Ui.MouseOverWidget == this || Children.Any(c => c == Ui.MouseOverWidget); @@ -580,8 +580,8 @@ namespace OpenRA.Mods.Common.Widgets { var visualSelectionStartIndex = selectionStartIndex < selectionEndIndex ? selectionStartIndex : selectionEndIndex; var visualSelectionEndIndex = selectionStartIndex < selectionEndIndex ? selectionEndIndex : selectionStartIndex; - var highlightStartX = font.Measure(apparentText.Substring(0, visualSelectionStartIndex)).X; - var highlightEndX = font.Measure(apparentText.Substring(0, visualSelectionEndIndex)).X; + var highlightStartX = font.Measure(apparentText[..visualSelectionStartIndex]).X; + var highlightEndX = font.Measure(apparentText[..visualSelectionEndIndex]).X; WidgetUtils.FillRectWithColor( new Rectangle(textPos.X + highlightStartX, textPos.Y, highlightEndX - highlightStartX, Bounds.Height - verticalMargin * 2), TextColorHighlight); diff --git a/OpenRA.Mods.Common/Widgets/WidgetUtils.cs b/OpenRA.Mods.Common/Widgets/WidgetUtils.cs index c9bcdda992..4cd449df5c 100644 --- a/OpenRA.Mods.Common/Widgets/WidgetUtils.cs +++ b/OpenRA.Mods.Common/Widgets/WidgetUtils.cs @@ -249,7 +249,7 @@ namespace OpenRA.Mods.Common.Widgets if (spaceIndex == -1) break; - var fragmentWidth = font.Measure(line.Substring(0, spaceIndex)).X; + var fragmentWidth = font.Measure(line[..spaceIndex]).X; if (fragmentWidth > width) break; @@ -258,8 +258,8 @@ namespace OpenRA.Mods.Common.Widgets if (start > 0) { - lines[i] = line.Substring(0, start - 1); - lines.Insert(i + 1, line.Substring(start)); + lines[i] = line[..(start - 1)]; + lines.Insert(i + 1, line[start..]); } } @@ -278,7 +278,7 @@ namespace OpenRA.Mods.Common.Widgets var trimmed = text; while (trimmedWidth > width && trimmed.Length > 3) { - trimmed = text.Substring(0, trimmed.Length - 4) + "..."; + trimmed = text[..(trimmed.Length - 4)] + "..."; trimmedWidth = font.Measure(trimmed).X; } diff --git a/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs b/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs index 848540af3d..b2ebba61ce 100644 --- a/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs +++ b/OpenRA.Platforms.Default/Sdl2PlatformWindow.cs @@ -209,7 +209,7 @@ namespace OpenRA.Platforms.Default var lines = p.StandardOutput.ReadToEnd().Split('\n'); foreach (var line in lines) - if (line.StartsWith("Xft.dpi") && int.TryParse(line.Substring(8), out var dpi)) + if (line.StartsWith("Xft.dpi") && int.TryParse(line[8..], out var dpi)) windowScale = dpi / 96f; } catch { }