From 77ce2e198014772a336f6e46506884074498efc8 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 20 Dec 2020 23:21:55 -0800 Subject: [PATCH] fix(core): Optimizes strings / .NET 5 compatibility changes (#354) - [X] Removes some string allocations (e.g. split) - [X] Optimizes some collections - [X] Converts insensitive to extension methods of built-ins. - [X] Adds ordinal (case sensitive) string helpers - [X] Fixes conditionals for in-game commands so they use Ordinal comparisons. - [X] Replaces ToLower.Contains with InsensitiveContains - [X] Adds ValueStringBuilder - [X] Implements ValueStringBuilder in a few places where it makes sense - [X] Removes the redundant Wrap function and replaces it with an optimized version - [X] Fixes list conversions in Utility Closes #351 Bumps release version --- .../BenchmarkStringHelpers.cs | 87 +++++ Projects/Benchmarks/Benchmarks.csproj | 1 + .../FeatureFlags/BenchmarkFeatureFlags.cs | 2 +- Projects/Benchmarks/Program.cs | 4 +- .../Buffers/CircularBufferReaderTests.cs | 118 ------ .../Buffers/CircularBufferWriterTests.cs | 92 ----- .../Buffers/CircularBufferReaderTests.cs | 102 +++++ .../Buffers/CircularBufferWriterTests.cs | 82 ++++ .../Tests/Buffers/ValueStringBuilderTests.cs | 21 + .../Tests/Utility/StringHelperTests.cs | 112 +++++- Projects/Server/Buffers/ValueStringBuilder.cs | 363 ++++++++++++++++++ Projects/Server/ClientVersion.cs | 25 +- Projects/Server/Commands.cs | 4 +- .../Configuration/ServerConfiguration.cs | 2 +- Projects/Server/Geometry/Point2D.cs | 2 +- Projects/Server/Geometry/Point3D.cs | 2 +- Projects/Server/Geometry/Rectangle2D.cs | 2 +- Projects/Server/Geometry/WorldLocation.cs | 2 +- Projects/Server/Guild.cs | 19 +- Projects/Server/Insensitive.cs | 24 -- Projects/Server/Items/Container.cs | 2 +- .../NullableStructSerializerFactory.cs | 5 +- Projects/Server/Main.cs | 6 +- Projects/Server/Map.cs | 4 +- Projects/Server/Mobiles/Body.cs | 2 +- Projects/Server/Mobiles/Mobile.cs | 4 +- Projects/Server/MultiData.cs | 4 +- Projects/Server/Network/NetState/NetState.cs | 4 +- .../Network/Packets/IncomingPlayerPackets.cs | 16 +- Projects/Server/Race.cs | 2 +- Projects/Server/Serialization/BufferWriter.cs | 2 +- .../Utilities/InsensitiveStringHelpers.cs | 102 +++++ .../Server/Utilities/OrdinalStringHelpers.cs | 100 +++++ Projects/Server/Utilities/StringHelpers.cs | 245 ++++++++++++ Projects/Server/Utilities/Utility.cs | 86 ++--- Projects/Server/World/World.cs | 4 +- .../Security/PasswordProtectionTest.cs | 0 .../Tests/Firewall/FirewallEntryTests.cs | 20 + .../Network/Packets/ArrowPacketTests.cs | 0 .../Network/Packets/ArrowPackets.cs | 0 Projects/UOContent/Accounting/Account.cs | 2 +- .../UOContent/Accounting/AccountHandler.cs | 8 +- Projects/UOContent/Accounting/Firewall.cs | 144 ++----- .../Security/MD5PasswordProtection.cs | 2 +- .../Security/SHA1PasswordProtection.cs | 2 +- .../Security/SHA2PasswordProtection.cs | 2 +- Projects/UOContent/Commands/Batch.cs | 2 +- Projects/UOContent/Commands/Docs.cs | 41 +- .../Commands/Generic/Commands/Commands.cs | 2 +- .../Commands/Generic/Commands/Interface.cs | 2 +- .../Compilers/ConditionalCompiler.cs | 72 +++- .../Generic/Extensions/SortExtension.cs | 2 +- .../Implementors/BaseCommandImplementor.cs | 5 +- .../Generic/Implementors/ObjectConditional.cs | 12 +- Projects/UOContent/Commands/Handlers.cs | 10 +- Projects/UOContent/Commands/HelpInfo.cs | 16 +- Projects/UOContent/Commands/Logging.cs | 2 +- .../UOContent/Commands/Object Creation/Add.cs | 6 +- .../Commands/Object Creation/AddGump.cs | 2 +- .../Object Creation/Categorization.cs | 2 +- .../Commands/Object Creation/Decorate.cs | 280 +++++++------- .../Commands/Object Creation/DecorateMag.cs | 280 +++++++------- Projects/UOContent/Commands/Properties.cs | 6 +- Projects/UOContent/Commands/SignParser.cs | 2 +- Projects/UOContent/Commands/Statics.cs | 3 +- .../Engines/BulkOrders/SmallBulkEntry.cs | 2 +- Projects/UOContent/Engines/Chat/Channel.cs | 2 +- .../Engines/Chat/ChatActionHandlers.cs | 8 +- .../UOContent/Engines/ConPVP/DuelContext.cs | 10 +- .../Engines/ConPVP/Games/DoubleDom.cs | 12 +- .../ConPVP/Gumps/TournamentBracketGump.cs | 8 +- .../UOContent/Engines/Ethics/Core/Ethic.cs | 4 +- .../Engines/Factions/Core/Faction.cs | 2 +- .../UOContent/Engines/Factions/Core/Town.cs | 2 +- .../Mobiles/Guards/BaseFactionGuard.cs | 18 +- .../UOContent/Engines/Help/PageQueueGump.cs | 2 +- .../Engines/MLQuests/MLQuestSystem.cs | 2 +- .../UOContent/Engines/Pathing/FastMovement.cs | 4 +- .../UOContent/Engines/Spawners/BaseSpawner.cs | 2 +- Projects/UOContent/Gumps/AdminGump.cs | 87 +++-- .../Gumps/Guilds/GuildDeclareWarPrompt.cs | 3 +- .../UOContent/Gumps/Guilds/GuildListGump.cs | 2 +- .../Guilds/New Guild System/BaseGuildGump.cs | 2 +- .../Guilds/New Guild System/DiplomacyGump.cs | 10 +- .../New Guild System/GuildMemberInfoGump.cs | 2 +- .../New Guild System/GuildRosterGump.cs | 6 +- Projects/UOContent/Gumps/HouseGump.cs | 71 +--- Projects/UOContent/Gumps/HouseGumpAOS.cs | 71 +--- Projects/UOContent/Gumps/Props/PropsGump.cs | 2 +- Projects/UOContent/Gumps/Props/SetBodyGump.cs | 2 +- Projects/UOContent/Gumps/WhoGump.cs | 4 +- .../Halloween/2006/Engines/TrickOrTreat.cs | 2 +- Projects/UOContent/Items/Body Parts/Head.cs | 6 +- Projects/UOContent/Items/Books/BaseBook.cs | 3 +- Projects/UOContent/Items/Misc/Teleporter.cs | 5 +- .../House Raffle/HouseRaffleManagementGump.cs | 4 +- Projects/UOContent/Misc/AutoSave.cs | 4 +- Projects/UOContent/Misc/InhumanSpeech.cs | 93 ++--- Projects/UOContent/Misc/NameVerification.cs | 4 +- Projects/UOContent/Misc/RenameRequests.cs | 2 +- Projects/UOContent/Misc/ResourceInfo.cs | 8 +- Projects/UOContent/Misc/ShardPoller.cs | 2 +- Projects/UOContent/Misc/ShrinkTable.cs | 2 +- Projects/UOContent/Misc/Titles.cs | 46 +-- Projects/UOContent/Mobiles/AI/BaseAI.cs | 4 +- Projects/UOContent/Mobiles/BaseCreature.cs | 4 +- .../UOContent/Mobiles/Townfolk/TownCrier.cs | 2 +- .../UOContent/Mobiles/Vendors/BaseVendor.cs | 28 +- .../Mobiles/Vendors/NPC/AnimalTrainer.cs | 4 +- .../NPC/Guildmasters/BaseGuildmaster.cs | 2 +- .../Mobiles/Vendors/PlayerBarkeeper.cs | 2 +- .../UOContent/Mobiles/Vendors/PlayerVendor.cs | 2 +- Projects/UOContent/Regions/HouseRegion.cs | 2 +- Projects/UOContent/Skills/ForensicEval.cs | 7 +- .../SpecialSystems/Engines/TestCenter.cs | 64 +-- .../UOContent/Spells/Base/SpellRegistry.cs | 2 +- Projects/UOContent/UOContent.csproj | 1 + 117 files changed, 2000 insertions(+), 1226 deletions(-) create mode 100644 Projects/Benchmarks/BenchmarkUtilities/BenchmarkStringHelpers.cs delete mode 100644 Projects/Server.Tests/Buffers/CircularBufferReaderTests.cs delete mode 100644 Projects/Server.Tests/Buffers/CircularBufferWriterTests.cs create mode 100644 Projects/Server.Tests/Tests/Buffers/CircularBufferReaderTests.cs create mode 100644 Projects/Server.Tests/Tests/Buffers/CircularBufferWriterTests.cs create mode 100644 Projects/Server.Tests/Tests/Buffers/ValueStringBuilderTests.cs create mode 100644 Projects/Server/Buffers/ValueStringBuilder.cs delete mode 100644 Projects/Server/Insensitive.cs create mode 100644 Projects/Server/Utilities/InsensitiveStringHelpers.cs create mode 100644 Projects/Server/Utilities/OrdinalStringHelpers.cs create mode 100644 Projects/Server/Utilities/StringHelpers.cs rename Projects/UOContent.Tests/{ => Tests}/Accounting/Security/PasswordProtectionTest.cs (100%) create mode 100644 Projects/UOContent.Tests/Tests/Firewall/FirewallEntryTests.cs rename Projects/UOContent.Tests/{ => Tests}/Network/Packets/ArrowPacketTests.cs (100%) rename Projects/UOContent.Tests/{ => Tests}/Network/Packets/ArrowPackets.cs (100%) diff --git a/Projects/Benchmarks/BenchmarkUtilities/BenchmarkStringHelpers.cs b/Projects/Benchmarks/BenchmarkUtilities/BenchmarkStringHelpers.cs new file mode 100644 index 000000000..01cf5bb3c --- /dev/null +++ b/Projects/Benchmarks/BenchmarkUtilities/BenchmarkStringHelpers.cs @@ -0,0 +1,87 @@ +using System.Buffers; +using System.Text; +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; +using Server.Buffers; + +namespace Benchmarks.BenchmarkUtilities +{ + [MemoryDiagnoser] + [SimpleJob(RuntimeMoniker.NetCoreApp50)] + public class BenchmarkStringHelpers + { + private readonly string[] names = + { + "Kamron", "Owyn", "Luthius", "Jaedan", "Vorspire", "other people", + "Kamron-2", "Owyn-2", "Luthius-2", "Jaedan-2", "Vorspire-2", "other people too" + }; + + private int length; + + [GlobalSetup] + public void Setup() + { + var chrs = ArrayPool.Shared.Rent(65535); + ArrayPool.Shared.Return(chrs); + length = 0; + + for (int i = 0; i < names.Length; i++) + { + length += names.Length; + } + + length += 2 * (names.Length - 1) + 3; + } + + [Benchmark] + public string BenchmarkStringBuilder() + { + var sb = new StringBuilder(); + for (var i = 0; i < names.Length; i++) + { + if (i > 0) + { + sb.Append(i == names.Length - 1 ? ", and" : ", "); + } + + sb.Append(names[i]); + } + + return sb.ToString(); + } + + [Benchmark] + public string BenchmarkValueStringBuilderWithStack() + { + using var sb = new ValueStringBuilder(stackalloc char[length]); + for (var i = 0; i < names.Length; i++) + { + if (i > 0) + { + sb.Append(i == names.Length - 1 ? ", and" : ", "); + } + + sb.Append(names[i]); + } + + return sb.ToString(); + } + + [Benchmark] + public string BenchmarkValueStringBuilderWithRentedBuffer() + { + using var sb = new ValueStringBuilder(stackalloc char[32]); + for (var i = 0; i < names.Length; i++) + { + if (i > 0) + { + sb.Append(i == names.Length - 1 ? ", and" : ", "); + } + + sb.Append(names[i]); + } + + return sb.ToString(); + } + } +} diff --git a/Projects/Benchmarks/Benchmarks.csproj b/Projects/Benchmarks/Benchmarks.csproj index 1d9434d67..e0ab71eea 100644 --- a/Projects/Benchmarks/Benchmarks.csproj +++ b/Projects/Benchmarks/Benchmarks.csproj @@ -6,6 +6,7 @@ x64 9 true + true diff --git a/Projects/Benchmarks/FeatureFlags/BenchmarkFeatureFlags.cs b/Projects/Benchmarks/FeatureFlags/BenchmarkFeatureFlags.cs index 84009d385..fcfffebbe 100644 --- a/Projects/Benchmarks/FeatureFlags/BenchmarkFeatureFlags.cs +++ b/Projects/Benchmarks/FeatureFlags/BenchmarkFeatureFlags.cs @@ -13,7 +13,7 @@ using Server.Items; namespace Benchmarks { - [SimpleJob(RuntimeMoniker.NetCoreApp31)] + [SimpleJob(RuntimeMoniker.NetCoreApp50)] public class BenchmarkFeatureFlags { public Dictionary> m_Dictionary; diff --git a/Projects/Benchmarks/Program.cs b/Projects/Benchmarks/Program.cs index a9bf8cccb..636bb412b 100644 --- a/Projects/Benchmarks/Program.cs +++ b/Projects/Benchmarks/Program.cs @@ -1,4 +1,5 @@ using BenchmarkDotNet.Running; +using Benchmarks.BenchmarkUtilities; namespace Benchmarks { @@ -8,7 +9,8 @@ namespace Benchmarks { // var featureFlags = BenchmarkRunner.Run(); // var packetConstruction = BenchmarkRunner.Run(); - var broadcast = BenchmarkRunner.Run(); + // var broadcast = BenchmarkRunner.Run(); + var stringHelpers = BenchmarkRunner.Run(); } } } diff --git a/Projects/Server.Tests/Buffers/CircularBufferReaderTests.cs b/Projects/Server.Tests/Buffers/CircularBufferReaderTests.cs deleted file mode 100644 index 3b2e2048e..000000000 --- a/Projects/Server.Tests/Buffers/CircularBufferReaderTests.cs +++ /dev/null @@ -1,118 +0,0 @@ -using System; -using System.IO; -using System.Text; -using Server.Network; -using Xunit; - -namespace Server.Tests.Network -{ - public class CircularBufferReaderTests - { - [Theory, InlineData("Test String", "us-ascii", false, -1, 1024, 1024, 0), - InlineData("Test String", "utf-u", false, -1, 1024, 1024, 0), - InlineData("Test String", "utf-16BE", false, -1, 1024, 1024, 0), - InlineData("Test String", "utf-16", false, -1, 1024, 1024, 0), - InlineData("Test String", "us-ascii", false, -1, 1024, 1024, 1030), - InlineData("Test String", "utf-u", false, -1, 1024, 1024, 1030), - InlineData("Test String", "utf-16BE", false, -1, 1024, 1024, 1030), - InlineData("Test String", "utf-16", false, -1, 1024, 1024, 1030), - InlineData("Test String", "us-ascii", false, -1, 1024, 1024, 1020), - InlineData("Test String", "utf-u", false, -1, 1024, 1024, 1020), - InlineData("Test String", "utf-16BE", false, -1, 1024, 1024, 1020), - InlineData("Test String", "utf-16", false, -1, 1024, 1024, 1020), - InlineData("Test String", "us-ascii", false, 8, 1024, 1024, 0), - InlineData("Test String", "utf-u", false, 8, 1024, 1024, 0), - InlineData("Test String", "utf-16BE", false, 8, 1024, 1024, 0), - InlineData("Test String", "utf-16", false, 8, 1024, 1024, 0), - InlineData("Test String", "us-ascii", false, 8, 1024, 1024, 1030), - InlineData("Test String", "utf-u", false, 8, 1024, 1024, 1030), - InlineData("Test String", "utf-16BE", false, 8, 1024, 1024, 1030), - InlineData("Test String", "utf-16", false, 8, 1024, 1024, 1030), - InlineData("Test String", "us-ascii", false, 8, 1024, 1024, 1020), - InlineData("Test String", "utf-u", false, 8, 1024, 1024, 1020), - InlineData("Test String", "utf-16BE", false, 8, 1024, 1024, 1020), - InlineData("Test String", "utf-16", false, 8, 1024, 1024, 1020), - InlineData("Test String", "us-ascii", false, 20, 1024, 1024, 0), - InlineData("Test String", "utf-u", false, 20, 1024, 1024, 0), - InlineData("Test String", "utf-16BE", false, 20, 1024, 1024, 0), - InlineData("Test String", "utf-16", false, 20, 1024, 1024, 0), - InlineData("Test String", "us-ascii", false, 20, 1024, 1024, 1030), - InlineData("Test String", "utf-u", false, 20, 1024, 1024, 1030), - InlineData("Test String", "utf-16BE", false, 20, 1024, 1024, 1030), - InlineData("Test String", "utf-16", false, 20, 1024, 1024, 1030), - InlineData("Test String", "us-ascii", false, 20, 1024, 1024, 1020), - InlineData("Test String", "utf-u", false, 20, 1024, 1024, 1020), - InlineData("Test String", "utf-16BE", false, 20, 1024, 1024, 1020), - InlineData("Test String", "utf-16", false, 20, 1024, 1024, 1020)] - // First only, beginning - - // Second only - - // Split - - // First only, beginning, fixed length smaller - - // Second only, fixed length smaller - - // Split, fixed length smaller - - // First only, beginning, fixed length bigger - - // Second only, fixed length bigger - - // Split, fixed length bigger - public void TestReadString( - string value, - string encodingStr, - bool isSafe, - int fixedLength, - int firstSize, - int secondSize, - int offset - ) - { - Span buffer = stackalloc byte[firstSize + secondSize]; - buffer.Clear(); - - var encoding = EncodingHelpers.GetEncoding(encodingStr); - - var strLength = fixedLength > -1 ? Math.Min(value.Length, fixedLength) : value.Length; - var chars = value.AsSpan(0, strLength); -; - encoding.GetBytes(chars, buffer.Slice(offset)); - - var reader = new CircularBufferReader(buffer.Slice(0, firstSize), buffer.Slice(firstSize)); - reader.Seek(offset, SeekOrigin.Begin); - - var actual = reader.ReadString(encoding, isSafe, fixedLength); - - Assert.Equal(value.Substring(0, strLength), actual); - } - - [Fact] - public void TestReadStringBetween() - { - Span expected = stackalloc byte[19]; - expected[0] = 0x1; - expected[1] = 0x1; - expected[2] = 0x1; - expected[3] = 0x1; - Encoding.ASCII.GetBytes("TestString", expected.Slice(4, 10)); - expected[14] = 0x0; // Null - expected[15] = 0x2; - expected[16] = 0x2; - expected[17] = 0x2; - expected[18] = 0x2; - - var reader = new CircularBufferReader(expected, stackalloc byte[0]); - - var num1 = reader.ReadInt32(); - var str = reader.ReadAscii(); - var num2 = reader.ReadInt32(); - - Assert.Equal(0x01010101, num1); - Assert.Equal("TestString", str); - Assert.Equal(0x02020202, num2); - } - } -} diff --git a/Projects/Server.Tests/Buffers/CircularBufferWriterTests.cs b/Projects/Server.Tests/Buffers/CircularBufferWriterTests.cs deleted file mode 100644 index f76726359..000000000 --- a/Projects/Server.Tests/Buffers/CircularBufferWriterTests.cs +++ /dev/null @@ -1,92 +0,0 @@ -using System; -using System.Buffers; -using System.IO; -using Xunit; - -namespace Server.Tests.Buffers -{ - public class CircularBufferWriterTests - { - [Theory, InlineData("Test String", "us-ascii", -1, 1024, 1024, 0), - InlineData("Test String", "utf-8", -1, 1024, 1024, 0), InlineData("Test String", "utf-16BE", -1, 1024, 1024, 0), - InlineData("Test String", "utf-16", -1, 1024, 1024, 0), InlineData("Test String", "us-ascii", -1, 1024, 1024, 1030), - InlineData("Test String", "utf-8", -1, 1024, 1024, 1030), - InlineData("Test String", "utf-16BE", -1, 1024, 1024, 1030), - InlineData("Test String", "utf-16", -1, 1024, 1024, 1030), - InlineData("Test String", "us-ascii", -1, 1024, 1024, 1020), - InlineData("Test String", "utf-8", -1, 1024, 1024, 1020), - InlineData("Test String", "utf-16BE", -1, 1024, 1024, 1020), - InlineData("Test String", "utf-16", -1, 1024, 1024, 1020), InlineData("Test String", "us-ascii", 8, 1024, 1024, 0), - InlineData("Test String", "utf-16BE", 8, 1024, 1024, 0), InlineData("Test String", "utf-16", 8, 1024, 1024, 0), - InlineData("Test String", "us-ascii", 8, 1024, 1024, 1030), - InlineData("Test String", "utf-16BE", 8, 1024, 1024, 1030), - InlineData("Test String", "utf-16", 8, 1024, 1024, 1030), - InlineData("Test String", "us-ascii", 8, 1024, 1024, 1020), - InlineData("Test String", "utf-16BE", 8, 1024, 1024, 1020), - InlineData("Test String", "utf-16", 8, 1024, 1024, 1020), InlineData("Test String", "us-ascii", 20, 1024, 1024, 0), - InlineData("Test String", "utf-16BE", 20, 1024, 1024, 0), InlineData("Test String", "utf-16", 20, 1024, 1024, 0), - InlineData("Test String", "us-ascii", 20, 1024, 1024, 1030), - InlineData("Test String", "utf-16BE", 20, 1024, 1024, 1030), - InlineData("Test String", "utf-16", 20, 1024, 1024, 1030), - InlineData("Test String", "us-ascii", 20, 1024, 1024, 1020), - InlineData("Test String", "utf-16BE", 20, 1024, 1024, 1020), - InlineData("Test String", "utf-16", 20, 1024, 1024, 1020)] - // First only, beginning - - // Second only - - // Split - - // First only, beginning, fixed length smaller - - // Second only, fixed length smaller - - // Split, fixed length smaller - - // First only, beginning, fixed length bigger - - // Second only, fixed length bigger - - // Split, fixed length bigger - public void TestWriteString( - string value, - string encodingStr, - int fixedLength, - int firstSize, - int secondSize, - int offset - ) - { - Span buffer = stackalloc byte[firstSize + secondSize]; - buffer.Clear(); - - var encoding = EncodingHelpers.GetEncoding(encodingStr); - var strLength = fixedLength > -1 ? Math.Min(value.Length, fixedLength) : value.Length; - var chars = value.AsSpan(0, strLength); - - var writer = new CircularBufferWriter(buffer.Slice(0, firstSize), buffer.Slice(firstSize)); - writer.Seek(offset, SeekOrigin.Begin); - writer.WriteString(chars, encoding); - - if (offset > 0) - { - Span testEmpty = stackalloc byte[offset]; - testEmpty.Clear(); - AssertThat.Equal(buffer.Slice(0, offset), testEmpty); - } - - Span expectedStr = stackalloc byte[encoding.GetByteCount(chars)]; - encoding.GetBytes(chars, expectedStr.Slice(0)); - - AssertThat.Equal(buffer.Slice(offset, expectedStr.Length), expectedStr); - offset += expectedStr.Length; - - if (offset < buffer.Length) - { - Span testEmpty = stackalloc byte[buffer.Length - offset]; - testEmpty.Clear(); - AssertThat.Equal(buffer.Slice(offset), testEmpty); - } - } - } -} diff --git a/Projects/Server.Tests/Tests/Buffers/CircularBufferReaderTests.cs b/Projects/Server.Tests/Tests/Buffers/CircularBufferReaderTests.cs new file mode 100644 index 000000000..00abc253a --- /dev/null +++ b/Projects/Server.Tests/Tests/Buffers/CircularBufferReaderTests.cs @@ -0,0 +1,102 @@ +using System; +using System.IO; +using System.Text; +using Server.Network; +using Xunit; + +namespace Server.Tests.Network +{ + public class CircularBufferReaderTests + { + [Theory] + [InlineData("Test String", "us-ascii", false, -1, 1024, 1024, 0)] + [InlineData("Test String", "utf-u", false, -1, 1024, 1024, 0)] + [InlineData("Test String", "utf-16BE", false, -1, 1024, 1024, 0)] + [InlineData("Test String", "utf-16", false, -1, 1024, 1024, 0)] + [InlineData("Test String", "us-ascii", false, -1, 1024, 1024, 1030)] + [InlineData("Test String", "utf-u", false, -1, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16BE", false, -1, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16", false, -1, 1024, 1024, 1030)] + [InlineData("Test String", "us-ascii", false, -1, 1024, 1024, 1020)] + [InlineData("Test String", "utf-u", false, -1, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16BE", false, -1, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16", false, -1, 1024, 1024, 1020)] + [InlineData("Test String", "us-ascii", false, 8, 1024, 1024, 0)] + [InlineData("Test String", "utf-u", false, 8, 1024, 1024, 0)] + [InlineData("Test String", "utf-16BE", false, 8, 1024, 1024, 0)] + [InlineData("Test String", "utf-16", false, 8, 1024, 1024, 0)] + [InlineData("Test String", "us-ascii", false, 8, 1024, 1024, 1030)] + [InlineData("Test String", "utf-u", false, 8, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16BE", false, 8, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16", false, 8, 1024, 1024, 1030)] + [InlineData("Test String", "us-ascii", false, 8, 1024, 1024, 1020)] + [InlineData("Test String", "utf-u", false, 8, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16BE", false, 8, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16", false, 8, 1024, 1024, 1020)] + [InlineData("Test String", "us-ascii", false, 20, 1024, 1024, 0)] + [InlineData("Test String", "utf-u", false, 20, 1024, 1024, 0)] + [InlineData("Test String", "utf-16BE", false, 20, 1024, 1024, 0)] + [InlineData("Test String", "utf-16", false, 20, 1024, 1024, 0)] + [InlineData("Test String", "us-ascii", false, 20, 1024, 1024, 1030)] + [InlineData("Test String", "utf-u", false, 20, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16BE", false, 20, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16", false, 20, 1024, 1024, 1030)] + [InlineData("Test String", "us-ascii", false, 20, 1024, 1024, 1020)] + [InlineData("Test String", "utf-u", false, 20, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16BE", false, 20, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16", false, 20, 1024, 1024, 1020)] + public void TestReadString( + string value, + string encodingStr, + bool isSafe, + int fixedLength, + int firstSize, + int secondSize, + int offset + ) + { + Span buffer = stackalloc byte[firstSize + secondSize]; + buffer.Clear(); + + var encoding = EncodingHelpers.GetEncoding(encodingStr); + + var strLength = fixedLength > -1 ? Math.Min(value.Length, fixedLength) : value.Length; + var chars = value.AsSpan(0, strLength); +; + encoding.GetBytes(chars, buffer.Slice(offset)); + + var reader = new CircularBufferReader(buffer.Slice(0, firstSize), buffer.Slice(firstSize)); + reader.Seek(offset, SeekOrigin.Begin); + + var actual = reader.ReadString(encoding, isSafe, fixedLength); + + Assert.Equal(value.Substring(0, strLength), actual); + } + + [Fact] + public void TestReadStringBetween() + { + Span expected = stackalloc byte[19]; + expected[0] = 0x1; + expected[1] = 0x1; + expected[2] = 0x1; + expected[3] = 0x1; + Encoding.ASCII.GetBytes("TestString", expected.Slice(4, 10)); + expected[14] = 0x0; // Null + expected[15] = 0x2; + expected[16] = 0x2; + expected[17] = 0x2; + expected[18] = 0x2; + + var reader = new CircularBufferReader(expected, stackalloc byte[0]); + + var num1 = reader.ReadInt32(); + var str = reader.ReadAscii(); + var num2 = reader.ReadInt32(); + + Assert.Equal(0x01010101, num1); + Assert.Equal("TestString", str); + Assert.Equal(0x02020202, num2); + } + } +} diff --git a/Projects/Server.Tests/Tests/Buffers/CircularBufferWriterTests.cs b/Projects/Server.Tests/Tests/Buffers/CircularBufferWriterTests.cs new file mode 100644 index 000000000..f57f5ef24 --- /dev/null +++ b/Projects/Server.Tests/Tests/Buffers/CircularBufferWriterTests.cs @@ -0,0 +1,82 @@ +using System; +using System.Buffers; +using System.IO; +using Xunit; + +namespace Server.Tests.Buffers +{ + public class CircularBufferWriterTests + { + [Theory] + [InlineData("Test String", "us-ascii", -1, 1024, 1024, 0)] + [InlineData("Test String", "utf-8", -1, 1024, 1024, 0)] + [InlineData("Test String", "utf-16BE", -1, 1024, 1024, 0)] + [InlineData("Test String", "utf-16", -1, 1024, 1024, 0)] + [InlineData("Test String", "us-ascii", -1, 1024, 1024, 1030)] + [InlineData("Test String", "utf-8", -1, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16BE", -1, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16", -1, 1024, 1024, 1030)] + [InlineData("Test String", "us-ascii", -1, 1024, 1024, 1020)] + [InlineData("Test String", "utf-8", -1, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16BE", -1, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16", -1, 1024, 1024, 1020)] + [InlineData("Test String", "us-ascii", 8, 1024, 1024, 0)] + [InlineData("Test String", "utf-16BE", 8, 1024, 1024, 0)] + [InlineData("Test String", "utf-16", 8, 1024, 1024, 0)] + [InlineData("Test String", "us-ascii", 8, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16BE", 8, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16", 8, 1024, 1024, 1030)] + [InlineData("Test String", "us-ascii", 8, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16BE", 8, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16", 8, 1024, 1024, 1020)] + [InlineData("Test String", "us-ascii", 20, 1024, 1024, 0)] + [InlineData("Test String", "utf-16BE", 20, 1024, 1024, 0)] + [InlineData("Test String", "utf-16", 20, 1024, 1024, 0)] + [InlineData("Test String", "us-ascii", 20, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16BE", 20, 1024, 1024, 1030)] + [InlineData("Test String", "utf-16", 20, 1024, 1024, 1030)] + [InlineData("Test String", "us-ascii", 20, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16BE", 20, 1024, 1024, 1020)] + [InlineData("Test String", "utf-16", 20, 1024, 1024, 1020)] + public void TestWriteString( + string value, + string encodingStr, + int fixedLength, + int firstSize, + int secondSize, + int offset + ) + { + Span buffer = stackalloc byte[firstSize + secondSize]; + buffer.Clear(); + + var encoding = EncodingHelpers.GetEncoding(encodingStr); + var strLength = fixedLength > -1 ? Math.Min(value.Length, fixedLength) : value.Length; + var chars = value.AsSpan(0, strLength); + + var writer = new CircularBufferWriter(buffer.Slice(0, firstSize), buffer.Slice(firstSize)); + writer.Seek(offset, SeekOrigin.Begin); + writer.WriteString(chars, encoding); + + if (offset > 0) + { + Span testEmpty = stackalloc byte[offset]; + testEmpty.Clear(); + AssertThat.Equal(buffer.Slice(0, offset), testEmpty); + } + + Span expectedStr = stackalloc byte[encoding.GetByteCount(chars)]; + encoding.GetBytes(chars, expectedStr.Slice(0)); + + AssertThat.Equal(buffer.Slice(offset, expectedStr.Length), expectedStr); + offset += expectedStr.Length; + + if (offset < buffer.Length) + { + Span testEmpty = stackalloc byte[buffer.Length - offset]; + testEmpty.Clear(); + AssertThat.Equal(buffer.Slice(offset), testEmpty); + } + } + } +} diff --git a/Projects/Server.Tests/Tests/Buffers/ValueStringBuilderTests.cs b/Projects/Server.Tests/Tests/Buffers/ValueStringBuilderTests.cs new file mode 100644 index 000000000..ccd9ced9e --- /dev/null +++ b/Projects/Server.Tests/Tests/Buffers/ValueStringBuilderTests.cs @@ -0,0 +1,21 @@ +using Server.Buffers; +using Xunit; + +namespace Server.Tests.Buffers +{ + public class ValueStringBuilderTests + { + [Theory] + [InlineData("Admin Kamron", "Kamron", 0, 6)] + [InlineData("Admin Kamron", "Admin ron", 6, 3)] + [InlineData("Admin Kamron", "Admin", 5, 7)] + public void TestRemove(string original, string removed, int startIndex, int length) + { + using var sb = new ValueStringBuilder(stackalloc char[64]); + sb.Append(original); + sb.Remove(startIndex, length); + + Assert.Equal(removed, sb.ToString()); + } + } +} diff --git a/Projects/Server.Tests/Tests/Utility/StringHelperTests.cs b/Projects/Server.Tests/Tests/Utility/StringHelperTests.cs index 38f25285c..5bb5e1d24 100644 --- a/Projects/Server.Tests/Tests/Utility/StringHelperTests.cs +++ b/Projects/Server.Tests/Tests/Utility/StringHelperTests.cs @@ -1,16 +1,124 @@ +using System; +using System.Collections.Generic; using Xunit; namespace Server.Tests { public class TestStringHelpers { - [Theory, InlineData(null, "default value", "default value"), InlineData("", "default value", "default value"), - InlineData("this is a valid string", "default value", "this is a valid string")] + [Theory] + [InlineData(null, "default value", "default value")] + [InlineData("", "default value", "default value")] + [InlineData("this is a valid string", "default value", "this is a valid string")] public void TestIsNullOrDefault(string value, string defaultValue, string expected) { var actual = value.DefaultIfNullOrEmpty(defaultValue); Assert.Equal(expected, actual); } + + [Theory] + [InlineData("this is not capitalized", "This Is Not Capitalized")] + [InlineData("", "")] + [InlineData(null, null)] + [InlineData("nospaceshere", "Nospaceshere")] + [InlineData("harry the fireman", "Harry the Fireman")] + public void TestCapitalize(string original, string capitalized) + { + var actual = original.Capitalize(); + + Assert.Equal(capitalized, actual); + } + + [Theory] + [InlineData("we are testing removing spaces", " ", "wearetestingremovingspaces", StringComparison.Ordinal)] + [InlineData("", " ", "", StringComparison.Ordinal)] + [InlineData(null, null, null, StringComparison.Ordinal)] + public void TestRemove(string original, string separator, string removed, StringComparison comparison) + { + var actual = original.AsSpan().Remove(separator, comparison); + + Assert.Equal(removed, actual); + } + + [Theory] + [InlineData("this is a sentence that will probably wrap around a few times because it is long", 10, 6)] + public void TestWrap(string sentence, int perLine, int maxLines) + { + var expected = OldWrap(sentence, perLine, maxLines); + var actual = sentence.Wrap(perLine, maxLines); + + Assert.Equal(expected, actual); + } + + // The old wrap function from HouseGump/HouseGumpAOS + private static List OldWrap(string value, int startIndex, int maxLines) + { + if (value == null || (value = value.Trim()).Length <= 0) + { + return null; + } + + var values = value.Split(' '); + var list = new List(); + var current = ""; + + for (var i = 0; i < values.Length; ++i) + { + var val = values[i]; + + var v = current.Length == 0 ? val : $"{current} {val}"; + + if (v.Length < startIndex) + { + current = v; + } + else if (v.Length == startIndex) + { + list.Add(v); + + if (list.Count == maxLines) + { + return list; + } + + current = ""; + } + else if (val.Length <= startIndex) + { + list.Add(current); + + if (list.Count == maxLines) + { + return list; + } + + current = val; + } + else + { + while (v.Length >= startIndex) + { + list.Add(v.Substring(0, startIndex)); + + if (list.Count == maxLines) + { + return list; + } + + v = v.Substring(startIndex); + } + + current = v; + } + } + + if (current.Length > 0) + { + list.Add(current); + } + + return list; + } } } diff --git a/Projects/Server/Buffers/ValueStringBuilder.cs b/Projects/Server/Buffers/ValueStringBuilder.cs new file mode 100644 index 000000000..94bf77679 --- /dev/null +++ b/Projects/Server/Buffers/ValueStringBuilder.cs @@ -0,0 +1,363 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Buffers; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Server.Buffers +{ + public ref struct ValueStringBuilder + { + private char[]? _arrayToReturnToPool; + private Span _chars; + + public ValueStringBuilder(Span initialBuffer) + { + _arrayToReturnToPool = null; + _chars = initialBuffer; + Length = 0; + } + + public ValueStringBuilder(int initialCapacity) + { + _arrayToReturnToPool = ArrayPool.Shared.Rent(initialCapacity); + _chars = _arrayToReturnToPool; + Length = 0; + } + + public int Length { get; set; } + + public int Capacity => _chars.Length; + + public void EnsureCapacity(int capacity) + { + if (capacity > _chars.Length) + { + Grow(capacity - Length); + } + } + + /// + /// Get a pinnable reference to the builder. + /// Does not ensure there is a null char after + /// This overload is pattern matched in the C# 7.3+ compiler so you can omit + /// the explicit method call, and write eg "fixed (char* c = builder)" + /// + public ref char GetPinnableReference() => ref MemoryMarshal.GetReference(_chars); + + /// + /// Get a pinnable reference to the builder. + /// + /// Ensures that the builder has a null char after + public ref char GetPinnableReference(bool terminate) + { + if (terminate) + { + EnsureCapacity(Length + 1); + _chars[Length] = '\0'; + } + return ref MemoryMarshal.GetReference(_chars); + } + + public ref char this[int index] => ref _chars[index]; + + public override string ToString() => _chars.Slice(0, Length).ToString(); + + /// Returns the underlying storage of the builder. + public Span RawChars => _chars; + + /// + /// Returns a span around the contents of the builder. + /// + /// Ensures that the builder has a null char after + public ReadOnlySpan AsSpan(bool terminate) + { + if (terminate) + { + EnsureCapacity(Length + 1); + _chars[Length] = '\0'; + } + return _chars.Slice(0, Length); + } + + public ReadOnlySpan AsSpan() => _chars.Slice(0, Length); + public ReadOnlySpan AsSpan(int start) => _chars.Slice(start, Length - start); + public ReadOnlySpan AsSpan(int start, int length) => _chars.Slice(start, length); + + public bool TryCopyTo(Span destination, out int charsWritten) + { + if (_chars.Slice(0, Length).TryCopyTo(destination)) + { + charsWritten = Length; + return true; + } + + charsWritten = 0; + return false; + } + + public void Insert(int index, char value, int count) + { + if (Length > _chars.Length - count) + { + Grow(count); + } + + int remaining = Length - index; + _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count)); + _chars.Slice(index, count).Fill(value); + Length += count; + } + + public void Insert(int index, string? s) + { + if (s == null) + { + return; + } + + int count = s.Length; + + if (Length > _chars.Length - count) + { + Grow(count); + } + + int remaining = Length - index; + _chars.Slice(index, remaining).CopyTo(_chars.Slice(index + count)); + s.AsSpan().CopyTo(_chars.Slice(index)); + Length += count; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Append(char c) + { + int pos = Length; + if ((uint)pos < (uint)_chars.Length) + { + _chars[pos] = c; + Length = pos + 1; + } + else + { + GrowAndAppend(c); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Append(string? s) + { + if (s == null) + { + return; + } + + int pos = Length; + if (s.Length == 1 && (uint)pos < (uint)_chars.Length) // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc. + { + _chars[pos] = s[0]; + Length = pos + 1; + } + else + { + AppendSlow(s); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void AppendLine(string? s) + { + if (s == null) + { + return; + } + + // very common case, e.g. appending strings from NumberFormatInfo like separators, percent symbols, etc. + if (s.Length == 1) + { + Append(s[0]); + } + else + { + AppendSlow(s); + } + + Append(Environment.NewLine); + } + + private void AppendSlow(string s) + { + int pos = Length; + if (pos > _chars.Length - s.Length) + { + Grow(s.Length); + } + + s.AsSpan().CopyTo(_chars.Slice(pos)); + Length += s.Length; + } + + public void Append(char c, int count) + { + if (Length > _chars.Length - count) + { + Grow(count); + } + + Span dst = _chars.Slice(Length, count); + for (int i = 0; i < dst.Length; i++) + { + dst[i] = c; + } + Length += count; + } + + public unsafe void Append(char* value, int length) + { + int pos = Length; + if (pos > _chars.Length - length) + { + Grow(length); + } + + Span dst = _chars.Slice(Length, length); + for (int i = 0; i < dst.Length; i++) + { + dst[i] = *value++; + } + Length += length; + } + + public void Append(ReadOnlySpan value) + { + int pos = Length; + if (pos > _chars.Length - value.Length) + { + Grow(value.Length); + } + + value.CopyTo(_chars.Slice(Length)); + Length += value.Length; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Span AppendSpan(int length) + { + int origPos = Length; + if (origPos > _chars.Length - length) + { + Grow(length); + } + + Length = origPos + length; + return _chars.Slice(origPos, length); + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void GrowAndAppend(char c) + { + Grow(1); + Append(c); + } + + /// + /// Resize the internal buffer either by doubling current buffer size or + /// by adding to + /// whichever is greater. + /// + /// + /// Number of chars requested beyond current position. + /// + [MethodImpl(MethodImplOptions.NoInlining)] + private void Grow(int additionalCapacityBeyondPos) + { + char[] poolArray = ArrayPool.Shared.Rent(Math.Max(Length + additionalCapacityBeyondPos, _chars.Length * 2)); + + _chars.Slice(0, Length).CopyTo(poolArray); + + char[]? toReturn = _arrayToReturnToPool; + _chars = _arrayToReturnToPool = poolArray; + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Dispose() + { + char[]? toReturn = _arrayToReturnToPool; + this = default; // for safety, to avoid using pooled array if this instance is erroneously appended to again + if (toReturn != null) + { + ArrayPool.Shared.Return(toReturn); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Replace(char oldChar, char newChar, int startIndex, int count) + { + int currentLength = Length; + if ((uint)startIndex > (uint)currentLength) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + if (count < 0 || startIndex > currentLength - count) + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + + var slice = _chars; + + while (true) + { + var indexOf = slice.IndexOf(oldChar); + if (indexOf == -1) + { + break; + } + + slice[indexOf] = newChar; + slice = slice.Slice(indexOf + 1); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Remove(int startIndex, int length) + { + if (length < 0) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + if (startIndex < 0) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + if (length > Length - startIndex) + { + throw new ArgumentOutOfRangeException(nameof(length)); + } + + if (startIndex == 0) + { + _chars = _chars.Slice(length); + } + else if (startIndex + length == Length) + { + _chars = _chars.Slice(0, startIndex); + } + else + { + // Somewhere in the middle, this will be slow + _chars.Slice(startIndex + length).CopyTo(_chars.Slice(startIndex)); + } + + Length -= length; + } + } +} diff --git a/Projects/Server/ClientVersion.cs b/Projects/Server/ClientVersion.cs index ed4386a2f..63f7216ea 100644 --- a/Projects/Server/ClientVersion.cs +++ b/Projects/Server/ClientVersion.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Server.Buffers; namespace Server { @@ -32,7 +33,7 @@ namespace Server try { - var br1 = fmt.IndexOf('.', StringComparison.Ordinal); + var br1 = fmt.IndexOfOrdinal('.'); var br2 = fmt.IndexOf('.', br1 + 1); var br3 = br2 + 1; @@ -60,15 +61,15 @@ namespace Server } } - if (fmt.Contains("god", StringComparison.Ordinal) || fmt.Contains("gq", StringComparison.Ordinal)) + if (fmt.InsensitiveContains("god") || fmt.InsensitiveContains("gq")) { Type = ClientType.God; } - else if (fmt.Contains("third dawn", StringComparison.Ordinal) || - fmt.Contains("uo:td", StringComparison.Ordinal) || - fmt.Contains("uotd", StringComparison.Ordinal) || - fmt.Contains("uo3d", StringComparison.Ordinal) || - fmt.Contains("uo:3d", StringComparison.Ordinal)) + else if (fmt.InsensitiveContains("third dawn") || + fmt.InsensitiveContains("uo:td") || + fmt.InsensitiveContains("uotd") || + fmt.InsensitiveContains("uo3d") || + fmt.InsensitiveContains("uo:3d")) { Type = ClientType.UOTD; } @@ -178,13 +179,13 @@ namespace Server private string ToStringImpl() { - var builder = new StringBuilder(16); + using var builder = new ValueStringBuilder(stackalloc char[32]); - builder.Append(Major); + builder.Append(Major.ToString()); builder.Append('.'); - builder.Append(Minor); + builder.Append(Minor.ToString()); builder.Append('.'); - builder.Append(Revision); + builder.Append(Revision.ToString()); if (Major <= 5 && Minor <= 0 && Revision <= 6) // Anything before 5.0.7 { @@ -196,7 +197,7 @@ namespace Server else { builder.Append('.'); - builder.Append(Patch); + builder.Append(Patch.ToString()); } if (Type != ClientType.Regular) diff --git a/Projects/Server/Commands.cs b/Projects/Server/Commands.cs index b0dbedb72..f13808424 100644 --- a/Projects/Server/Commands.cs +++ b/Projects/Server/Commands.cs @@ -188,7 +188,7 @@ namespace Server public static bool Handle(Mobile from, string text, MessageType type = MessageType.Regular) { - if (!text.StartsWith(Prefix, StringComparison.Ordinal) && type != MessageType.Command) + if (!text.StartsWithOrdinal(Prefix) && type != MessageType.Command) { return false; } @@ -198,7 +198,7 @@ namespace Server text = text.Substring(Prefix.Length); } - var indexOf = text.IndexOf(' ', StringComparison.Ordinal); + var indexOf = text.IndexOfOrdinal(' '); string command; string[] args; diff --git a/Projects/Server/Configuration/ServerConfiguration.cs b/Projects/Server/Configuration/ServerConfiguration.cs index 4f8463b93..88a53300e 100644 --- a/Projects/Server/Configuration/ServerConfiguration.cs +++ b/Projects/Server/Configuration/ServerConfiguration.cs @@ -266,7 +266,7 @@ namespace Server break; } - if (!ipStr.Contains(':', StringComparison.Ordinal)) + if (!ipStr.ContainsOrdinal(':')) { ipStr += ":2593"; } diff --git a/Projects/Server/Geometry/Point2D.cs b/Projects/Server/Geometry/Point2D.cs index 704bd6436..8e42236d3 100644 --- a/Projects/Server/Geometry/Point2D.cs +++ b/Projects/Server/Geometry/Point2D.cs @@ -55,7 +55,7 @@ namespace Server public static Point2D Parse(string value) { - var start = value.IndexOf('(', StringComparison.Ordinal); + var start = value.IndexOfOrdinal('('); var end = value.IndexOf(',', start + 1); Utility.ToInt32(value.Substring(start + 1, end - (start + 1)).Trim(), out var x); diff --git a/Projects/Server/Geometry/Point3D.cs b/Projects/Server/Geometry/Point3D.cs index 45b1c6dd7..80588ef6d 100644 --- a/Projects/Server/Geometry/Point3D.cs +++ b/Projects/Server/Geometry/Point3D.cs @@ -77,7 +77,7 @@ namespace Server public static Point3D Parse(string value) { - var start = value.IndexOf('(', StringComparison.Ordinal); + var start = value.IndexOfOrdinal('('); var end = value.IndexOf(',', start + 1); Utility.ToInt32(value.Substring(start + 1, end - (start + 1)).Trim(), out var x); diff --git a/Projects/Server/Geometry/Rectangle2D.cs b/Projects/Server/Geometry/Rectangle2D.cs index 2ad4e1225..1d079abeb 100644 --- a/Projects/Server/Geometry/Rectangle2D.cs +++ b/Projects/Server/Geometry/Rectangle2D.cs @@ -49,7 +49,7 @@ namespace Server public static Rectangle2D Parse(string value) { - var start = value.IndexOf('(', StringComparison.Ordinal); + var start = value.IndexOfOrdinal('('); var end = value.IndexOf(',', start + 1); Utility.ToInt32(value.Substring(start + 1, end - (start + 1)).Trim(), out var x); diff --git a/Projects/Server/Geometry/WorldLocation.cs b/Projects/Server/Geometry/WorldLocation.cs index 1ebfb04cd..23883b781 100644 --- a/Projects/Server/Geometry/WorldLocation.cs +++ b/Projects/Server/Geometry/WorldLocation.cs @@ -142,7 +142,7 @@ namespace Server public static WorldLocation Parse(string value) { - var start = value.IndexOf('(', StringComparison.Ordinal); + var start = value.IndexOfOrdinal('('); var end = value.IndexOf(',', start + 1); Utility.ToInt32(value.Substring(start + 1, end - (start + 1)).Trim(), out var x); diff --git a/Projects/Server/Guild.cs b/Projects/Server/Guild.cs index cfadf5dfe..33aa98aa3 100644 --- a/Projects/Server/Guild.cs +++ b/Projects/Server/Guild.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.Linq; @@ -55,16 +54,26 @@ namespace Server.Guilds public static BaseGuild FindByAbbrev(string abbr) => World.Guilds.Values.FirstOrDefault(g => g.Abbreviation == abbr); - public static List Search(string find) + public static HashSet Search(string find) { var words = find.ToLower().Split(' '); - var results = new List(); + var results = new HashSet(); foreach (var g in World.Guilds.Values) { - var name = g.Name.ToLower(); + var name = g.Name; - if (words.All(t => name.IndexOf(t, StringComparison.Ordinal) != -1)) + bool all = true; + foreach (var t in words) + { + if (name.InsensitiveIndexOf(t) == -1) + { + all = false; + break; + } + } + + if (all) { results.Add(g); } diff --git a/Projects/Server/Insensitive.cs b/Projects/Server/Insensitive.cs deleted file mode 100644 index 2fbe0c90e..000000000 --- a/Projects/Server/Insensitive.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Server -{ - public static class Insensitive - { - public static IComparer Comparer { get; } = StringComparer.OrdinalIgnoreCase; - - public static int Compare(string a, string b) => Comparer.Compare(a, b); - - public static bool Equals(string a, string b) => - a == null && b == null || a != null && b != null && a.Length == b.Length && Comparer.Compare(a, b) == 0; - - public static bool StartsWith(string a, string b) => - a != null && b != null && a.Length >= b.Length && Comparer.Compare(a.Substring(0, b.Length), b) == 0; - - public static bool EndsWith(string a, string b) => - a != null && b != null && a.Length >= b.Length && Comparer.Compare(a.Substring(a.Length - b.Length), b) == 0; - - public static bool Contains(string a, string b) => - a != null && b != null && a.Length >= b.Length && a.Contains(b, StringComparison.Ordinal); - } -} diff --git a/Projects/Server/Items/Container.cs b/Projects/Server/Items/Container.cs index bd8ebdc08..eb12cb6b7 100644 --- a/Projects/Server/Items/Container.cs +++ b/Projects/Server/Items/Container.cs @@ -1823,7 +1823,7 @@ namespace Server.Items { line = line.Trim(); - if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length == 0 || line.StartsWithOrdinal("#")) { continue; } diff --git a/Projects/Server/Json/Converters/NullableStructSerializerFactory.cs b/Projects/Server/Json/Converters/NullableStructSerializerFactory.cs index 36ba88abe..5c6824aad 100644 --- a/Projects/Server/Json/Converters/NullableStructSerializerFactory.cs +++ b/Projects/Server/Json/Converters/NullableStructSerializerFactory.cs @@ -13,6 +13,8 @@ * along with this program. If not, see . * *************************************************************************/ +using Server; + namespace System.Text.Json.Serialization { public class NullableStructSerializerFactory : JsonConverterFactory @@ -26,8 +28,7 @@ namespace System.Text.Json.Serialization var structType = typeToConvert.GenericTypeArguments[0]; return !structType.IsPrimitive && - structType.Namespace?.StartsWith(nameof(System), StringComparison.Ordinal) != true && - !structType.IsEnum; + structType.Namespace.StartsWithOrdinal(nameof(System)) && !structType.IsEnum; } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) => diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 5deb92e70..8bae34f3a 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -61,9 +61,7 @@ namespace Server public static bool IsRunningFromXUnit => m_IsRunningFromXUnit ??= AppDomain.CurrentDomain.GetAssemblies() .Any( - a => a.FullName? - .ToUpperInvariant() - .StartsWith("XUNIT", StringComparison.Ordinal) ?? false + a => a.FullName.InsensitiveStartsWith("XUNIT") ); public static bool Profiling @@ -346,7 +344,7 @@ namespace Server foreach (var a in args) { - if (Insensitive.Equals(a, "-profile")) + if (a.InsensitiveEquals("-profile")) { Profiling = true; } diff --git a/Projects/Server/Map.cs b/Projects/Server/Map.cs index 07135c5a8..00dda91e8 100644 --- a/Projects/Server/Map.cs +++ b/Projects/Server/Map.cs @@ -397,7 +397,7 @@ namespace Server return null; } - if (Insensitive.Equals(value, "Internal")) + if (value.InsensitiveEquals("Internal")) { return Internal; } @@ -419,7 +419,7 @@ namespace Server continue; } - if (index >= 0 && map.MapIndex == index || Insensitive.Equals(map.Name, value)) + if (index >= 0 && map.MapIndex == index || map.Name.InsensitiveEquals(value)) { return map; } diff --git a/Projects/Server/Mobiles/Body.cs b/Projects/Server/Mobiles/Body.cs index bc0582491..7fee53a41 100644 --- a/Projects/Server/Mobiles/Body.cs +++ b/Projects/Server/Mobiles/Body.cs @@ -28,7 +28,7 @@ namespace Server while ((line = ip.ReadLine()) != null) { - if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length == 0 || line.StartsWithOrdinal("#")) { continue; } diff --git a/Projects/Server/Mobiles/Mobile.cs b/Projects/Server/Mobiles/Mobile.cs index f10c84359..cff424d00 100644 --- a/Projects/Server/Mobiles/Mobile.cs +++ b/Projects/Server/Mobiles/Mobile.cs @@ -7,6 +7,7 @@ using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Text; using Server.Accounting; +using Server.Buffers; using Server.ContextMenus; using Server.Guilds; using Server.Gumps; @@ -5674,8 +5675,7 @@ namespace Server return false; } - var sb = new StringBuilder(text.Length, text.Length); - + using var sb = new ValueStringBuilder(stackalloc char[Math.Min(text.Length, 256)]); for (var i = 0; i < text.Length; ++i) { sb.Append(text[i] != ' ' ? GhostChars.RandomElement() : ' '); diff --git a/Projects/Server/MultiData.cs b/Projects/Server/MultiData.cs index 563126fab..58523f9ff 100644 --- a/Projects/Server/MultiData.cs +++ b/Projects/Server/MultiData.cs @@ -152,7 +152,7 @@ namespace Server stream.Seek(offset + headerSize, SeekOrigin.Begin); - Span sourceData = new byte[compressedSize]; + Span sourceData = GC.AllocateUninitializedArray(compressedSize); if (stream.Read(sourceData) != compressedSize) { @@ -163,7 +163,7 @@ namespace Server if (compressionMethod == 1) { - data = new byte[decompressedSize]; + data = GC.AllocateUninitializedArray(decompressedSize); Zlib.Unpack(data, ref decompressedSize, sourceData, compressedSize); } else diff --git a/Projects/Server/Network/NetState/NetState.cs b/Projects/Server/Network/NetState/NetState.cs index 40e92e478..ad9afb8c6 100644 --- a/Projects/Server/Network/NetState/NetState.cs +++ b/Projects/Server/Network/NetState/NetState.cs @@ -84,9 +84,9 @@ namespace Server.Network HuePickers = new List(); Menus = new List(); Trades = new List(); - _recvBuffer = new byte[RecvPipeSize]; + _recvBuffer = GC.AllocateUninitializedArray(RecvPipeSize); RecvPipe = new Pipe(_recvBuffer); - _sendBuffer = new byte[SendPipeSize]; + _sendBuffer = GC.AllocateUninitializedArray(SendPipeSize); SendPipe = new Pipe(_sendBuffer); m_NextCheckActivity = Core.TickCount + 30000; diff --git a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs index 912acb44f..7e037aa30 100644 --- a/Projects/Server/Network/Packets/IncomingPlayerPackets.cs +++ b/Projects/Server/Network/Packets/IncomingPlayerPackets.cs @@ -13,6 +13,7 @@ * along with this program. If not, see . * *************************************************************************/ +using Microsoft.Toolkit.HighPerformance.Extensions; using Server.Diagnostics; using Server.Gumps; @@ -133,7 +134,8 @@ namespace Server.Network } case 0x24: // Use skill { - if (!int.TryParse(command.Split(' ')[0], out var skillIndex)) + var tokenizer = command.Tokenize(' '); + if (!tokenizer.MoveNext() || !int.TryParse(tokenizer.Current, out var skillIndex)) { break; } @@ -155,15 +157,11 @@ namespace Server.Network } case 0x27: // Cast spell from book { - var split = command.Split(' '); + var tokenizer = command.Tokenize(' '); + var spellID = (tokenizer.MoveNext() ? Utility.ToInt32(tokenizer.Current) : 0) - 1; + var serial = tokenizer.MoveNext() ? Utility.ToUInt32(tokenizer.Current) : (uint)Serial.MinusOne; - if (split.Length > 0) - { - var spellID = Utility.ToInt32(split[0]) - 1; - var serial = split.Length > 1 ? Utility.ToUInt32(split[1]) : (uint)Serial.MinusOne; - - EventSink.InvokeCastSpellRequest(from, spellID, World.FindItem(serial)); - } + EventSink.InvokeCastSpellRequest(from, spellID, World.FindItem(serial)); break; } diff --git a/Projects/Server/Race.cs b/Projects/Server/Race.cs index b397b659f..516eb8f50 100644 --- a/Projects/Server/Race.cs +++ b/Projects/Server/Race.cs @@ -74,7 +74,7 @@ namespace Server for (var i = 0; i < m_RaceNames.Length; ++i) { - if (Insensitive.Equals(m_RaceNames[i], value)) + if (m_RaceNames[i].InsensitiveEquals(value)) { return m_RaceValues[i]; } diff --git a/Projects/Server/Serialization/BufferWriter.cs b/Projects/Server/Serialization/BufferWriter.cs index d1e87756d..5930787ba 100644 --- a/Projects/Server/Serialization/BufferWriter.cs +++ b/Projects/Server/Serialization/BufferWriter.cs @@ -42,7 +42,7 @@ namespace Server { m_PrefixStrings = prefixStr; m_Encoding = Utility.UTF8; - _buffer = new byte[BufferSize]; + _buffer = GC.AllocateUninitializedArray(BufferSize); } public virtual long Position => Index; diff --git a/Projects/Server/Utilities/InsensitiveStringHelpers.cs b/Projects/Server/Utilities/InsensitiveStringHelpers.cs new file mode 100644 index 000000000..c04fbc07c --- /dev/null +++ b/Projects/Server/Utilities/InsensitiveStringHelpers.cs @@ -0,0 +1,102 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: InsensitiveStringHelpers.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Runtime.CompilerServices; + +namespace Server +{ + public static class InsensitiveStringHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int InsensitiveCompare(this ReadOnlySpan a, ReadOnlySpan b) => + a.CompareTo(b, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int InsensitiveCompare(this string a, string b) => StringComparer.Ordinal.Compare(a, b); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveEquals(this ReadOnlySpan a, string b) => + a.Equals(b, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveEquals(this string a, string b) => + a?.Equals(b, StringComparison.OrdinalIgnoreCase) ?? b == null; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveStartsWith(this ReadOnlySpan a, ReadOnlySpan b) => + a.StartsWith(b, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveStartsWith(this string a, string b) => + a?.StartsWith(b, StringComparison.OrdinalIgnoreCase) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveEndsWith(this string a, string b) => + a?.EndsWith(b, StringComparison.OrdinalIgnoreCase) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveEndsWith(this ReadOnlySpan a, ReadOnlySpan b) => + a.EndsWith(b, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveContains(this ReadOnlySpan a, string b) => + a.Contains(b, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveContains(this string a, string b) => + a?.Contains(b, StringComparison.OrdinalIgnoreCase) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveContains(this ReadOnlySpan a, ReadOnlySpan b) => + a.Contains(b, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool InsensitiveContains(this string a, char b) => + a?.Contains(b, StringComparison.OrdinalIgnoreCase) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int InsensitiveIndexOf(this string a, char b) => + a?.IndexOf(b, StringComparison.OrdinalIgnoreCase) ?? -1; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int InsensitiveIndexOf(this string a, string b) => + a?.IndexOf(b, StringComparison.OrdinalIgnoreCase) ?? -1; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int InsensitiveIndexOf(this string a, string b, int startIndex) => + a?.IndexOf(b, startIndex, StringComparison.OrdinalIgnoreCase) ?? -1; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int InsensitiveIndexOf(this ReadOnlySpan a, ReadOnlySpan b) => + a.IndexOf(b, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string InsensitiveReplace(this string a, string o, string n) => + a?.Replace(o, n, StringComparison.OrdinalIgnoreCase); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void InsensitiveRemove( + this ReadOnlySpan a, + ReadOnlySpan b, + Span buffer, + out int size + ) => a.Remove(b, StringComparison.OrdinalIgnoreCase, buffer, out size); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string InsensitiveRemove(this ReadOnlySpan a, ReadOnlySpan b) => + a.Remove(b, StringComparison.OrdinalIgnoreCase); + } +} diff --git a/Projects/Server/Utilities/OrdinalStringHelpers.cs b/Projects/Server/Utilities/OrdinalStringHelpers.cs new file mode 100644 index 000000000..3bbe662a5 --- /dev/null +++ b/Projects/Server/Utilities/OrdinalStringHelpers.cs @@ -0,0 +1,100 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: OrdinalStringHelpers.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Runtime.CompilerServices; + +namespace Server +{ + public static class OrdinalStringHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CompareOrdinal(this ReadOnlySpan a, ReadOnlySpan b) => + a.CompareTo(b, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int CompareOrdinal(this string a, string b) => StringComparer.Ordinal.Compare(a, b); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EqualsOrdinal(this ReadOnlySpan a, string b) => + a.Equals(b, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EqualsOrdinal(this string a, string b) => + a?.Equals(b, StringComparison.Ordinal) ?? b == null; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool StartsWithOrdinal(this ReadOnlySpan a, ReadOnlySpan b) => + a.StartsWith(b, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool StartsWithOrdinal(this string a, string b) => + a?.StartsWith(b, StringComparison.Ordinal) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EndsWithOrdinal(this string a, string b) => + a?.EndsWith(b, StringComparison.Ordinal) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool EndsWithOrdinal(this ReadOnlySpan a, ReadOnlySpan b) => + a.EndsWith(b, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsOrdinal(this ReadOnlySpan a, string b) => + a.Contains(b, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsOrdinal(this string a, string b) => + a?.Contains(b, StringComparison.Ordinal) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsOrdinal(this ReadOnlySpan a, ReadOnlySpan b) => + a.Contains(b, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static bool ContainsOrdinal(this string a, char b) => + a?.Contains(b, StringComparison.Ordinal) == true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfOrdinal(this string a, char b) => a?.IndexOf(b, StringComparison.Ordinal) ?? -1; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfOrdinal(this string a, string b) => a?.IndexOf(b, StringComparison.Ordinal) ?? -1; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfOrdinal(this string a, string b, int startIndex) => + a?.IndexOf(b, startIndex, StringComparison.Ordinal) ?? -1; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexOfOrdinal(this ReadOnlySpan a, ReadOnlySpan b) => + a.IndexOf(b, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string ReplaceOrdinal(this string a, string o, string n) => + a?.Replace(o, n, StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string RemoveOrdinal(this string a, string b) => + a?.Replace(b, "", StringComparison.Ordinal); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void RemoveOrdinal(this ReadOnlySpan a, ReadOnlySpan b, Span buffer, out int size) => + a.Remove(b, StringComparison.Ordinal, buffer, out size); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string RemoveOrdinal(this ReadOnlySpan a, ReadOnlySpan b) => + a.Remove(b, StringComparison.Ordinal); + } +} diff --git a/Projects/Server/Utilities/StringHelpers.cs b/Projects/Server/Utilities/StringHelpers.cs new file mode 100644 index 000000000..2b8a61115 --- /dev/null +++ b/Projects/Server/Utilities/StringHelpers.cs @@ -0,0 +1,245 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019-2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: StringHelpers.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Buffers; +using System.Collections.Generic; +using System.Runtime.CompilerServices; + +namespace Server +{ + public static class StringHelpers + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string DefaultIfNullOrEmpty(this string value, string def) => value?.Trim().Length > 0 ? value : def; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static void Remove( + this ReadOnlySpan a, + ReadOnlySpan b, + StringComparison comparison, + Span buffer, + out int size + ) + { + size = 0; + if (a == null || a.Length == 0) + { + return; + } + + var sliced = a; + + while (true) + { + var indexOf = sliced.IndexOf(b, comparison); + if (indexOf == -1) + { + indexOf = sliced.Length; + } + + if (size + indexOf > buffer.Length) + { + throw new OutOfMemoryException(nameof(buffer)); + } + + sliced.Slice(0, indexOf).CopyTo(buffer.Slice(size)); + size += indexOf; + + if (indexOf == sliced.Length) + { + break; + } + + sliced = sliced.Slice(indexOf + 1); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string Remove(this ReadOnlySpan a, ReadOnlySpan b, StringComparison comparison) + { + if (a == null) + { + return null; + } + + if (a.Length == 0) + { + return ""; + } + + Span span = a.Length < 1024 ? stackalloc char[a.Length] : null; + char[] chrs; + if (span == null) + { + chrs = ArrayPool.Shared.Rent(a.Length); + span = chrs.AsSpan(); + } + else + { + chrs = null; + } + + a.Remove(b, comparison, span, out var size); + + var str = span.Slice(0, size).ToString(); + + if (chrs != null) + { + ArrayPool.Shared.Return(chrs); + } + + return str; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static string Capitalize(this string value) + { + if (string.IsNullOrEmpty(value)) + { + return value; + } + + Span span = value.Length < 1024 ? stackalloc char[value.Length] : null; + char[] chrs; + if (span == null) + { + chrs = ArrayPool.Shared.Rent(value.Length); + span = chrs.AsSpan(); + } + else + { + chrs = null; + } + + var sliced = value.AsSpan(); + // Copy over the previous span + sliced.CopyTo(span); + + var index = 0; + + while (true) + { + // Special case for titles - words that don't get capitalized + if (sliced.InsensitiveStartsWith("the ")) + { + sliced = sliced.Slice(4); + index += 4; + continue; + } + + var indexOf = sliced.IndexOf(' '); + span[index] = char.ToUpperInvariant(sliced[0]); + + if (indexOf == -1) + { + break; + } + + if (indexOf == sliced.Length - 1) + { + break; + } + + sliced = sliced.Slice(indexOf + 1); + index += indexOf + 1; + } + + var str = span.ToString(); + + if (chrs != null) + { + ArrayPool.Shared.Return(chrs); + } + + return str; + } + + public static List Wrap(this string value, int perLine, int maxLines) + { + if ((value = value?.Trim() ?? "").Length <= 0) + { + return null; + } + + var span = value.AsSpan(); + var list = new List(maxLines); + var lineLength = 0; + + while (span.Length > 0) + { + var spaceIndex = span.Slice(lineLength).IndexOf(' '); + if (spaceIndex == -1) + { + spaceIndex = span.Length; // End of the string + } + + var newLineLength = lineLength + spaceIndex; + + if (newLineLength == perLine || newLineLength == span.Length - 1) + { + // Could be the end of the string + var length = span[newLineLength] == ' ' ? newLineLength - 1 : newLineLength; + list.Add(span.Slice(0, length).ToString()); + if (list.Count == maxLines) + { + break; + } + + span = span.Slice(newLineLength); + lineLength = 0; + } + else if (newLineLength < perLine) + { + lineLength = newLineLength + 1; + } + else if (lineLength > 0 && lineLength <= perLine) + { + list.Add(span.Slice(0, lineLength - 1).ToString()); + if (list.Count == maxLines) + { + break; + } + + span = span.Slice(lineLength); + lineLength = spaceIndex; + } + else + { + lineLength = newLineLength; + var index = 0; + + while (index < lineLength) + { + lineLength -= perLine; + + var length = perLine - (span[index] == ' ' ? 1 : 0); + list.Add(span.Slice(index, length).ToString()); + if (list.Count == maxLines) + { + break; + } + + index += perLine; + } + + span = span.Slice(lineLength); + } + } + + return list; + } + } +} diff --git a/Projects/Server/Utilities/Utility.cs b/Projects/Server/Utilities/Utility.cs index 16c1bd2d1..bfe60d8b8 100644 --- a/Projects/Server/Utilities/Utility.cs +++ b/Projects/Server/Utilities/Utility.cs @@ -1,5 +1,6 @@ using System; using System.Buffers.Binary; +using System.Collections; using System.Collections.Generic; using System.Globalization; using System.IO; @@ -11,6 +12,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Xml; using Microsoft.Toolkit.HighPerformance.Extensions; +using Server.Buffers; using Server.Random; namespace Server @@ -144,18 +146,20 @@ namespace Server ReadOnlySpan chars = s.AsSpan(); - StringBuilder stringBuilder = null; + using ValueStringBuilder sb = new ValueStringBuilder(stackalloc char[256]); + var hasDoneAnyReplacements = false; for (int i = 0, last = 0; i < chars.Length; i++) { - if (!IsSafeChar(chars[i]) || stringBuilder != null && i == chars.Length - 1) + if (!IsSafeChar(chars[i]) && i == chars.Length - 1) { - (stringBuilder ??= new StringBuilder()).Append(chars.Slice(last, i - last)); + hasDoneAnyReplacements = true; + sb.Append(chars.Slice(last, i - last)); last = i + 1; // Skip the unsafe char } } - return stringBuilder?.ToString() ?? s; + return !hasDoneAnyReplacements ? s : sb.ToString(); } public static void Separate(StringBuilder sb, string value, string separator) @@ -175,9 +179,6 @@ namespace Server str = Intern(str); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static string DefaultIfNullOrEmpty(this string value, string def) => value?.Trim().Length > 0 ? value : def; - public static IPAddress Intern(IPAddress ipAddress) { if (ipAddress == null) @@ -301,7 +302,7 @@ namespace Server public static bool IPMatch(string val, IPAddress ip, out bool valid) { var family = ip.AddressFamily; - var useIPv6 = family == AddressFamily.InterNetworkV6 || val.Contains(':', StringComparison.Ordinal); + var useIPv6 = family == AddressFamily.InterNetworkV6 || val.ContainsOrdinal(':'); ip = useIPv6 ? ip.MapToIPv6() : ip.MapToIPv4(); @@ -619,9 +620,9 @@ namespace Server return ""; } - var hasOpen = str.Contains('<', StringComparison.Ordinal); - var hasClose = str.Contains('>', StringComparison.Ordinal); - var hasPound = str.Contains('#', StringComparison.Ordinal); + var hasOpen = str.ContainsOrdinal('<'); + var hasClose = str.ContainsOrdinal('>'); + var hasPound = str.ContainsOrdinal('#'); if (!hasOpen && !hasClose && !hasPound) { @@ -648,9 +649,9 @@ namespace Server return sb.ToString(); } - public static int InsensitiveCompare(string first, string second) => Insensitive.Compare(first, second); + public static int InsensitiveCompare(string first, string second) => first.InsensitiveCompare(second); - public static bool InsensitiveStartsWith(string first, string second) => Insensitive.StartsWith(first, second); + public static bool InsensitiveStartsWith(string first, string second) => first.InsensitiveStartsWith(second); public static Direction GetDirection(IPoint2D from, IPoint2D to) { @@ -990,33 +991,18 @@ namespace Server } } - public static List CastListContravariant(this IReadOnlyCollection coll) - where TInput : TOutput + // Using this instead of Linq Cast<> means we can ditch the yield and enforce contravariance + public static HashSet SafeConvertSet(this IEnumerable coll) + where TOutput : TInput => coll.SafeConvert, TInput, TOutput>(); + + public static List SafeConvertList(this IEnumerable coll) + where TOutput : TInput => coll.SafeConvert, TInput, TOutput>(); + + public static TColl SafeConvert(this IEnumerable coll) + where TOutput : TInput where TColl : ICollection, new() { - var outputList = new List(); - foreach (var entry in coll) - { - outputList.Add(entry); - } + var outputList = new TColl(); - return outputList; - } - - public static List CastListCovariant(this IReadOnlyCollection coll) - where TOutput : TInput - { - var outputList = new List(); - foreach (var entry in coll) - { - outputList.Add((TOutput)entry); - } - - return outputList; - } - - public static List SafeConvertList(this IReadOnlyCollection coll) where TOutput : class - { - var outputList = new List(); foreach (var entry in coll) { if (entry is TOutput outEntry) @@ -1055,14 +1041,14 @@ namespace Server return t; } - public static int ToInt32(string value) + public static int ToInt32(ReadOnlySpan value) { int i; #pragma warning disable CA1806 // Do not ignore method results - if (value.StartsWith("0x", StringComparison.Ordinal)) + if (value.StartsWithOrdinal("0x")) { - int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i); + int.TryParse(value.Slice(2), NumberStyles.HexNumber, null, out i); } else { @@ -1073,14 +1059,14 @@ namespace Server return i; } - public static uint ToUInt32(string value) + public static uint ToUInt32(ReadOnlySpan value) { uint i; #pragma warning disable CA1806 // Do not ignore method results - if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + if (value.InsensitiveStartsWith("0x")) { - uint.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i); + uint.TryParse(value.Slice(2), NumberStyles.HexNumber, null, out i); } else { @@ -1091,14 +1077,14 @@ namespace Server return i; } - public static bool ToInt32(string value, out int i) => - value.StartsWith("0x", StringComparison.OrdinalIgnoreCase) - ? int.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i) + public static bool ToInt32(ReadOnlySpan value, out int i) => + value.InsensitiveStartsWith("0x") + ? int.TryParse(value.Slice(2), NumberStyles.HexNumber, null, out i) : int.TryParse(value, out i); - public static bool ToUInt32(string value, out uint i) => - value.StartsWith("0x", StringComparison.OrdinalIgnoreCase) - ? uint.TryParse(value.Substring(2), NumberStyles.HexNumber, null, out i) + public static bool ToUInt32(ReadOnlySpan value, out uint i) => + value.InsensitiveStartsWith("0x") + ? uint.TryParse(value.Slice(2), NumberStyles.HexNumber, null, out i) : uint.TryParse(value, out i); public static int GetXMLInt32(string intString, int defaultValue) diff --git a/Projects/Server/World/World.cs b/Projects/Server/World/World.cs index 1a9d8a709..6bead8af6 100644 --- a/Projects/Server/World/World.cs +++ b/Projects/Server/World/World.cs @@ -313,7 +313,7 @@ namespace Server continue; } - byte[] saveBuffer = new byte[entry.Length]; + byte[] saveBuffer = GC.AllocateUninitializedArray(entry.Length); reader.Read(saveBuffer, 0, entry.Length); t.SaveBuffer = new BufferWriter(saveBuffer, true); } @@ -331,7 +331,7 @@ namespace Server } using FileStream bin = new FileStream(dataPath, FileMode.Open, FileAccess.Read, FileShare.Read); - var buffer = new byte[bin.Length]; + var buffer = bin.Length <= int.MaxValue ? GC.AllocateUninitializedArray((int)bin.Length) : new byte[bin.Length]; bin.Read(buffer); bin.Close(); diff --git a/Projects/UOContent.Tests/Accounting/Security/PasswordProtectionTest.cs b/Projects/UOContent.Tests/Tests/Accounting/Security/PasswordProtectionTest.cs similarity index 100% rename from Projects/UOContent.Tests/Accounting/Security/PasswordProtectionTest.cs rename to Projects/UOContent.Tests/Tests/Accounting/Security/PasswordProtectionTest.cs diff --git a/Projects/UOContent.Tests/Tests/Firewall/FirewallEntryTests.cs b/Projects/UOContent.Tests/Tests/Firewall/FirewallEntryTests.cs new file mode 100644 index 000000000..79c1fd0dd --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Firewall/FirewallEntryTests.cs @@ -0,0 +1,20 @@ +using System; +using System.Net; +using Xunit; + +namespace Server.Tests +{ + public class FirewallEntryTests + { + [Theory] + [InlineData("192.168.1.1/24", typeof(Firewall.CIDRFirewallEntry), "192.168.1.50")] + [InlineData("192.168.*.100-200", typeof(Firewall.WildcardIPFirewallEntry), "192.168.30.150")] + [InlineData("::1234:*:1000-1234", typeof(Firewall.WildcardIPFirewallEntry), "::1234:5678:1150")] + public void TestFirewallEntry(string entry, Type entryType, string ipToMatch) + { + var firewallEntry = Firewall.ToFirewallEntry(entry); + Assert.IsType(entryType, firewallEntry); + Assert.True(firewallEntry.IsBlocked(IPAddress.Parse(ipToMatch))); + } + } +} diff --git a/Projects/UOContent.Tests/Network/Packets/ArrowPacketTests.cs b/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPacketTests.cs similarity index 100% rename from Projects/UOContent.Tests/Network/Packets/ArrowPacketTests.cs rename to Projects/UOContent.Tests/Tests/Network/Packets/ArrowPacketTests.cs diff --git a/Projects/UOContent.Tests/Network/Packets/ArrowPackets.cs b/Projects/UOContent.Tests/Tests/Network/Packets/ArrowPackets.cs similarity index 100% rename from Projects/UOContent.Tests/Network/Packets/ArrowPackets.cs rename to Projects/UOContent.Tests/Tests/Network/Packets/ArrowPackets.cs diff --git a/Projects/UOContent/Accounting/Account.cs b/Projects/UOContent/Accounting/Account.cs index 904c702d1..6498a5166 100644 --- a/Projects/UOContent/Accounting/Account.cs +++ b/Projects/UOContent/Accounting/Account.cs @@ -775,7 +775,7 @@ namespace Server.Accounting } m_PasswordAlgorithm = algorithm; - Password = password.Replace("-", string.Empty, StringComparison.Ordinal); + Password = password.ReplaceOrdinal("-", string.Empty); return true; } diff --git a/Projects/UOContent/Accounting/AccountHandler.cs b/Projects/UOContent/Accounting/AccountHandler.cs index d1addf3b6..9fccd3737 100644 --- a/Projects/UOContent/Accounting/AccountHandler.cs +++ b/Projects/UOContent/Accounting/AccountHandler.cs @@ -176,7 +176,7 @@ namespace Server.Misc if (entry != null) { - if (entry.Message.StartsWith("[Automated: Change Password]", StringComparison.Ordinal)) + if (entry.Message.StartsWithOrdinal("[Automated: Change Password]")) { from.SendMessage("You already have a password change request in the help system queue."); } @@ -288,9 +288,9 @@ namespace Server.Misc return null; } - var isSafe = !(un.StartsWith(" ", StringComparison.Ordinal) || - un.EndsWith(" ", StringComparison.Ordinal) || - un.EndsWith(".", StringComparison.Ordinal)); + var isSafe = !(un.StartsWithOrdinal(" ") || + un.EndsWithOrdinal(" ") || + un.EndsWithOrdinal(".")); for (var i = 0; isSafe && i < un.Length; ++i) { diff --git a/Projects/UOContent/Accounting/Firewall.cs b/Projects/UOContent/Accounting/Firewall.cs index a0ea62f34..3b79c333e 100644 --- a/Projects/UOContent/Accounting/Firewall.cs +++ b/Projects/UOContent/Accounting/Firewall.cs @@ -2,20 +2,21 @@ using System; using System.Collections.Generic; using System.IO; using System.Net; +using Microsoft.Toolkit.HighPerformance.Extensions; namespace Server { public static class Firewall { + private const string firewallConfigPath = "firewall.cfg"; + static Firewall() { - List = new List(); + Set = new HashSet(); - var path = "firewall.cfg"; - - if (File.Exists(path)) + if (File.Exists(firewallConfigPath)) { - using var ip = new StreamReader(path); + using var ip = new StreamReader(firewallConfigPath); string line; while ((line = ip.ReadLine()) != null) @@ -27,24 +28,12 @@ namespace Server continue; } - List.Add(ToFirewallEntry(line)); - - /* - object toAdd; - - IPAddress addr; - if (IPAddress.TryParse( line, out addr )) - toAdd = addr; - else - toAdd = line; - - m_Blocked.Add( toAdd.ToString() ); - * */ + Set.Add(ToFirewallEntry(line)); } } } - public static List List { get; } + public static HashSet Set { get; } public static IFirewallEntry ToFirewallEntry(object entry) { @@ -59,111 +48,79 @@ namespace Server public static IFirewallEntry ToFirewallEntry(string entry) { + if (entry == null) + { + return null; + } + if (IPAddress.TryParse(entry, out var addr)) { return new IPFirewallEntry(addr); } // Try CIDR parse - var str = entry?.Split('/'); + var tokenizer = entry.Tokenize('/'); + var ip = tokenizer.MoveNext() ? tokenizer.Current : null; + var length = tokenizer.MoveNext() ? tokenizer.Current : null; - if (str?.Length == 2) + if ( + length != null && + IPAddress.TryParse(ip, out var cidrPrefix) && + int.TryParse(length, out var cidrLength) + ) { - if (IPAddress.TryParse(str[0], out var cidrPrefix)) - { - if (int.TryParse(str[1], out var cidrLength)) - { - return new CIDRFirewallEntry(cidrPrefix, cidrLength); - } - } + return new CIDRFirewallEntry(cidrPrefix, cidrLength); } return new WildcardIPFirewallEntry(entry); } - public static void RemoveAt(int index) - { - List.RemoveAt(index); - Save(); - } - public static void Remove(object obj) { var entry = ToFirewallEntry(obj); if (entry != null) { - List.Remove(entry); + Set.Remove(entry); Save(); } } public static void Add(object obj) { - if (obj is IPAddress address) - { - Add(address); - } - else if (obj is string s) - { - Add(s); - } - else if (obj is IFirewallEntry entry) - { - Add(entry); - } + Add(ToFirewallEntry(obj)); } public static void Add(IFirewallEntry entry) { - if (!List.Contains(entry)) - { - List.Add(entry); - } - + Set.Add(entry); Save(); } public static void Add(string pattern) { - var entry = ToFirewallEntry(pattern); - - if (!List.Contains(entry)) - { - List.Add(entry); - } - - Save(); + Add(ToFirewallEntry(pattern)); } public static void Add(IPAddress ip) { - IFirewallEntry entry = new IPFirewallEntry(ip); - - if (!List.Contains(entry)) - { - List.Add(entry); - } - - Save(); + Add(ToFirewallEntry(ip)); } public static void Save() { - var path = "firewall.cfg"; - - using var op = new StreamWriter(path); - for (var i = 0; i < List.Count; ++i) + using var op = new StreamWriter(firewallConfigPath); + foreach (var entry in Set) { - op.WriteLine(List[i]); + op.WriteLine(entry); } } public static bool IsBlocked(IPAddress ip) { - for (var i = 0; i < List.Count; i++) + foreach (var entry in Set) { - if (List[i].IsBlocked(ip)) + if (entry.IsBlocked(ip)) { return true; } @@ -189,24 +146,13 @@ namespace Server public override bool Equals(object obj) { - if (obj is IPAddress) + return obj switch { - return obj.Equals(m_Address); - } - - if (obj is string s) - { - if (IPAddress.TryParse(s, out var otherAddress)) - { - return otherAddress.Equals(m_Address); - } - } - else if (obj is IPFirewallEntry entry) - { - return m_Address.Equals(entry.m_Address); - } - - return false; + IPAddress => obj.Equals(m_Address), + string s when IPAddress.TryParse(s, out var otherAddress) => otherAddress.Equals(m_Address), + IPFirewallEntry entry => m_Address.Equals(entry.m_Address), + _ => false + }; } public override int GetHashCode() => m_Address.GetHashCode(); @@ -259,21 +205,11 @@ namespace Server { private readonly string m_Entry; - private bool m_Valid; + private bool m_Valid = true; public WildcardIPFirewallEntry(string entry) => m_Entry = entry; - public bool IsBlocked(IPAddress address) - { - if (!m_Valid) - { - return false; // Why process if it's invalid? it'll return false anyway after processing it. - } - - var matched = Utility.IPMatch(m_Entry, address, out var valid); - m_Valid = valid; - return matched; - } + public bool IsBlocked(IPAddress address) => m_Valid && Utility.IPMatch(m_Entry, address, out m_Valid); public override string ToString() => m_Entry; diff --git a/Projects/UOContent/Accounting/Security/MD5PasswordProtection.cs b/Projects/UOContent/Accounting/Security/MD5PasswordProtection.cs index 76da4dbdf..c593157ba 100644 --- a/Projects/UOContent/Accounting/Security/MD5PasswordProtection.cs +++ b/Projects/UOContent/Accounting/Security/MD5PasswordProtection.cs @@ -29,7 +29,7 @@ namespace Server.Accounting.Security public string EncryptPassword(string plainPassword) { var password = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length)); - var bytes = new byte[Encoding.ASCII.GetByteCount(password)]; + var bytes = GC.AllocateUninitializedArray(Encoding.ASCII.GetByteCount(password)); Encoding.ASCII.GetBytes(password, bytes); return m_MD5HashProvider.ComputeHash(bytes).ToHexString(); diff --git a/Projects/UOContent/Accounting/Security/SHA1PasswordProtection.cs b/Projects/UOContent/Accounting/Security/SHA1PasswordProtection.cs index 2005c2ded..a21730fb3 100644 --- a/Projects/UOContent/Accounting/Security/SHA1PasswordProtection.cs +++ b/Projects/UOContent/Accounting/Security/SHA1PasswordProtection.cs @@ -29,7 +29,7 @@ namespace Server.Accounting.Security public string EncryptPassword(string plainPassword) { var password = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length)); - var bytes = new byte[Encoding.ASCII.GetByteCount(password)]; + var bytes = GC.AllocateUninitializedArray(Encoding.ASCII.GetByteCount(password)); Encoding.ASCII.GetBytes(password, bytes); return m_SHA1HashProvider.ComputeHash(bytes).ToHexString(); diff --git a/Projects/UOContent/Accounting/Security/SHA2PasswordProtection.cs b/Projects/UOContent/Accounting/Security/SHA2PasswordProtection.cs index 0c452e458..5c53dc68c 100644 --- a/Projects/UOContent/Accounting/Security/SHA2PasswordProtection.cs +++ b/Projects/UOContent/Accounting/Security/SHA2PasswordProtection.cs @@ -27,7 +27,7 @@ namespace Server.Accounting.Security public string EncryptPassword(string plainPassword) { var password = plainPassword.AsSpan(0, Math.Min(256, plainPassword.Length)); - var bytes = new byte[Encoding.ASCII.GetByteCount(password)]; + var bytes = GC.AllocateUninitializedArray(Encoding.ASCII.GetByteCount(password)); Encoding.ASCII.GetBytes(password, bytes); return m_SHA2HashProvider.ComputeHash(bytes).ToHexString(); diff --git a/Projects/UOContent/Commands/Batch.cs b/Projects/UOContent/Commands/Batch.cs index 2c5ee8944..aae44e94e 100644 --- a/Projects/UOContent/Commands/Batch.cs +++ b/Projects/UOContent/Commands/Batch.cs @@ -208,7 +208,7 @@ namespace Server.Commands public void GetDetails(out string command, out string argString, out string[] args) { - var indexOf = Command.IndexOf(' ', StringComparison.Ordinal); + var indexOf = Command.IndexOfOrdinal(' '); if (indexOf >= 0) { diff --git a/Projects/UOContent/Commands/Docs.cs b/Projects/UOContent/Commands/Docs.cs index 7075c7f81..73822308d 100644 --- a/Projects/UOContent/Commands/Docs.cs +++ b/Projects/UOContent/Commands/Docs.cs @@ -331,7 +331,7 @@ namespace Server.Commands if (type.IsGenericType) { - var index = type.Name.IndexOf('`', StringComparison.Ordinal); + var index = type.Name.IndexOfOrdinal('`'); if (index > 0) { @@ -406,19 +406,14 @@ namespace Server.Commands public static string SanitizeType(string name) { - var anonymousType = name.Contains('<', StringComparison.Ordinal); + var anonymousType = name.ContainsOrdinal('<'); var sb = new StringBuilder(name); for (var i = 0; i < ReplaceChars.Length; ++i) { sb.Replace(ReplaceChars[i], '-'); } - if (anonymousType) - { - return $"(Anonymous-Type){sb}"; - } - - return sb.ToString(); + return anonymousType ? $"(Anonymous-Type){sb}" : sb.ToString(); } public static string AliasForName(string name) @@ -465,7 +460,7 @@ namespace Server.Commands return true; } - if (type.Namespace.StartsWith("Server", StringComparison.Ordinal)) + if (type.Namespace.StartsWithOrdinal("Server")) { return false; } @@ -604,7 +599,7 @@ namespace Server.Commands if (realType?.IsGenericType == true) { FormatGeneric(realType, out _, out _, out var linkName); - aliased = linkName.Replace("@directory@", null, StringComparison.Ordinal); + aliased = linkName.ReplaceOrdinal("@directory@", null); } else { @@ -1719,7 +1714,7 @@ namespace Server.Commands { line = line.Trim(); - if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length == 0 || line.StartsWithOrdinal("#")) { continue; } @@ -2030,8 +2025,8 @@ namespace Server.Commands var aliases = attrs.Length == 0 ? null : attrs[0] as AliasesAttribute; var descString = desc.Description - .Replace("<", "<", StringComparison.Ordinal) - .Replace(">", ">", StringComparison.Ordinal); + .ReplaceOrdinal("<", "<") + .ReplaceOrdinal(">", ">"); list.Add(new DocCommandEntry(e.AccessLevel, e.Command, aliases?.Aliases, usage.Usage, descString)); } @@ -2058,8 +2053,8 @@ namespace Server.Commands } desc = desc - .Replace("<", "<", StringComparison.Ordinal) - .Replace(">", ">", StringComparison.Ordinal); + .ReplaceOrdinal("<", "<") + .ReplaceOrdinal(">", ">"); if (command.Supports != CommandSupport.Single) { @@ -2136,8 +2131,8 @@ namespace Server.Commands } desc = desc - .Replace("<", "<", StringComparison.Ordinal) - .Replace(">", ">", StringComparison.Ordinal); + .ReplaceOrdinal("<", "<") + .ReplaceOrdinal(">", ">"); list.Add(new DocCommandEntry(command.AccessLevel, cmd, aliases, usage, desc)); } @@ -2237,8 +2232,8 @@ namespace Server.Commands html.Write( "Usage: {0}
{1}", usage - .Replace("<", "<", StringComparison.Ordinal) - .Replace(">", ">", StringComparison.Ordinal), + .ReplaceOrdinal("<", "<") + .ReplaceOrdinal(">", ">"), desc ); } @@ -2247,8 +2242,8 @@ namespace Server.Commands html.Write( "Usage: {0}
Alias{1}: ", usage - .Replace("<", "<", StringComparison.Ordinal) - .Replace(">", ">", StringComparison.Ordinal), + .ReplaceOrdinal("<", "<") + .ReplaceOrdinal(">", ">"), aliases.Length == 1 ? "" : "es" ); @@ -2567,7 +2562,7 @@ namespace Server.Commands if (ifaceInfo == null) { FormatGeneric(iface, out _, out _, out var linkName); - typeHtml.Write($"{linkName.Replace("@directory@", null, StringComparison.Ordinal)}"); + typeHtml.Write($"{linkName.ReplaceOrdinal("@directory@", null)}"); } else { @@ -2913,7 +2908,7 @@ namespace Server.Commands public string FileName => m_FileName; public string TypeName => m_TypeName; - public string LinkName(string dirRoot) => m_LinkName.Replace("@directory@", dirRoot, StringComparison.Ordinal); + public string LinkName(string dirRoot) => m_LinkName.ReplaceOrdinal("@directory@", dirRoot); } private class SpeechEntry diff --git a/Projects/UOContent/Commands/Generic/Commands/Commands.cs b/Projects/UOContent/Commands/Generic/Commands/Commands.cs index c6464f2c4..c0fac740c 100644 --- a/Projects/UOContent/Commands/Generic/Commands/Commands.cs +++ b/Projects/UOContent/Commands/Generic/Commands/Commands.cs @@ -788,7 +788,7 @@ namespace Server.Commands.Generic var result = Properties.GetValue(e.Mobile, obj, e.GetString(i)); if (result == "Property not found." || result == "Property is write only." || - result.StartsWith("Getting this property", StringComparison.Ordinal)) + result.StartsWithOrdinal("Getting this property")) { LogFailure(result); } diff --git a/Projects/UOContent/Commands/Generic/Commands/Interface.cs b/Projects/UOContent/Commands/Generic/Commands/Interface.cs index 6c6c78cfd..6a343f554 100644 --- a/Projects/UOContent/Commands/Generic/Commands/Interface.cs +++ b/Projects/UOContent/Commands/Generic/Commands/Interface.cs @@ -28,7 +28,7 @@ namespace Server.Commands.Generic { var offset = 0; - if (Insensitive.Equals(e.GetString(0), "view")) + if (e.GetString(0).InsensitiveEquals("view")) { ++offset; } diff --git a/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs b/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs index feafc9b9a..a481ff35e 100644 --- a/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs +++ b/Projects/UOContent/Commands/Generic/Extensions/Compilers/ConditionalCompiler.cs @@ -148,7 +148,7 @@ namespace Server.Commands.Generic { var style = NumberStyles.Integer; - if (Insensitive.StartsWith(toParse, "0x")) + if (toParse.InsensitiveStartsWith("0x")) { style = NumberStyles.HexNumber; toParse = toParse.Substring(2); @@ -231,7 +231,6 @@ namespace Server.Commands.Generic NotEqual, Contains, - StartsWith, EndsWith } @@ -260,39 +259,74 @@ namespace Server.Commands.Generic { var inverse = false; + Type type = m_IgnoreCase ? typeof(InsensitiveStringHelpers) : typeof(OrdinalStringHelpers); string methodName; switch (m_Operator) { - case StringOperator.Equal: - methodName = "Equals"; - break; - case StringOperator.NotEqual: - methodName = "Equals"; - inverse = true; - break; + { + inverse = true; + goto case StringOperator.Equal; + } + case StringOperator.Equal: + { + if (m_IgnoreCase) + { + methodName = "InsensitiveEquals"; + } + else + { + methodName = "EqualsOrdinal"; + } + break; + } case StringOperator.Contains: - methodName = "Contains"; - break; + { + if (m_IgnoreCase) + { + methodName = "InsensitiveContains"; + } + else + { + methodName = "ContainsOrdinal"; + } + break; + } case StringOperator.StartsWith: - methodName = "StartsWith"; - break; + { + if (m_IgnoreCase) + { + methodName = "InsensitiveStartsWith"; + } + else + { + methodName = "StartsWithOrdinal"; + } + break; + } case StringOperator.EndsWith: - methodName = "EndsWith"; - break; + { + if (m_IgnoreCase) + { + methodName = "InsensitiveEndsWith"; + } + else + { + methodName = "EndsWithOrdinal"; + } + break; + } default: throw new InvalidOperationException("Invalid string comparison operator."); } - if (m_IgnoreCase || methodName == "Equals") + if (m_Operator == StringOperator.Equal || m_Operator == StringOperator.NotEqual) { - var type = m_IgnoreCase ? typeof(Insensitive) : typeof(string); - emitter.BeginCall( type.GetMethod( methodName, @@ -334,7 +368,7 @@ namespace Server.Commands.Generic emitter.LoadLocal(temp); emitter.BeginCall( - typeof(string).GetMethod( + type.GetMethod( methodName, BindingFlags.Public | BindingFlags.Instance, null, diff --git a/Projects/UOContent/Commands/Generic/Extensions/SortExtension.cs b/Projects/UOContent/Commands/Generic/Extensions/SortExtension.cs index c1ae5f7c7..c81f8f160 100644 --- a/Projects/UOContent/Commands/Generic/Extensions/SortExtension.cs +++ b/Projects/UOContent/Commands/Generic/Extensions/SortExtension.cs @@ -45,7 +45,7 @@ namespace Server.Commands.Generic throw new Exception("Invalid ordering syntax."); } - if (Insensitive.Equals(arguments[offset], "by")) + if (arguments[offset].InsensitiveEquals("by")) { ++offset; --size; diff --git a/Projects/UOContent/Commands/Generic/Implementors/BaseCommandImplementor.cs b/Projects/UOContent/Commands/Generic/Implementors/BaseCommandImplementor.cs index b7d94c243..f6eb94211 100644 --- a/Projects/UOContent/Commands/Generic/Implementors/BaseCommandImplementor.cs +++ b/Projects/UOContent/Commands/Generic/Implementors/BaseCommandImplementor.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Server.Buffers; namespace Server.Commands.Generic { @@ -185,7 +186,7 @@ namespace Server.Commands.Generic // NOTE: this does not preserve the case where quotation marks are used on a single word - var sb = new StringBuilder(); + using var sb = new ValueStringBuilder(stackalloc char[64]); for (var i = 0; i < args.Length; ++i) { @@ -194,7 +195,7 @@ namespace Server.Commands.Generic sb.Append(' '); } - if (args[i].Contains(' ', StringComparison.Ordinal)) + if (args[i].ContainsOrdinal(' ')) { sb.Append('"'); sb.Append(args[i]); diff --git a/Projects/UOContent/Commands/Generic/Implementors/ObjectConditional.cs b/Projects/UOContent/Commands/Generic/Implementors/ObjectConditional.cs index 16411710d..474fe66d4 100644 --- a/Projects/UOContent/Commands/Generic/Implementors/ObjectConditional.cs +++ b/Projects/UOContent/Commands/Generic/Implementors/ObjectConditional.cs @@ -71,7 +71,7 @@ namespace Server.Commands.Generic for (var i = 0; i < args.Length; ++i) { - if (Insensitive.Equals(args[i], "where")) + if (args[i].InsensitiveEquals("where")) { var origArgs = args; @@ -111,9 +111,7 @@ namespace Server.Commands.Generic } var conditions = new List(); - var current = new List(); - - current.Add(TypeCondition.Default); + var current = new List { TypeCondition.Default }; var index = 1; @@ -123,7 +121,7 @@ namespace Server.Commands.Generic var inverse = false; - if (Insensitive.Equals(cur, "not") || cur == "!") + if (cur.InsensitiveEquals("not") || cur == "!") { inverse = true; ++index; @@ -133,7 +131,7 @@ namespace Server.Commands.Generic throw new Exception("Improperly formatted object conditional."); } } - else if (Insensitive.Equals(cur, "or") || cur == "||") + else if (cur.InsensitiveEquals("or") || cur == "||") { if (current.Count > 1) { @@ -199,7 +197,7 @@ namespace Server.Commands.Generic "contains" => new StringCondition(prop, inverse, StringOperator.Contains, val, false), "contains~" => new StringCondition(prop, inverse, StringOperator.Contains, val, true), "~contains" => new StringCondition(prop, inverse, StringOperator.Contains, val, true), - _ => null + _ => null }; if (condition == null) diff --git a/Projects/UOContent/Commands/Handlers.cs b/Projects/UOContent/Commands/Handlers.cs index 469a45a1f..29d4fddde 100644 --- a/Projects/UOContent/Commands/Handlers.cs +++ b/Projects/UOContent/Commands/Handlers.cs @@ -582,7 +582,7 @@ namespace Server.Commands continue; } - if (Insensitive.Equals(name, map.Name)) + if (name.InsensitiveEquals(map.Name)) { from.Map = map; return; @@ -595,7 +595,7 @@ namespace Server.Commands { var r = kvp.Value; - if (Insensitive.Equals(r.Name, name)) + if (r.Name.InsensitiveEquals(name)) { from.Location = new Point3D(r.GoLocation); return; @@ -613,7 +613,7 @@ namespace Server.Commands foreach (var r in map.Regions.Values) { - if (Insensitive.Equals(r.Name, name)) + if (r.Name.InsensitiveEquals(name)) { from.MoveToWorld(r.GoLocation, map); return; @@ -676,8 +676,8 @@ namespace Server.Commands e.GetInt32(0), e.GetInt32(4), e.GetInt32(1), - Insensitive.Equals(e.GetString(5), "E"), - Insensitive.Equals(e.GetString(2), "S") + e.GetString(5).InsensitiveEquals("E"), + e.GetString(2).InsensitiveEquals("S") ); if (p != Point3D.Zero) diff --git a/Projects/UOContent/Commands/HelpInfo.cs b/Projects/UOContent/Commands/HelpInfo.cs index 5f5525719..01bce89f3 100644 --- a/Projects/UOContent/Commands/HelpInfo.cs +++ b/Projects/UOContent/Commands/HelpInfo.cs @@ -94,8 +94,8 @@ namespace Server.Commands var aliases = attrs.Length == 0 ? null : attrs[0] as AliasesAttribute; var descString = desc.Description - .Replace("<", "(", StringComparison.Ordinal) - .Replace(">", ")", StringComparison.Ordinal); + .ReplaceOrdinal("<", "(") + .ReplaceOrdinal(">", ")"); if (aliases == null) { @@ -140,8 +140,8 @@ namespace Server.Commands } desc = desc - .Replace("<", "(", StringComparison.Ordinal) - .Replace(">", ")", StringComparison.Ordinal); + .ReplaceOrdinal("<", "(") + .ReplaceOrdinal(">", ")"); if (command.Supports != CommandSupport.Single) { @@ -229,8 +229,8 @@ namespace Server.Commands } desc = desc - .Replace("<", ")", StringComparison.Ordinal) - .Replace(">", ")", StringComparison.Ordinal); + .ReplaceOrdinal("<", ")") + .ReplaceOrdinal(">", ")"); list.Add(new CommandInfo(command.AccessLevel, cmd, aliases, usage, desc)); @@ -413,8 +413,8 @@ namespace Server.Commands sb.Append("Usage: "); var usage = info.Usage - .Replace("<", "(", StringComparison.Ordinal) - .Replace(">", ")", StringComparison.Ordinal); + .ReplaceOrdinal("<", "(") + .ReplaceOrdinal(">", ")"); sb.Append(usage); sb.Append("
"); diff --git a/Projects/UOContent/Commands/Logging.cs b/Projects/UOContent/Commands/Logging.cs index c99e75867..a116e3dea 100644 --- a/Projects/UOContent/Commands/Logging.cs +++ b/Projects/UOContent/Commands/Logging.cs @@ -114,7 +114,7 @@ namespace Server.Commands for (var i = 0; isSafe && i < m_NotSafe.Length; ++i) { - isSafe = !ip.Contains(m_NotSafe[i], StringComparison.Ordinal); + isSafe = !ip.ContainsOrdinal(m_NotSafe[i]); } if (isSafe) diff --git a/Projects/UOContent/Commands/Object Creation/Add.cs b/Projects/UOContent/Commands/Object Creation/Add.cs index 11aa55635..7f0964875 100644 --- a/Projects/UOContent/Commands/Object Creation/Add.cs +++ b/Projects/UOContent/Commands/Object Creation/Add.cs @@ -89,7 +89,7 @@ namespace Server.Commands for (var i = 0; i < args.Length; ++i) { - if (Insensitive.Equals(args[i], "set")) + if (args[i].InsensitiveEquals("set")) { var remains = args.Length - i - 1; @@ -179,7 +179,7 @@ namespace Server.Commands for (var j = 0; thisProp == null && j < allProps.Length; ++j) { - if (Insensitive.Equals(propName, allProps[j].Name)) + if (propName.InsensitiveEquals(allProps[j].Name)) { thisProp = allProps[j]; } @@ -300,7 +300,7 @@ namespace Server.Commands object obj = value; - if (value?.StartsWith("0x", StringComparison.Ordinal) == true) + if (value.StartsWithOrdinal("0x")) { if (IsSignedNumeric(type)) { diff --git a/Projects/UOContent/Commands/Object Creation/AddGump.cs b/Projects/UOContent/Commands/Object Creation/AddGump.cs index 585b5fd1e..e4bb04815 100644 --- a/Projects/UOContent/Commands/Object Creation/AddGump.cs +++ b/Projects/UOContent/Commands/Object Creation/AddGump.cs @@ -134,7 +134,7 @@ namespace Server.Gumps var t = types[i]; if ((typeofMobile.IsAssignableFrom(t) || typeofItem.IsAssignableFrom(t)) && - t.Name.ToLower().Contains(match, StringComparison.Ordinal) && !results.Contains(t)) + t.Name.InsensitiveContains(match) && !results.Contains(t)) { var ctors = t.GetConstructors(); diff --git a/Projects/UOContent/Commands/Object Creation/Categorization.cs b/Projects/UOContent/Commands/Object Creation/Categorization.cs index 5745c65be..c4e60ac6d 100644 --- a/Projects/UOContent/Commands/Object Creation/Categorization.cs +++ b/Projects/UOContent/Commands/Object Creation/Categorization.cs @@ -304,7 +304,7 @@ namespace Server.Commands var text = lines[index].Text; - var start = text.IndexOf('(', StringComparison.Ordinal); + var start = text.IndexOfOrdinal('('); if (start < 0) { diff --git a/Projects/UOContent/Commands/Object Creation/Decorate.cs b/Projects/UOContent/Commands/Object Creation/Decorate.cs index c035849fa..e02f19a3a 100644 --- a/Projects/UOContent/Commands/Object Creation/Decorate.cs +++ b/Projects/UOContent/Commands/Object Creation/Decorate.cs @@ -103,9 +103,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("LabelNumber", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("LabelNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -123,9 +123,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("LabelNumber", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("LabelNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -171,9 +171,9 @@ namespace Server.Commands { locked = true; } - else if (m_Params[i].StartsWith("TargetMap", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("TargetMap")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -200,54 +200,54 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Range", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Range")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { range = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("WarningString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("WarningNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("HintString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("HintString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { hintString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("HintNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("HintNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { hintNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("ResetDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("ResetDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -273,36 +273,36 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Range", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Range")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { range = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("WarningString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("WarningNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("ResetDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("ResetDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -324,9 +324,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("CannonDirection", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("CannonDirection")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -348,27 +348,27 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Word", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Word")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { word = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("DestStart", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestStart")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { destination.Start = Point2D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEnd", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEnd")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -386,9 +386,9 @@ namespace Server.Commands for (var i = 0; !fill && i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Content", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Content")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -417,9 +417,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Facing", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Facing")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -447,9 +447,9 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("SpawnLocation", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("SpawnLocation")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -515,45 +515,45 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Spawn", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Spawn")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.AddEntry(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MinDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MinDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.MinDelay = TimeSpan.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MaxDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MaxDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.MaxDelay = TimeSpan.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("NextSpawn", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("NextSpawn")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.NextSpawn = TimeSpan.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Count", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Count")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -564,36 +564,36 @@ namespace Server.Commands } } } - else if (m_Params[i].StartsWith("Team", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Team")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.Team = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("HomeRange", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("HomeRange")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.HomeRange = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Running", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Running")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.Running = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Group", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Group")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -606,36 +606,36 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Description", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Description")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { rune.Description = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("Marked", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Marked")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { rune.Marked = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("TargetMap", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("TargetMap")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { rune.TargetMap = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Target", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Target")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -648,108 +648,108 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Skill", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Skill")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Skill = (SkillName)Enum.Parse(typeof(SkillName), m_Params[i].Substring(++indexOf), true); } } - else if (m_Params[i].StartsWith("RequiredFixedPoint", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("RequiredFixedPoint")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Required = Utility.ToInt32(m_Params[i].Substring(++indexOf)) * 0.1; } } - else if (m_Params[i].StartsWith("Required", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Required")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Required = Utility.ToDouble(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MessageString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MessageString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.MessageString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("MessageNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MessageNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.MessageNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("PointDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("PointDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.PointDest = Point3D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MapDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MapDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.MapDest = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Creatures", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Creatures")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Creatures = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SourceEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SourceEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.SourceEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.DestEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SoundID", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SoundID")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.SoundID = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Delay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Delay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -767,90 +767,90 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Substring", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Substring")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Substring = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("Keyword", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Keyword")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Keyword = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Range", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Range")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Range = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("PointDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("PointDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.PointDest = Point3D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MapDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MapDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.MapDest = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Creatures", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Creatures")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Creatures = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SourceEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SourceEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.SourceEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.DestEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SoundID", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SoundID")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.SoundID = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Delay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Delay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -868,63 +868,63 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("PointDest", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("PointDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.PointDest = Point3D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MapDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MapDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.MapDest = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Creatures", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Creatures")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.Creatures = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SourceEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SourceEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.SourceEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.DestEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SoundID", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SoundID")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.SoundID = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Delay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Delay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -942,9 +942,9 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("ContentType", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("ContentType")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -971,18 +971,18 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Light", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Light")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { item.Light = (LightType)Enum.Parse(typeof(LightType), m_Params[i].Substring(++indexOf), true); } } - else if (m_Params[i].StartsWith("Hue", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Hue")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -998,18 +998,18 @@ namespace Server.Commands } } } - else if (m_Params[i].StartsWith("Name", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Name")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { item.Name = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("Amount", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Amount")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -1248,7 +1248,7 @@ namespace Server.Commands { line = line.Trim(); - if (line.Length > 0 && !line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length > 0 && !line.StartsWithOrdinal("#")) { break; } @@ -1261,7 +1261,7 @@ namespace Server.Commands var list = new DecorationList(); - var indexOf = line.IndexOf(' ', StringComparison.Ordinal); + var indexOf = line.IndexOfOrdinal(' '); list.m_Type = AssemblyHandler.FindFirstTypeForName(line.Substring(0, indexOf++), true); @@ -1271,14 +1271,14 @@ namespace Server.Commands } line = line.Substring(indexOf); - indexOf = line.IndexOf('(', StringComparison.Ordinal); + indexOf = line.IndexOfOrdinal('('); if (indexOf >= 0) { list.m_ItemID = Utility.ToInt32(line.Substring(0, indexOf - 1)); var parms = line.Substring(++indexOf); - if (line.EndsWith(")", StringComparison.Ordinal)) + if (line.EndsWithOrdinal(")")) { parms = parms.Substring(0, parms.Length - 1); } @@ -1307,7 +1307,7 @@ namespace Server.Commands break; } - if (line.StartsWith("#", StringComparison.Ordinal)) + if (line.StartsWithOrdinal("#")) { continue; } @@ -1337,7 +1337,7 @@ namespace Server.Commands public static void Pop(out string v, ref string line) { - var space = line.IndexOf(' ', StringComparison.Ordinal); + var space = line.IndexOfOrdinal(' '); if (space >= 0) { diff --git a/Projects/UOContent/Commands/Object Creation/DecorateMag.cs b/Projects/UOContent/Commands/Object Creation/DecorateMag.cs index 67220c553..2d03a1a0f 100644 --- a/Projects/UOContent/Commands/Object Creation/DecorateMag.cs +++ b/Projects/UOContent/Commands/Object Creation/DecorateMag.cs @@ -100,9 +100,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("LabelNumber", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("LabelNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -120,9 +120,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("LabelNumber", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("LabelNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -168,9 +168,9 @@ namespace Server.Commands { locked = true; } - else if (m_Params[i].StartsWith("TargetMap", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("TargetMap")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -197,54 +197,54 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Range", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Range")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { range = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("WarningString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("WarningNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("HintString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("HintString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { hintString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("HintNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("HintNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { hintNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("ResetDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("ResetDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -270,36 +270,36 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Range", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Range")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { range = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("WarningString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("WarningNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("WarningNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { messageNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("ResetDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("ResetDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -321,9 +321,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("CannonDirection", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("CannonDirection")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -345,27 +345,27 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Word", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Word")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { word = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("DestStart", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestStart")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { destination.Start = Point2D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEnd", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEnd")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -383,9 +383,9 @@ namespace Server.Commands for (var i = 0; !fill && i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Content", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Content")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -414,9 +414,9 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Facing", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Facing")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -444,9 +444,9 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("SpawnLocation", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("SpawnLocation")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -512,45 +512,45 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Spawn", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Spawn")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.AddEntry(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MinDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MinDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.MinDelay = TimeSpan.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MaxDelay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MaxDelay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.MaxDelay = TimeSpan.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("NextSpawn", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("NextSpawn")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.NextSpawn = TimeSpan.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Count", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Count")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -561,36 +561,36 @@ namespace Server.Commands } } } - else if (m_Params[i].StartsWith("Team", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Team")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.Team = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("HomeRange", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("HomeRange")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.HomeRange = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Running", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Running")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { sp.Running = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Group", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Group")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -603,36 +603,36 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Description", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Description")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { rune.Description = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("Marked", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Marked")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { rune.Marked = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("TargetMap", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("TargetMap")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { rune.TargetMap = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Target", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Target")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -645,108 +645,108 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Skill", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Skill")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Skill = (SkillName)Enum.Parse(typeof(SkillName), m_Params[i].Substring(++indexOf), true); } } - else if (m_Params[i].StartsWith("RequiredFixedPoint", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("RequiredFixedPoint")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Required = Utility.ToInt32(m_Params[i].Substring(++indexOf)) * 0.1; } } - else if (m_Params[i].StartsWith("Required", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Required")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Required = Utility.ToDouble(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MessageString", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MessageString")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.MessageString = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("MessageNumber", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MessageNumber")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.MessageNumber = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("PointDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("PointDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.PointDest = Point3D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MapDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MapDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.MapDest = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Creatures", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Creatures")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.Creatures = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SourceEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SourceEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.SourceEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.DestEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SoundID", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SoundID")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { st.SoundID = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Delay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Delay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -764,90 +764,90 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Substring", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Substring")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Substring = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("Keyword", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Keyword")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Keyword = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Range", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Range")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Range = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("PointDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("PointDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.PointDest = Point3D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MapDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MapDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.MapDest = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Creatures", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Creatures")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.Creatures = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SourceEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SourceEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.SourceEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.DestEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SoundID", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SoundID")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { kt.SoundID = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Delay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Delay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -865,63 +865,63 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("PointDest", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("PointDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.PointDest = Point3D.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("MapDest", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("MapDest")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.MapDest = Map.Parse(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Creatures", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Creatures")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.Creatures = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SourceEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SourceEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.SourceEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("DestEffect", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("DestEffect")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.DestEffect = Utility.ToBoolean(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("SoundID", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("SoundID")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { tp.SoundID = Utility.ToInt32(m_Params[i].Substring(++indexOf)); } } - else if (m_Params[i].StartsWith("Delay", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Delay")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -939,9 +939,9 @@ namespace Server.Commands { for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("ContentType", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("ContentType")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -968,18 +968,18 @@ namespace Server.Commands for (var i = 0; i < m_Params.Length; ++i) { - if (m_Params[i].StartsWith("Light", StringComparison.Ordinal)) + if (m_Params[i].StartsWithOrdinal("Light")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { item.Light = (LightType)Enum.Parse(typeof(LightType), m_Params[i].Substring(++indexOf), true); } } - else if (m_Params[i].StartsWith("Hue", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Hue")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -995,18 +995,18 @@ namespace Server.Commands } } } - else if (m_Params[i].StartsWith("Name", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Name")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { item.Name = m_Params[i].Substring(++indexOf); } } - else if (m_Params[i].StartsWith("Amount", StringComparison.Ordinal)) + else if (m_Params[i].StartsWithOrdinal("Amount")) { - var indexOf = m_Params[i].IndexOf('=', StringComparison.Ordinal); + var indexOf = m_Params[i].IndexOfOrdinal('='); if (indexOf >= 0) { @@ -1235,7 +1235,7 @@ namespace Server.Commands { line = line.Trim(); - if (line.Length > 0 && !line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length > 0 && !line.StartsWithOrdinal("#")) { break; } @@ -1248,7 +1248,7 @@ namespace Server.Commands var list = new DecorationListMag(); - var indexOf = line.IndexOf(' ', StringComparison.Ordinal); + var indexOf = line.IndexOfOrdinal(' '); list.m_Type = AssemblyHandler.FindFirstTypeForName(line.Substring(0, indexOf++), true); @@ -1258,14 +1258,14 @@ namespace Server.Commands } line = line.Substring(indexOf); - indexOf = line.IndexOf('(', StringComparison.Ordinal); + indexOf = line.IndexOfOrdinal('('); if (indexOf >= 0) { list.m_ItemID = Utility.ToInt32(line.Substring(0, indexOf - 1)); var parms = line.Substring(++indexOf); - if (line.EndsWith(")", StringComparison.Ordinal)) + if (line.EndsWithOrdinal(")")) { parms = parms.Substring(0, parms.Length - 1); } @@ -1294,7 +1294,7 @@ namespace Server.Commands break; } - if (line.StartsWith("#", StringComparison.Ordinal)) + if (line.StartsWithOrdinal("#")) { continue; } @@ -1324,7 +1324,7 @@ namespace Server.Commands public void Pop(out string v, ref string line) { - var space = line.IndexOf(' ', StringComparison.Ordinal); + var space = line.IndexOfOrdinal(' '); if (space >= 0) { diff --git a/Projects/UOContent/Commands/Properties.cs b/Projects/UOContent/Commands/Properties.cs index 9890176be..7d2ce7715 100644 --- a/Projects/UOContent/Commands/Properties.cs +++ b/Projects/UOContent/Commands/Properties.cs @@ -76,7 +76,7 @@ namespace Server.Commands } } - private static bool CIEqual(string l, string r) => Insensitive.Equals(l, r); + private static bool CIEqual(string l, string r) => l.InsensitiveEquals(r); public static CPA GetCPA(PropertyInfo p) { @@ -254,7 +254,7 @@ namespace Server.Commands { var valueString = args[1 + i * 2]; - if (valueString.StartsWith("0x", StringComparison.Ordinal)) + if (valueString.StartsWithOrdinal("0x")) { realValues[i] = Convert.ToInt32(valueString.Substring(2), 16); } @@ -483,7 +483,7 @@ namespace Server.Commands { toSet = null; } - else if (value.StartsWith("0x", StringComparison.Ordinal) && IsNumeric(type)) + else if (value.StartsWithOrdinal("0x") && IsNumeric(type)) { try { diff --git a/Projects/UOContent/Commands/SignParser.cs b/Projects/UOContent/Commands/SignParser.cs index 0cf0f417a..c26f5fe5d 100644 --- a/Projects/UOContent/Commands/SignParser.cs +++ b/Projects/UOContent/Commands/SignParser.cs @@ -108,7 +108,7 @@ namespace Server.Commands Item sign; - if (name.StartsWith("#", StringComparison.Ordinal)) + if (name.StartsWithOrdinal("#")) { sign = new LocalizedSign(itemID, Utility.ToInt32(name.Substring(1))); } diff --git a/Projects/UOContent/Commands/Statics.cs b/Projects/UOContent/Commands/Statics.cs index 12ff060f5..015136f82 100644 --- a/Projects/UOContent/Commands/Statics.cs +++ b/Projects/UOContent/Commands/Statics.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using Server.Commands; @@ -715,7 +716,7 @@ namespace Server if (m_Buffer == null || length > m_Buffer.Length) { - m_Buffer = new byte[length]; + m_Buffer = GC.AllocateUninitializedArray(length); } mulStream.Read(m_Buffer, 0, length); diff --git a/Projects/UOContent/Engines/BulkOrders/SmallBulkEntry.cs b/Projects/UOContent/Engines/BulkOrders/SmallBulkEntry.cs index 431307e6e..3d76aa1c7 100644 --- a/Projects/UOContent/Engines/BulkOrders/SmallBulkEntry.cs +++ b/Projects/UOContent/Engines/BulkOrders/SmallBulkEntry.cs @@ -65,7 +65,7 @@ namespace Server.Engines.BulkOrders while ((line = ip.ReadLine()) != null) { - if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length == 0 || line.StartsWithOrdinal("#")) { continue; } diff --git a/Projects/UOContent/Engines/Chat/Channel.cs b/Projects/UOContent/Engines/Chat/Channel.cs index 190415f2d..2128eeb21 100644 --- a/Projects/UOContent/Engines/Chat/Channel.cs +++ b/Projects/UOContent/Engines/Chat/Channel.cs @@ -76,7 +76,7 @@ namespace Server.Engines.Chat public bool IsVoiced(ChatUser user) => m_Voices.Contains(user); - public bool ValidatePassword(string password) => m_Password == null || Insensitive.Equals(m_Password, password); + public bool ValidatePassword(string password) => m_Password == null || m_Password.InsensitiveEquals(password); public bool ValidateModerator(ChatUser user) { diff --git a/Projects/UOContent/Engines/Chat/ChatActionHandlers.cs b/Projects/UOContent/Engines/Chat/ChatActionHandlers.cs index 504b776b2..64e071a75 100644 --- a/Projects/UOContent/Engines/Chat/ChatActionHandlers.cs +++ b/Projects/UOContent/Engines/Chat/ChatActionHandlers.cs @@ -86,7 +86,7 @@ namespace Server.Engines.Chat public static void PrivateMessage(ChatUser from, Channel channel, string param) { - var indexOf = param.IndexOf(' ', StringComparison.Ordinal); + var indexOf = param.IndexOfOrdinal(' '); var name = param.Substring(0, indexOf); var text = param.Substring(indexOf + 1); @@ -173,7 +173,7 @@ namespace Server.Engines.Chat string name; string password = null; - var start = param.IndexOf('\"', StringComparison.Ordinal); + var start = param.IndexOfOrdinal('\"'); if (start >= 0) { @@ -191,7 +191,7 @@ namespace Server.Engines.Chat } else { - var indexOf = param.IndexOf(' ', StringComparison.Ordinal); + var indexOf = param.IndexOfOrdinal(' '); if (indexOf >= 0) { @@ -228,7 +228,7 @@ namespace Server.Engines.Chat string name; string password = null; - var start = param.IndexOf('{', StringComparison.Ordinal); + var start = param.IndexOfOrdinal('{'); if (start >= 0) { diff --git a/Projects/UOContent/Engines/ConPVP/DuelContext.cs b/Projects/UOContent/Engines/ConPVP/DuelContext.cs index abdbbbc26..392e7ecf3 100644 --- a/Projects/UOContent/Engines/ConPVP/DuelContext.cs +++ b/Projects/UOContent/Engines/ConPVP/DuelContext.cs @@ -1396,7 +1396,7 @@ namespace Server.Engines.ConPVP return; } - if (Insensitive.Contains(e.Speech, "i wish to duel")) + if (e.Speech.InsensitiveContains("i wish to duel")) { if (!pm.CheckAlive()) { @@ -1432,7 +1432,7 @@ namespace Server.Engines.ConPVP e.Handled = true; } } - else if (Insensitive.Equals(e.Speech, "change arena preferences")) + else if (e.Speech.InsensitiveEquals("change arena preferences")) { if (!pm.CheckAlive()) { @@ -1448,7 +1448,7 @@ namespace Server.Engines.ConPVP } } } - else if (Insensitive.Equals(e.Speech, "showladder")) + else if (e.Speech.InsensitiveEquals("showladder")) { e.Blocked = true; if (!pm.CheckAlive()) @@ -1487,7 +1487,7 @@ namespace Server.Engines.ConPVP } } } - else if (Insensitive.Equals(e.Speech, "viewladder")) + else if (e.Speech.InsensitiveEquals("viewladder")) { e.Blocked = true; @@ -1509,7 +1509,7 @@ namespace Server.Engines.ConPVP } } } - else if (Insensitive.Contains(e.Speech, "i yield")) + else if (e.Speech.InsensitiveContains("i yield")) { if (!pm.CheckAlive()) { diff --git a/Projects/UOContent/Engines/ConPVP/Games/DoubleDom.cs b/Projects/UOContent/Engines/ConPVP/Games/DoubleDom.cs index f38c251a7..fb880c190 100644 --- a/Projects/UOContent/Engines/ConPVP/Games/DoubleDom.cs +++ b/Projects/UOContent/Engines/ConPVP/Games/DoubleDom.cs @@ -122,7 +122,10 @@ namespace Server.Engines.ConPVP { for (var i = 0; i < entries.Count; ++i) { - var teamInfo = entries[i] as DDTeamInfo; + if (entries[i] is not DDTeamInfo teamInfo) + { + continue; + } AddImage(30, 70 + i * 75, 10152); AddImage(30, 85 + i * 75, 10151); @@ -884,7 +887,7 @@ namespace Server.Engines.ConPVP } } - if (i == winner.TeamID) + if (i == winner?.TeamID) { continue; } @@ -898,7 +901,10 @@ namespace Server.Engines.ConPVP } } - m_Context.Finish(m_Context.Participants[winner.TeamID]); + if (winner != null) + { + m_Context.Finish(m_Context.Participants[winner.TeamID]); + } } public override void OnStop() diff --git a/Projects/UOContent/Engines/ConPVP/Gumps/TournamentBracketGump.cs b/Projects/UOContent/Engines/ConPVP/Gumps/TournamentBracketGump.cs index c5e4ce1a5..d35084f89 100644 --- a/Projects/UOContent/Engines/ConPVP/Gumps/TournamentBracketGump.cs +++ b/Projects/UOContent/Engines/ConPVP/Gumps/TournamentBracketGump.cs @@ -279,7 +279,7 @@ namespace Server.Engines.ConPVP AddPage(0); AddBackground(0, 0, 300, 300, 9380); - var pList = m_List?.CastListCovariant() + var pList = m_List?.SafeConvertList() ?? new List(tourney.Participants); AddLeftArrow(25, 11, ToButtonID(0, 0)); @@ -412,10 +412,6 @@ namespace Server.Engines.ConPVP AddLeftArrow(25, 11, ToButtonID(0, 0)); AddHtml(25, 35, 250, 20, Center("Rounds")); - // List levelsList = m_List != null - // ? Utility.CastListCovariant(m_List) - // : new List(tourney.Pyramid.Levels); - StartPage(out var index, out var count, out var y, 12); for (var i = 0; i < count; ++i, y += 18) @@ -439,7 +435,7 @@ namespace Server.Engines.ConPVP } var matchesList = m_List != null - ? m_List.CastListCovariant() + ? m_List.SafeConvertList() : new List(level.Matches); AddRightArrow( diff --git a/Projects/UOContent/Engines/Ethics/Core/Ethic.cs b/Projects/UOContent/Engines/Ethics/Core/Ethic.cs index c2d777e36..c6859ac15 100644 --- a/Projects/UOContent/Engines/Ethics/Core/Ethic.cs +++ b/Projects/UOContent/Engines/Ethics/Core/Ethic.cs @@ -151,7 +151,7 @@ namespace Server.Ethics continue; } - if (!Insensitive.Equals(ethic.Definition.JoinPhrase.String, e.Speech)) + if (!ethic.Definition.JoinPhrase.String.InsensitiveEquals(e.Speech)) { continue; } @@ -185,7 +185,7 @@ namespace Server.Ethics { var power = ethic.Definition.Powers[i]; - if (!Insensitive.Equals(power.Definition.Phrase.String, e.Speech)) + if (!power.Definition.Phrase.String.InsensitiveEquals(e.Speech)) { continue; } diff --git a/Projects/UOContent/Engines/Factions/Core/Faction.cs b/Projects/UOContent/Engines/Factions/Core/Faction.cs index 05009ec15..bec06efc5 100644 --- a/Projects/UOContent/Engines/Factions/Core/Faction.cs +++ b/Projects/UOContent/Engines/Factions/Core/Faction.cs @@ -1277,7 +1277,7 @@ namespace Server.Factions { var faction = factions[i]; - if (Insensitive.Equals(faction.Definition.FriendlyName, name)) + if (faction.Definition.FriendlyName.InsensitiveEquals(name)) { return faction; } diff --git a/Projects/UOContent/Engines/Factions/Core/Town.cs b/Projects/UOContent/Engines/Factions/Core/Town.cs index 0b7b377a9..6952a5bb3 100644 --- a/Projects/UOContent/Engines/Factions/Core/Town.cs +++ b/Projects/UOContent/Engines/Factions/Core/Town.cs @@ -536,7 +536,7 @@ namespace Server.Factions { var town = towns[i]; - if (Insensitive.Equals(town.Definition.FriendlyName, name)) + if (town.Definition.FriendlyName.InsensitiveEquals(name)) { return town; } diff --git a/Projects/UOContent/Engines/Factions/Mobiles/Guards/BaseFactionGuard.cs b/Projects/UOContent/Engines/Factions/Mobiles/Guards/BaseFactionGuard.cs index d0faec3f1..29bcef7da 100644 --- a/Projects/UOContent/Engines/Factions/Mobiles/Guards/BaseFactionGuard.cs +++ b/Projects/UOContent/Engines/Factions/Mobiles/Guards/BaseFactionGuard.cs @@ -205,7 +205,7 @@ namespace Server.Factions { var name = Name; - return name != null && Insensitive.StartsWith(speech, name); + return name != null && speech.InsensitiveStartsWith(name); } public override void OnSpeech(SpeechEventArgs e) @@ -216,7 +216,7 @@ namespace Server.Factions if (!e.Handled && InRange(from, ListenRange) && from.Alive) { - if (e.HasKeyword(0xE6) && (Insensitive.Equals(e.Speech, "orders") || WasNamed(e.Speech))) // *orders* + if (e.HasKeyword(0xE6) && (e.Speech.InsensitiveEquals("orders") || WasNamed(e.Speech))) // *orders* { if (m_Town?.IsSheriff(from) != true) { @@ -240,15 +240,15 @@ namespace Server.Factions var understood = true; ReactionType newType = 0; - if (Insensitive.Contains(e.Speech, "attack")) + if (e.Speech.InsensitiveContains("attack")) { newType = ReactionType.Attack; } - else if (Insensitive.Contains(e.Speech, "warn")) + else if (e.Speech.InsensitiveContains("warn")) { newType = ReactionType.Warn; } - else if (Insensitive.Contains(e.Speech, "ignore")) + else if (e.Speech.InsensitiveContains("ignore")) { newType = ReactionType.Ignore; } @@ -261,7 +261,7 @@ namespace Server.Factions { understood = false; - if (Insensitive.Contains(e.Speech, "civil")) + if (e.Speech.InsensitiveContains("civil")) { ChangeReaction(null, newType); understood = true; @@ -273,14 +273,14 @@ namespace Server.Factions { var faction = factions[i]; - if (faction != m_Faction && Insensitive.Contains(e.Speech, faction.Definition.Keyword)) + if (faction != m_Faction && e.Speech.InsensitiveContains(faction.Definition.Keyword)) { ChangeReaction(faction, newType); understood = true; } } } - else if (Insensitive.Contains(e.Speech, "patrol")) + else if (e.Speech.InsensitiveContains("patrol")) { Home = Location; RangeHome = 6; @@ -289,7 +289,7 @@ namespace Server.Factions Say(1005146); // This spot looks like it needs protection! I shall guard it with my life. understood = true; } - else if (Insensitive.Contains(e.Speech, "follow")) + else if (e.Speech.InsensitiveContains("follow")) { Home = Location; RangeHome = 6; diff --git a/Projects/UOContent/Engines/Help/PageQueueGump.cs b/Projects/UOContent/Engines/Help/PageQueueGump.cs index 5a1c7e8ac..2289e0ad9 100644 --- a/Projects/UOContent/Engines/Help/PageQueueGump.cs +++ b/Projects/UOContent/Engines/Help/PageQueueGump.cs @@ -188,7 +188,7 @@ namespace Server.Engines.Help while ((line = ip.ReadLine()?.Trim()) != null) { - if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length == 0 || line.StartsWithOrdinal("#")) { continue; } diff --git a/Projects/UOContent/Engines/MLQuests/MLQuestSystem.cs b/Projects/UOContent/Engines/MLQuests/MLQuestSystem.cs index 1c339d910..ca9a6968c 100644 --- a/Projects/UOContent/Engines/MLQuests/MLQuestSystem.cs +++ b/Projects/UOContent/Engines/MLQuests/MLQuestSystem.cs @@ -44,7 +44,7 @@ namespace Server.Engines.MLQuests { line = line.Trim(); - if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length == 0 || line.StartsWithOrdinal("#")) { continue; } diff --git a/Projects/UOContent/Engines/Pathing/FastMovement.cs b/Projects/UOContent/Engines/Pathing/FastMovement.cs index 4f2ad387c..6eef714b8 100644 --- a/Projects/UOContent/Engines/Pathing/FastMovement.cs +++ b/Projects/UOContent/Engines/Pathing/FastMovement.cs @@ -245,7 +245,7 @@ namespace Server.Movement { itemData = TileData.ItemTable[tile.ID & TileData.MaxItemValue]; - if (m.Flying && Insensitive.Equals(itemData.Name, "hover over")) + if (m.Flying && itemData.Name.InsensitiveEquals("hover over")) { newZ = tile.Z; return true; @@ -350,7 +350,7 @@ namespace Server.Movement itemData = item.ItemData; flags = itemData.Flags; - if (m.Flying && Insensitive.Equals(itemData.Name, "hover over")) + if (m.Flying && itemData.Name.InsensitiveEquals("hover over")) { newZ = item.Z; return true; diff --git a/Projects/UOContent/Engines/Spawners/BaseSpawner.cs b/Projects/UOContent/Engines/Spawners/BaseSpawner.cs index 4ea70a221..44e370459 100644 --- a/Projects/UOContent/Engines/Spawners/BaseSpawner.cs +++ b/Projects/UOContent/Engines/Spawners/BaseSpawner.cs @@ -519,7 +519,7 @@ namespace Server.Engines.Spawners for (var j = 0; thisProp == null && j < allProps.Length; ++j) { - if (Insensitive.Equals(propName, allProps[j].Name)) + if (propName.InsensitiveEquals(allProps[j].Name)) { thisProp = allProps[j]; } diff --git a/Projects/UOContent/Gumps/AdminGump.cs b/Projects/UOContent/Gumps/AdminGump.cs index afc6aed45..d131c8154 100644 --- a/Projects/UOContent/Gumps/AdminGump.cs +++ b/Projects/UOContent/Gumps/AdminGump.cs @@ -167,7 +167,7 @@ namespace Server.Gumps AddLabel(150, 150, LabelHue, banned.ToString()); AddLabel(20, 170, LabelHue, "Firewalled:"); - AddLabel(150, 170, LabelHue, Firewall.List.Count.ToString()); + AddLabel(150, 170, LabelHue, Firewall.Set.Count.ToString()); AddLabel(20, 190, LabelHue, "Clients:"); AddLabel(150, 190, LabelHue, TcpServer.Instances.Count.ToString()); @@ -196,8 +196,8 @@ namespace Server.Gumps AddLabel(20, 350, LabelHue, "Operating System: "); var os = Environment.OSVersion.ToString(); - os = os.Replace("Microsoft", "MSFT", StringComparison.Ordinal); - os = os.Replace("Service Pack", "SP", StringComparison.Ordinal); + os = os.ReplaceOrdinal("Microsoft", "MSFT"); + os = os.ReplaceOrdinal("Service Pack", "SP"); AddLabel(150, 350, LabelHue, os); @@ -612,11 +612,12 @@ namespace Server.Gumps if (m_List == null) { sharedAccounts = GetAllSharedAccounts(); - m_List = sharedAccounts.CastListContravariant>, object>(); + // TODO: Find a better way, don't use KVPs? + m_List = sharedAccounts.ConvertAll(kvp => (object)kvp); } else { - sharedAccounts = m_List.CastListCovariant>>(); + sharedAccounts = m_List.SafeConvertList>>(); } AddLabelCropped(12, 120, 60, 20, LabelHue, "Count"); @@ -1004,11 +1005,11 @@ namespace Server.Gumps if (m_List == null) { ipAddresses = a.LoginIPs.ToList(); - m_List = ipAddresses.CastListContravariant(); + m_List = ipAddresses.ToList(); } else { - ipAddresses = m_List.CastListCovariant(); + ipAddresses = m_List.SafeConvertList(); } AddHtml(10, 195, 400, 20, Color(Center("Client Addresses"), LabelColor32)); @@ -1076,11 +1077,11 @@ namespace Server.Gumps if (m_List == null) { ipRestrictions = a.IPRestrictions.ToList(); - m_List = ipRestrictions.CastListContravariant(); + m_List = ipRestrictions.ToList(); } else { - ipRestrictions = m_List.CastListCovariant(); + ipRestrictions = m_List.SafeConvertList(); } AddHtml(10, 195, 400, 20, Color(Center("Address Restrictions"), LabelColor32)); @@ -1260,16 +1261,16 @@ namespace Server.Gumps { AddFirewallHeader(); - List firewallEntries; + HashSet firewallEntries; if (m_List == null) { - firewallEntries = Firewall.List; - m_List = firewallEntries.CastListContravariant(); + firewallEntries = Firewall.Set; + m_List = firewallEntries.ToList(); } else { - firewallEntries = m_List.CastListCovariant(); + firewallEntries = m_List.SafeConvertSet(); } AddLabelCropped(12, 120, 358, 20, LabelHue, "IP Address"); @@ -1296,17 +1297,22 @@ namespace Server.Gumps { AddLabel(12, 140, LabelHue, "The firewall list is empty."); } - - for (int i = 0, index = listPage * 12; - i < 12 && index >= 0 && index < firewallEntries.Count; - ++i, ++index) + else { - var firewallEntry = firewallEntries[index]; + var i = 0; + var index = listPage * 12; + foreach (var firewallEntry in firewallEntries) + { + if (i >= 12) + { + break; + } - var offset = 140 + i * 20; + var offset = 140 + i++ * 20; - AddLabelCropped(12, offset, 358, 20, LabelHue, firewallEntry.ToString()); - AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(6, index + 4)); + AddLabelCropped(12, offset, 358, 20, LabelHue, firewallEntry.ToString()); + AddButton(380, offset - 1, 0xFA5, 0xFA7, GetButtonID(6, index++ + 4)); + } } break; @@ -1351,11 +1357,11 @@ namespace Server.Gumps } blockedAccts.Sort(AccountComparer.Instance); - m_List = blockedAccts.CastListContravariant(); + m_List = blockedAccts.ToList(); } else { - blockedAccts = m_List.CastListCovariant(); + blockedAccts = m_List.SafeConvertList(); } if (listPage > 0) @@ -1968,7 +1974,7 @@ namespace Server.Gumps if (m_PageType == AdminGumpPage.Accounts) { - var list = m_List.CastListCovariant(); + var list = m_List.SafeConvertList(); if (list != null && m_State is List rads) { @@ -2453,12 +2459,12 @@ namespace Server.Gumps var m = ns.Mobile; var a = ns.Account; - isMatch = m?.Name.ToLower().Contains(match, StringComparison.Ordinal) == true - || a?.Username.ToLower().Contains(match, StringComparison.Ordinal) == true; + isMatch = m?.Name.InsensitiveContains(match) == true + || a?.Username.InsensitiveContains(match) == true; } else { - isMatch = ns.ToString().Contains(match, StringComparison.Ordinal); + isMatch = ns.ToString().ContainsOrdinal(match); } if (isMatch) @@ -2508,7 +2514,7 @@ namespace Server.Gumps from, AdminGumpPage.Clients, 0, - results.CastListContravariant(), + results.ToList(), "One match found." ) ); @@ -2521,7 +2527,7 @@ namespace Server.Gumps from, AdminGumpPage.Clients, 0, - results.CastListContravariant(), + results.ToList(), notice ?? (results.Count == 0 ? "Nothing matched your search terms." : null) ) ); @@ -2715,8 +2721,7 @@ namespace Server.Gumps else { results = Accounts.GetAccounts() - .Where(acct => - acct.Username.ToLower().Contains(match, StringComparison.Ordinal)) + .Where(acct => acct.Username.InsensitiveContains(match)) .ToList(); results.Sort(AccountComparer.Instance); } @@ -2741,7 +2746,7 @@ namespace Server.Gumps from, AdminGumpPage.Accounts, 0, - results.CastListContravariant(), + results.ToList(), results.Count == 0 ? "Nothing matched your search terms." : null, new List() ) @@ -2869,7 +2874,7 @@ namespace Server.Gumps from, AdminGumpPage.Accounts, 0, - list.CastListContravariant(), + list.ToList(), null, new List() ) @@ -3492,7 +3497,7 @@ namespace Server.Gumps from, AdminGumpPage.Accounts, 0, - kvp.Value.CastListContravariant(), + kvp.Value.ToList(), null, new List() ) @@ -3525,13 +3530,13 @@ namespace Server.Gumps } else { - for (var i = 0; i < Firewall.List.Count; ++i) + foreach (var check in Firewall.Set) { - var check = Firewall.List[i].ToString(); + var checkStr = check.ToString(); - if (check?.Contains(match, StringComparison.Ordinal) == true) + if (checkStr.ContainsOrdinal(match)) { - results.Add(Firewall.List[i]); + results.Add(check); } } } @@ -3958,7 +3963,7 @@ namespace Server.Gumps from, AdminGumpPage.Accounts, 0, - list.CastListContravariant(), + list.ToList(), null, new List() ) @@ -4222,7 +4227,7 @@ namespace Server.Gumps return -1; } - return aMob.AccessLevel < bMob.AccessLevel ? 1 : Insensitive.Compare(aMob.Name, bMob.Name); + return aMob.AccessLevel < bMob.AccessLevel ? 1 : aMob.Name.InsensitiveCompare(bMob.Name); } } @@ -4265,7 +4270,7 @@ namespace Server.Gumps return -1; } - return aLevel < bLevel ? 1 : Insensitive.Compare(x.Username, y.Username); + return aLevel < bLevel ? 1 : x.Username.InsensitiveCompare(y.Username); } } } diff --git a/Projects/UOContent/Gumps/Guilds/GuildDeclareWarPrompt.cs b/Projects/UOContent/Gumps/Guilds/GuildDeclareWarPrompt.cs index d2bede918..0b98e5ebd 100644 --- a/Projects/UOContent/Gumps/Guilds/GuildDeclareWarPrompt.cs +++ b/Projects/UOContent/Gumps/Guilds/GuildDeclareWarPrompt.cs @@ -1,3 +1,4 @@ +using System.Linq; using Server.Guilds; using Server.Prompts; @@ -36,7 +37,7 @@ namespace Server.Gumps if (text.Length >= 3) { - var guilds = BaseGuild.Search(text).CastListCovariant(); + var guilds = BaseGuild.Search(text).SafeConvertList(); GuildGump.EnsureClosed(m_Mobile); diff --git a/Projects/UOContent/Gumps/Guilds/GuildListGump.cs b/Projects/UOContent/Gumps/Guilds/GuildListGump.cs index 4c44099ad..a91f740f4 100644 --- a/Projects/UOContent/Gumps/Guilds/GuildListGump.cs +++ b/Projects/UOContent/Gumps/Guilds/GuildListGump.cs @@ -22,7 +22,7 @@ namespace Server.Gumps Design(); - m_List = new List(list); + m_List = list; for (var i = 0; i < m_List.Count; ++i) { diff --git a/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildGump.cs b/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildGump.cs index 3ee2bba1d..6d32a40ca 100644 --- a/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildGump.cs +++ b/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildGump.cs @@ -120,7 +120,7 @@ namespace Server.Guilds for (var i = 0; i < disallowed.Length; i++) { - if (s.IndexOf(disallowed[i], StringComparison.Ordinal) != -1) + if (s.IndexOfOrdinal(disallowed[i]) != -1) { return false; } diff --git a/Projects/UOContent/Gumps/Guilds/New Guild System/DiplomacyGump.cs b/Projects/UOContent/Gumps/Guilds/New Guild System/DiplomacyGump.cs index 34e8e6473..18f16b1d7 100644 --- a/Projects/UOContent/Gumps/Guilds/New Guild System/DiplomacyGump.cs +++ b/Projects/UOContent/Gumps/Guilds/New Guild System/DiplomacyGump.cs @@ -26,7 +26,7 @@ namespace Server.Guilds "", 0, GuildDisplayType.All, - World.Guilds.Values.CastListCovariant(), + World.Guilds.Values.SafeConvertList(), 1063136 + (int)GuildDisplayType.All ) { @@ -44,7 +44,7 @@ namespace Server.Guilds filter, startNumber, display, - World.Guilds.Values.CastListCovariant(), + World.Guilds.Values.SafeConvertList(), 1063136 + (int)display ) { @@ -224,7 +224,7 @@ namespace Server.Guilds } } - return !(Insensitive.Contains(g.Name, filter) || Insensitive.Contains(g.Abbreviation, filter)); + return !(g.Name.InsensitiveContains(filter) || g.Abbreviation.InsensitiveContains(filter)); } public override Gump GetResentGump( @@ -285,7 +285,7 @@ namespace Server.Guilds return 1; } - return Insensitive.Compare(x.Name, y.Name); + return x.Name.InsensitiveCompare(y.Name); } } @@ -365,7 +365,7 @@ namespace Server.Guilds return 1; } - return Insensitive.Compare(x.Abbreviation, y.Abbreviation); + return x.Abbreviation.InsensitiveCompare(y.Abbreviation); } } } diff --git a/Projects/UOContent/Gumps/Guilds/New Guild System/GuildMemberInfoGump.cs b/Projects/UOContent/Gumps/Guilds/New Guild System/GuildMemberInfoGump.cs index e27552421..a23357827 100644 --- a/Projects/UOContent/Gumps/Guilds/New Guild System/GuildMemberInfoGump.cs +++ b/Projects/UOContent/Gumps/Guilds/New Guild System/GuildMemberInfoGump.cs @@ -277,7 +277,7 @@ namespace Server.Guilds } else { - if (Insensitive.Equals(title, "none")) + if (title.InsensitiveEquals("none")) { m_Member.GuildTitle = null; } diff --git a/Projects/UOContent/Gumps/Guilds/New Guild System/GuildRosterGump.cs b/Projects/UOContent/Gumps/Guilds/New Guild System/GuildRosterGump.cs index d3f181887..c31e443db 100644 --- a/Projects/UOContent/Gumps/Guilds/New Guild System/GuildRosterGump.cs +++ b/Projects/UOContent/Gumps/Guilds/New Guild System/GuildRosterGump.cs @@ -85,7 +85,7 @@ namespace Server.Guilds return true; } - return !Insensitive.Contains(pm.Name, filter); + return !pm.Name.InsensitiveContains(filter); } public override Gump GetResentGump( @@ -208,7 +208,7 @@ namespace Server.Guilds return 1; } - return Insensitive.Compare(x.Name, y.Name); + return x.Name.InsensitiveCompare(y.Name); } } @@ -276,7 +276,7 @@ namespace Server.Guilds return 1; } - return Insensitive.Compare(x.GuildTitle, y.GuildTitle); + return x.GuildTitle.InsensitiveCompare(y.GuildTitle); } } diff --git a/Projects/UOContent/Gumps/HouseGump.cs b/Projects/UOContent/Gumps/HouseGump.cs index 049e99d6b..89cf0ea01 100644 --- a/Projects/UOContent/Gumps/HouseGump.cs +++ b/Projects/UOContent/Gumps/HouseGump.cs @@ -242,7 +242,7 @@ namespace Server.Gumps if (m_House.Sign != null) { - var lines = Wrap(m_House.Sign.GetName()); + var lines = m_House.Sign.GetName().Wrap(10, 6); for (int i = 0, y = (101 - lines.Count * 14) / 2; i < lines.Count; ++i, y += 14) { @@ -402,75 +402,6 @@ namespace Server.Gumps } } - private List Wrap(string value) - { - if (value == null || (value = value.Trim()).Length <= 0) - { - return null; - } - - var values = value.Split(' '); - var list = new List(); - var current = ""; - - for (var i = 0; i < values.Length; ++i) - { - var val = values[i]; - - var v = current.Length == 0 ? val : $"{current} {val}"; - - if (v.Length < 10) - { - current = v; - } - else if (v.Length == 10) - { - list.Add(v); - - if (list.Count == 6) - { - return list; - } - - current = ""; - } - else if (val.Length <= 10) - { - list.Add(current); - - if (list.Count == 6) - { - return list; - } - - current = val; - } - else - { - while (v.Length >= 10) - { - list.Add(v.Substring(0, 10)); - - if (list.Count == 6) - { - return list; - } - - v = v.Substring(10); - } - - current = v; - } - } - - if (current.Length > 0) - { - list.Add(current); - } - - return list; - } - private string GetOwnerName() { var m = m_House.Owner; diff --git a/Projects/UOContent/Gumps/HouseGumpAOS.cs b/Projects/UOContent/Gumps/HouseGumpAOS.cs index fd4b2d944..8fcbca778 100644 --- a/Projects/UOContent/Gumps/HouseGumpAOS.cs +++ b/Projects/UOContent/Gumps/HouseGumpAOS.cs @@ -115,7 +115,7 @@ namespace Server.Gumps if (m_House.Sign != null) { - var lines = Wrap(m_House.Sign.GetName()); + var lines = m_House.Sign.GetName().Wrap(10, 6); for (int i = 0, y = (114 - lines.Count * 14) / 2; i < lines.Count; ++i, y += 14) { @@ -1739,74 +1739,5 @@ namespace Server.Gumps } } } - - private List Wrap(string value) - { - if (value == null || (value = value.Trim()).Length <= 0) - { - return null; - } - - var values = value.Split(' '); - var list = new List(); - var current = ""; - - for (var i = 0; i < values.Length; ++i) - { - var val = values[i]; - - var v = current.Length == 0 ? val : $"{current} {val}"; - - if (v.Length < 10) - { - current = v; - } - else if (v.Length == 10) - { - list.Add(v); - - if (list.Count == 6) - { - return list; - } - - current = ""; - } - else if (val.Length <= 10) - { - list.Add(current); - - if (list.Count == 6) - { - return list; - } - - current = val; - } - else - { - while (v.Length >= 10) - { - list.Add(v.Substring(0, 10)); - - if (list.Count == 6) - { - return list; - } - - v = v.Substring(10); - } - - current = v; - } - } - - if (current.Length > 0) - { - list.Add(current); - } - - return list; - } } } diff --git a/Projects/UOContent/Gumps/Props/PropsGump.cs b/Projects/UOContent/Gumps/Props/PropsGump.cs index 568952a61..bf0722d88 100644 --- a/Projects/UOContent/Gumps/Props/PropsGump.cs +++ b/Projects/UOContent/Gumps/Props/PropsGump.cs @@ -757,7 +757,7 @@ namespace Server.Gumps if (t == typeof(byte) || t == typeof(sbyte) || t == typeof(short) || t == typeof(ushort) || t == typeof(int) || t == typeof(uint) || t == typeof(long) || t == typeof(ulong)) { - if (s.StartsWith("0x", StringComparison.Ordinal)) + if (s.StartsWithOrdinal("0x")) { if (t == typeof(ulong) || t == typeof(uint) || t == typeof(ushort) || t == typeof(byte)) { diff --git a/Projects/UOContent/Gumps/Props/SetBodyGump.cs b/Projects/UOContent/Gumps/Props/SetBodyGump.cs index 7f859efab..3736a3a0f 100644 --- a/Projects/UOContent/Gumps/Props/SetBodyGump.cs +++ b/Projects/UOContent/Gumps/Props/SetBodyGump.cs @@ -310,7 +310,7 @@ namespace Server.Gumps for (var i = 0; i < m_GroupNames.Length; ++i) { - if (DisplayName.StartsWith(m_GroupNames[i], StringComparison.Ordinal)) + if (DisplayName.StartsWithOrdinal(m_GroupNames[i])) { DisplayName = DisplayName.Substring(m_GroupNames[i].Length); break; diff --git a/Projects/UOContent/Gumps/WhoGump.cs b/Projects/UOContent/Gumps/WhoGump.cs index f98c67166..37451ccf9 100644 --- a/Projects/UOContent/Gumps/WhoGump.cs +++ b/Projects/UOContent/Gumps/WhoGump.cs @@ -103,7 +103,7 @@ namespace Server.Gumps if (m != null && (m == owner || !m.Hidden || owner.AccessLevel >= m.AccessLevel || m is PlayerMobile mobile && mobile.VisibilityList.Contains(owner))) { - if (filter != null && m.Name?.ToLower().Contains(filter, StringComparison.Ordinal) != true) + if (filter != null && !m.Name.InsensitiveContains(filter)) { continue; } @@ -330,7 +330,7 @@ namespace Server.Gumps return -1; } - return x.AccessLevel < y.AccessLevel ? 1 : Insensitive.Compare(x.Name, y.Name); + return x.AccessLevel < y.AccessLevel ? 1 : x.Name.InsensitiveCompare(y.Name); } } } diff --git a/Projects/UOContent/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs b/Projects/UOContent/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs index 4a23369ef..99a5b3173 100644 --- a/Projects/UOContent/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs +++ b/Projects/UOContent/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs @@ -23,7 +23,7 @@ namespace Server.Engines.Events private static void EventSink_Speech(SpeechEventArgs e) { - if (Insensitive.Contains(e.Speech, "trick or treat")) + if (e.Speech.InsensitiveContains("trick or treat")) { e.Mobile.Target = new TrickOrTreatTarget(); diff --git a/Projects/UOContent/Items/Body Parts/Head.cs b/Projects/UOContent/Items/Body Parts/Head.cs index 6c9eabcc0..8af56e53c 100644 --- a/Projects/UOContent/Items/Body Parts/Head.cs +++ b/Projects/UOContent/Items/Body Parts/Head.cs @@ -81,17 +81,17 @@ namespace Server.Items if (format != null) { - if (format.StartsWith("the head of ", StringComparison.Ordinal)) + if (format.StartsWithOrdinal("the head of ")) { format = format.Substring(14); // "the head of|..." } - if (format.EndsWith(", taken in a duel", StringComparison.Ordinal)) + if (format.EndsWithOrdinal(", taken in a duel")) { format = format.Substring(0, format.Length - ", taken in a duel".Length); HeadType = HeadType.Duel; } - else if (format.EndsWith(", taken in a tournament", StringComparison.Ordinal)) + else if (format.EndsWithOrdinal(", taken in a tournament")) { format = format.Substring(0, format.Length - ", taken in a tournament".Length); HeadType = HeadType.Tournament; diff --git a/Projects/UOContent/Items/Books/BaseBook.cs b/Projects/UOContent/Items/Books/BaseBook.cs index 50d6cacba..655fbd872 100644 --- a/Projects/UOContent/Items/Books/BaseBook.cs +++ b/Projects/UOContent/Items/Books/BaseBook.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Text; +using Server.Buffers; using Server.ContextMenus; using Server.Gumps; using Server.Multis; @@ -119,7 +120,7 @@ namespace Server.Items { get { - var sb = new StringBuilder(); + using var sb = new ValueStringBuilder(stackalloc char[256]); foreach (var bpi in Pages) { diff --git a/Projects/UOContent/Items/Misc/Teleporter.cs b/Projects/UOContent/Items/Misc/Teleporter.cs index 16f53cfb0..9ed22b319 100644 --- a/Projects/UOContent/Items/Misc/Teleporter.cs +++ b/Projects/UOContent/Items/Misc/Teleporter.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Server.Buffers; using Server.Mobiles; using Server.Network; using Server.Spells; @@ -594,7 +595,7 @@ namespace Server.Items { isMatch = true; } - else if (m_Substring != null && e.Speech.ToLower().Contains(m_Substring.ToLower(), StringComparison.Ordinal)) + else if (m_Substring != null && e.Speech.InsensitiveContains(m_Substring)) { isMatch = true; } @@ -1189,7 +1190,7 @@ namespace Server.Items { base.GetProperties(list); - var props = new StringBuilder(); + using var props = new ValueStringBuilder(stackalloc char[128]); if (GetFlag(ConditionFlag.DenyMounted)) { diff --git a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs index 8fe03caab..ef78fa154 100644 --- a/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs +++ b/Projects/UOContent/Items/Special/House Raffle/HouseRaffleManagementGump.cs @@ -262,7 +262,7 @@ namespace Server.Gumps return 1; } - var result = Insensitive.Compare(x.From.Name, y.From.Name); + var result = x.From.Name.InsensitiveCompare(y.From.Name); return result == 0 ? x.Date.CompareTo(y.Date) : result; } @@ -310,7 +310,7 @@ namespace Server.Gumps return 1; } - var result = Insensitive.Compare(a.Username, b.Username); + var result = a.Username.InsensitiveCompare(b.Username); return result == 0 ? x.Date.CompareTo(y.Date) : result; } diff --git a/Projects/UOContent/Misc/AutoSave.cs b/Projects/UOContent/Misc/AutoSave.cs index bc51a2903..206ba77ce 100644 --- a/Projects/UOContent/Misc/AutoSave.cs +++ b/Projects/UOContent/Misc/AutoSave.cs @@ -168,7 +168,7 @@ namespace Server.Misc { var info = new DirectoryInfo(paths[i]); - if (info.Name.StartsWith(match, StringComparison.Ordinal)) + if (info.Name.StartsWithOrdinal(match)) { return info; } @@ -182,7 +182,7 @@ namespace Server.Misc private static string FindTimeStamp(string input) { - var start = input.IndexOf('(', StringComparison.Ordinal); + var start = input.IndexOfOrdinal('('); if (start >= 0) { diff --git a/Projects/UOContent/Misc/InhumanSpeech.cs b/Projects/UOContent/Misc/InhumanSpeech.cs index 76736bbcb..9ca52dca5 100644 --- a/Projects/UOContent/Misc/InhumanSpeech.cs +++ b/Projects/UOContent/Misc/InhumanSpeech.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Text; +using Server.Buffers; namespace Server.Misc { @@ -316,9 +317,10 @@ namespace Server.Misc return string.Concat(syllables); } - public string ConstructSentance(int wordCount) + // TODO: Should be changed a preset table that is built + public string ConstructSentence(int wordCount) { - var sentance = new StringBuilder(); + using var sentence = new ValueStringBuilder(stackalloc char[256]); var needUpperCase = true; @@ -330,56 +332,33 @@ namespace Server.Misc if (random < 11) { - sentance.Append(' '); + sentence.Append(' '); } else { needUpperCase = true; - if (random > 13) - { - sentance.Append("! "); - } - else - { - sentance.Append(". "); - } + sentence.Append(random > 13 ? "! " : ". "); } } - int syllableCount; - - if (Utility.Random(100) < 30) - { - syllableCount = Utility.Random(1, 5); - } - else - { - syllableCount = Utility.Random(1, 3); - } + var syllableCount = Utility.Random(1, Utility.Random(100) < 30 ? 5 : 3); var word = ConstructWord(syllableCount); - sentance.Append(word); + sentence.Append(word); if (needUpperCase) { - sentance.Replace(word[0], char.ToUpper(word[0]), sentance.Length - word.Length, 1); + sentence.Replace(word[0], char.ToUpper(word[0]), sentence.Length - word.Length, 1); } needUpperCase = false; } - if (Utility.RandomMinMax(1, 5) == 1) - { - sentance.Append('!'); - } - else - { - sentance.Append('.'); - } + sentence.Append(Utility.RandomMinMax(1, 5) == 1 ? '!' : '.'); - return sentance.ToString(); + return sentence.ToString(); } public void SayRandomTranslate(Mobile mob, params string[] sentancesInEnglish) @@ -435,44 +414,43 @@ namespace Server.Misc if (keywordsFound.Count > 0) { - string responseWord; - - if (Utility.RandomBool()) - { - responseWord = GetRandomResponseWord(keywordsFound); - } - else - { - responseWord = keywordsFound.RandomElement(); - } + var responseWord = Utility.RandomBool() ? + GetRandomResponseWord(keywordsFound) : keywordsFound.RandomElement(); var secondResponseWord = GetRandomResponseWord(keywordsFound); - var response = new StringBuilder(); + using var response = new ValueStringBuilder(stackalloc char[256]); switch (Utility.Random(6)) { default: case 0: { - response.Append("Me ").Append(responseWord).Append('?'); + response.Append("Me "); + response.Append(responseWord); + response.Append('?'); break; } case 1: { - response.Append(responseWord).Append(" thee!"); + response.Append(responseWord); + response.Append(" thee!"); response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); break; } case 2: { - response.Append(responseWord).Append('?'); + response.Append(responseWord); + response.Append('?'); response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); break; } case 3: { - response.Append(responseWord).Append("! ").Append(secondResponseWord).Append('.'); + response.Append(responseWord); + response.Append("! "); + response.Append(secondResponseWord); + response.Append('.'); response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); response.Replace( secondResponseWord[0], @@ -484,13 +462,17 @@ namespace Server.Misc } case 4: { - response.Append(responseWord).Append('.'); + response.Append(responseWord); + response.Append('.'); response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); break; } case 5: { - response.Append(responseWord).Append("? ").Append(secondResponseWord).Append('.'); + response.Append(responseWord); + response.Append("? "); + response.Append(secondResponseWord); + response.Append('.'); response.Replace(responseWord[0], char.ToUpper(responseWord[0]), 0, 1); response.Replace( secondResponseWord[0], @@ -502,16 +484,7 @@ namespace Server.Misc } } - var maxWords = split.Length / 2 + 1; - - if (maxWords < 2) - { - maxWords = 2; - } - else if (maxWords > 6) - { - maxWords = 6; - } + var maxWords = Math.Clamp(split.Length / 2 + 1, 2, 6); SaySentance(mob, Utility.RandomMinMax(2, maxWords)); mob.Say(response.ToString()); @@ -617,7 +590,7 @@ namespace Server.Misc public void SaySentance(Mobile mob, int wordCount) { - mob.Say(ConstructSentance(wordCount)); + mob.Say(ConstructSentence(wordCount)); mob.PlaySound(Sound); } } diff --git a/Projects/UOContent/Misc/NameVerification.cs b/Projects/UOContent/Misc/NameVerification.cs index add3e5e0c..5c0b7f654 100644 --- a/Projects/UOContent/Misc/NameVerification.cs +++ b/Projects/UOContent/Misc/NameVerification.cs @@ -201,7 +201,7 @@ namespace Server.Misc for (var i = 0; i < disallowed.Length; ++i) { - var indexOf = name.IndexOf(disallowed[i], StringComparison.Ordinal); + var indexOf = name.IndexOfOrdinal(disallowed[i]); if (indexOf == -1) { @@ -235,7 +235,7 @@ namespace Server.Misc for (var i = 0; i < startDisallowed.Length; ++i) { - if (name.StartsWith(startDisallowed[i], StringComparison.Ordinal)) + if (name.StartsWithOrdinal(startDisallowed[i])) { return false; } diff --git a/Projects/UOContent/Misc/RenameRequests.cs b/Projects/UOContent/Misc/RenameRequests.cs index 393f19340..6856ede73 100644 --- a/Projects/UOContent/Misc/RenameRequests.cs +++ b/Projects/UOContent/Misc/RenameRequests.cs @@ -34,7 +34,7 @@ namespace Server.Misc for (var i = 0; i < disallowed.Length; i++) { - if (name.IndexOf(disallowed[i], StringComparison.Ordinal) != -1) + if (name.IndexOfOrdinal(disallowed[i]) != -1) { from.SendLocalizedMessage(1072622); // That name isn't very polite. return; diff --git a/Projects/UOContent/Misc/ResourceInfo.cs b/Projects/UOContent/Misc/ResourceInfo.cs index e8214ed1a..778de771e 100644 --- a/Projects/UOContent/Misc/ResourceInfo.cs +++ b/Projects/UOContent/Misc/ResourceInfo.cs @@ -870,22 +870,22 @@ namespace Server.Items /// public static CraftResource GetFromOreInfo(OreInfo info) { - if (info.Name.Contains("Spined", StringComparison.Ordinal)) + if (info.Name.ContainsOrdinal("Spined")) { return CraftResource.SpinedLeather; } - if (info.Name.Contains("Horned", StringComparison.Ordinal)) + if (info.Name.ContainsOrdinal("Horned")) { return CraftResource.HornedLeather; } - if (info.Name.Contains("Barbed", StringComparison.Ordinal)) + if (info.Name.ContainsOrdinal("Barbed")) { return CraftResource.BarbedLeather; } - if (info.Name.Contains("Leather", StringComparison.Ordinal)) + if (info.Name.ContainsOrdinal("Leather")) { return CraftResource.RegularLeather; } diff --git a/Projects/UOContent/Misc/ShardPoller.cs b/Projects/UOContent/Misc/ShardPoller.cs index 82c3769d1..767131d69 100644 --- a/Projects/UOContent/Misc/ShardPoller.cs +++ b/Projects/UOContent/Misc/ShardPoller.cs @@ -393,7 +393,7 @@ namespace Server.Misc do { ++count; - index = title.IndexOf("
", index + 1, StringComparison.Ordinal); + index = title.IndexOfOrdinal("
", index + 1); } while (index >= 0); return count; diff --git a/Projects/UOContent/Misc/ShrinkTable.cs b/Projects/UOContent/Misc/ShrinkTable.cs index e01281d46..de397b191 100644 --- a/Projects/UOContent/Misc/ShrinkTable.cs +++ b/Projects/UOContent/Misc/ShrinkTable.cs @@ -56,7 +56,7 @@ namespace Server { line = line.Trim(); - if (line.Length == 0 || line.StartsWith("#", StringComparison.Ordinal)) + if (line.Length == 0 || line.StartsWithOrdinal("#")) { continue; } diff --git a/Projects/UOContent/Misc/Titles.cs b/Projects/UOContent/Misc/Titles.cs index 662fc98a7..cd1738569 100644 --- a/Projects/UOContent/Misc/Titles.cs +++ b/Projects/UOContent/Misc/Titles.cs @@ -143,14 +143,12 @@ namespace Server.Misc offset = Math.Min(offset - m.Fame / 100, 0); } - if (m.Fame + offset > MaxFame) + offset = (m.Fame + offset) switch { - offset = MaxFame - m.Fame; - } - else if (m.Fame + offset < MinFame) - { - offset = MinFame - m.Fame; - } + > MaxFame => MaxFame - m.Fame, + < MinFame => MinFame - m.Fame, + _ => offset + }; m.Fame += offset; @@ -219,14 +217,12 @@ namespace Server.Misc offset = Math.Min(offset - m.Karma / 100, 0); } - if (m.Karma + offset > MaxKarma) + offset = (m.Karma + offset) switch { - offset = MaxKarma - m.Karma; - } - else if (m.Karma + offset < MinKarma) - { - offset = MinKarma - m.Karma; - } + > MaxKarma => MaxKarma - m.Karma, + < MinKarma => MinKarma - m.Karma, + _ => offset + }; var wasPositiveKarma = m.Karma >= 0; @@ -288,11 +284,6 @@ namespace Server.Misc var showSkillTitle = beheld.ShowFameTitle && (beholder == beheld || fame >= 5000); - /*if (beheld.Kills >= 5) - { - title.AppendFormat( beheld.Fame >= 10000 ? "The Murderer {1} {0}" : "The Murderer {0}", beheld.Name, beheld.Female ? "Lady" : "Lord" ); - } - else*/ if (beheld.ShowFameTitle || beholder == beheld) { for (var i = 0; i < m_FameEntries.Length; ++i) @@ -345,15 +336,12 @@ namespace Server.Misc } } - var offset = 0; - if (highestValue > 800) + var offset = highestValue switch { - offset = 3; - } - else if (highestValue > 300) - { - offset = highestValue / 300; - } + > 800 => 3, + > 300 => highestValue / 300, + _ => 0 + }; if (offset > 0) { @@ -369,7 +357,7 @@ namespace Server.Misc var customTitle = beheld.Title; - if (customTitle != null && (customTitle = customTitle.Trim()).Length > 0) + if ((customTitle = customTitle?.Trim())?.Length > 0) { title.AppendFormat(" {0}", customTitle); } @@ -395,7 +383,7 @@ namespace Server.Misc var skillLevel = GetSkillLevel(highest); var skillTitle = highest.Info.Title; - if (mob.Female && skillTitle.EndsWith("man", StringComparison.Ordinal)) + if (mob.Female && skillTitle.EndsWithOrdinal("man")) { skillTitle = $"{skillTitle.Substring(0, skillTitle.Length - 3)}woman"; } diff --git a/Projects/UOContent/Mobiles/AI/BaseAI.cs b/Projects/UOContent/Mobiles/AI/BaseAI.cs index 1ecdf31dc..6ae4b8c0b 100644 --- a/Projects/UOContent/Mobiles/AI/BaseAI.cs +++ b/Projects/UOContent/Mobiles/AI/BaseAI.cs @@ -156,7 +156,7 @@ namespace Server.Mobiles { var name = m_Mobile.Name; - return name != null && Insensitive.StartsWith(speech, name); + return name != null && speech.InsensitiveStartsWith(name); } public virtual void GetContextMenuEntries(Mobile from, List list) @@ -786,7 +786,7 @@ namespace Server.Mobiles { var word = str[i]; - if (Insensitive.Equals(word, "obey")) + if (word.InsensitiveEquals("obey")) { m_Mobile.SetControlMaster(e.Mobile); diff --git a/Projects/UOContent/Mobiles/BaseCreature.cs b/Projects/UOContent/Mobiles/BaseCreature.cs index bad1c26f0..25ae4f35a 100644 --- a/Projects/UOContent/Mobiles/BaseCreature.cs +++ b/Projects/UOContent/Mobiles/BaseCreature.cs @@ -3775,12 +3775,12 @@ namespace Server.Mobiles { var word = wordsString[i]; - if (Insensitive.Equals(word, wordName)) + if (word.InsensitiveEquals(wordName)) { bFound = true; } - if (bWithAll && Insensitive.Equals(word, "all")) + if (bWithAll && word.InsensitiveEquals("all")) { return true; } diff --git a/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs b/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs index eabcebf23..dcd31a2b4 100644 --- a/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs +++ b/Projects/UOContent/Mobiles/Townfolk/TownCrier.cs @@ -238,7 +238,7 @@ namespace Server.Mobiles } else { - for (var i = 0; i < entries.Count; ++i) + for (var i = 0; i < entries!.Count; ++i) { var tce = entries[i]; diff --git a/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs b/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs index ffd668c14..0201b0ed6 100644 --- a/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs +++ b/Projects/UOContent/Mobiles/Vendors/BaseVendor.cs @@ -771,33 +771,7 @@ namespace Server.Mobiles public virtual void CapitalizeTitle() { - var title = Title; - - if (title == null) - { - return; - } - - var split = title.Split(' '); - - for (var i = 0; i < split.Length; ++i) - { - if (Insensitive.Equals(split[i], "the")) - { - continue; - } - - if (split[i].Length > 1) - { - split[i] = char.ToUpper(split[i][0]) + split[i].Substring(1); - } - else if (split[i].Length > 0) - { - split[i] = char.ToUpper(split[i][0]).ToString(); - } - } - - Title = string.Join(" ", split); + Title = Title.Capitalize(); } public virtual int GetHairHue() => Race.RandomHairHue(); diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs b/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs index 7c8ab3e2f..6c22c1a7b 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/AnimalTrainer.cs @@ -308,7 +308,7 @@ namespace Server.Mobiles ++stabled; - if (claimByName && !Insensitive.Equals(pet.Name, petName)) + if (claimByName && !pet.Name.InsensitiveEquals(petName)) { continue; } @@ -387,7 +387,7 @@ namespace Server.Mobiles CloseClaimList(e.Mobile); - var index = e.Speech.IndexOf(' ', StringComparison.Ordinal); + var index = e.Speech.IndexOfOrdinal(' '); if (index != -1) { diff --git a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs index 9cb56075b..10873c8b8 100644 --- a/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs +++ b/Projects/UOContent/Mobiles/Vendors/NPC/Guildmasters/BaseGuildmaster.cs @@ -65,7 +65,7 @@ namespace Server.Mobiles { var name = Name; - return name != null && Insensitive.StartsWith(speech, name); + return name != null && speech.InsensitiveStartsWith(name); } public override bool HandlesOnSpeech(Mobile from) diff --git a/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs b/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs index c67a302b3..0fed15299 100644 --- a/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs +++ b/Projects/UOContent/Mobiles/Vendors/PlayerBarkeeper.cs @@ -297,7 +297,7 @@ namespace Server.Mobiles continue; } - if (Insensitive.Equals(keyword, e.Speech)) + if (keyword.InsensitiveEquals(e.Speech)) { var message = rumor.Message; diff --git a/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs b/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs index 38696aef2..222f4b0d9 100644 --- a/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs +++ b/Projects/UOContent/Mobiles/Vendors/PlayerVendor.cs @@ -1249,7 +1249,7 @@ namespace Server.Mobiles public override bool HandlesOnSpeech(Mobile from) => from.Alive && from.GetDistanceToSqrt(this) <= 3; - public bool WasNamed(string speech) => Name != null && Insensitive.StartsWith(speech, Name); + public bool WasNamed(string speech) => Name != null && speech.InsensitiveStartsWith(Name); public override void OnSpeech(SpeechEventArgs e) { diff --git a/Projects/UOContent/Regions/HouseRegion.cs b/Projects/UOContent/Regions/HouseRegion.cs index baa229eb4..6055f5888 100644 --- a/Projects/UOContent/Regions/HouseRegion.cs +++ b/Projects/UOContent/Regions/HouseRegion.cs @@ -236,7 +236,7 @@ namespace Server.Regions return; } - if (Core.ML && Insensitive.Equals(e.Speech, "I wish to resize my house")) + if (Core.ML && e.Speech.InsensitiveEquals("I wish to resize my house")) { if (from.Map != sign.Map || !from.InRange(sign, 0)) { diff --git a/Projects/UOContent/Skills/ForensicEval.cs b/Projects/UOContent/Skills/ForensicEval.cs index de0cd457b..92cb749f1 100644 --- a/Projects/UOContent/Skills/ForensicEval.cs +++ b/Projects/UOContent/Skills/ForensicEval.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using Server.Buffers; using Server.Items; using Server.Mobiles; using Server.Targeting; @@ -75,12 +76,12 @@ namespace Server.SkillHandlers if (c.Looters.Count > 0) { - var sb = new StringBuilder(); + using var sb = new ValueStringBuilder(stackalloc char[128]); for (var i = 0; i < c.Looters.Count; i++) { if (i > 0) { - sb.Append(", "); + sb.Append(i == c.Looters.Count - 1 ? ", and " : ", "); } sb.Append(c.Looters[i].Name); @@ -89,7 +90,7 @@ namespace Server.SkillHandlers from.SendLocalizedMessage( 1042752, sb.ToString() - ); // This body has been distrubed by ~1_PLAYER_NAMES~ + ); // This body has been disturbed by ~1_PLAYER_NAMES~ } else { diff --git a/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs b/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs index 355a2f4bb..27019fcaa 100644 --- a/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs +++ b/Projects/UOContent/SpecialSystems/Engines/TestCenter.cs @@ -1,5 +1,6 @@ using System; using System.Text; +using Microsoft.Toolkit.HighPerformance.Extensions; using Server.Commands; using Server.Gumps; using Server.Network; @@ -31,43 +32,50 @@ namespace Server.Misc return; } - if (Insensitive.StartsWith(args.Speech, "set")) + if (args.Speech.InsensitiveStartsWith("set")) { var from = args.Mobile; - var split = args.Speech.Split(' '); - - if (split.Length == 3) + var tokenizer = args.Speech.Tokenize(' '); + if (!tokenizer.MoveNext()) { - try - { - var name = split[1]; - var value = Convert.ToDouble(split[2]); + return; + } - if (Insensitive.Equals(name, "str")) - { - ChangeStrength(from, (int)value); - } - else if (Insensitive.Equals(name, "dex")) - { - ChangeDexterity(from, (int)value); - } - else if (Insensitive.Equals(name, "int")) - { - ChangeIntelligence(from, (int)value); - } - else - { - ChangeSkill(from, name, value); - } - } - catch + var name = tokenizer.MoveNext() ? tokenizer.Current : null; + var valueStr = tokenizer.MoveNext() ? tokenizer.Current : null; + if (valueStr == null) + { + return; + } + + var value = double.Parse(valueStr); + + try + { + if (name.InsensitiveEquals("str")) { - // ignored + ChangeStrength(from, (int)value); + } + else if (name.InsensitiveEquals("dex")) + { + ChangeDexterity(from, (int)value); + } + else if (name.InsensitiveEquals("int")) + { + ChangeIntelligence(from, (int)value); + } + else + { + ChangeSkill(from, name.ToString(), value); } } + catch + { + // ignored + } } - else if (Insensitive.Equals(args.Speech, "help")) + else if (args.Speech.InsensitiveEquals("help")) { args.Mobile.SendGump(new TCHelpGump()); args.Handled = true; diff --git a/Projects/UOContent/Spells/Base/SpellRegistry.cs b/Projects/UOContent/Spells/Base/SpellRegistry.cs index 4aaf9bc30..4433bf7ac 100644 --- a/Projects/UOContent/Spells/Base/SpellRegistry.cs +++ b/Projects/UOContent/Spells/Base/SpellRegistry.cs @@ -152,7 +152,7 @@ namespace Server.Spells public static Spell NewSpell(string name, Mobile caster, Item scroll) { - name = name.Replace(" ", "", StringComparison.Ordinal); + name = name.RemoveOrdinal(" "); for (var i = 0; i < m_CircleNames.Length; ++i) { diff --git a/Projects/UOContent/UOContent.csproj b/Projects/UOContent/UOContent.csproj index 149003883..e88d49329 100644 --- a/Projects/UOContent/UOContent.csproj +++ b/Projects/UOContent/UOContent.csproj @@ -29,6 +29,7 @@ false +