fix: Adds ISpanParsable and fixes command conditionals (#1241)
* Adds `ISpanParsable<T>` * Removes `[Parsable]` * Fixes querying by serial, body, and a few others. * Adds `Parse` to `Rectangle3D` * Fixes AutoArchive NPE Closes #1209
This commit is contained in:
parent
d494a9c78c
commit
03fb36c869
21 changed files with 1119 additions and 271 deletions
|
|
@ -65,4 +65,44 @@ public class Point2DTests
|
|||
Assert.False(p4.TryFormat(array, out var cp4, null, null));
|
||||
Assert.Equal(0, cp4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPoint2DTryParse()
|
||||
{
|
||||
// Happy Path
|
||||
Assert.True(Point2D.TryParse("(101, 23)", null, out var p));
|
||||
Assert.Equal(new Point2D(101, 23), p);
|
||||
Assert.Equal(new Point2D(101, 23), Point2D.Parse("(101, 23)", null));
|
||||
|
||||
// Trimming
|
||||
Assert.True(Point2D.TryParse(" (101,23) ", null, out p));
|
||||
Assert.Equal(new Point2D(101, 23), p);
|
||||
Assert.Equal(new Point2D(101, 23), Point2D.Parse(" (101,23) ", null));
|
||||
|
||||
// No parenthesis
|
||||
Assert.False(Point2D.TryParse("101, 23)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point2D.Parse("101, 23)", null));
|
||||
|
||||
Assert.False(Point2D.TryParse("(101, 23", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point2D.Parse("(101, 23", null));
|
||||
|
||||
// No numbers
|
||||
Assert.False(Point2D.TryParse("()", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point2D.Parse("()", null));
|
||||
|
||||
Assert.False(Point2D.TryParse("(101)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point2D.Parse("(101)", null));
|
||||
|
||||
Assert.False(Point2D.TryParse("(101,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point2D.Parse("(101,)", null));
|
||||
|
||||
Assert.False(Point2D.TryParse("(,23)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point2D.Parse("(,23)", null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,4 +69,60 @@ public class Point3DTests
|
|||
Assert.False(p4.TryFormat(array, out var cp4, null, null));
|
||||
Assert.Equal(0, cp4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestPoint3DTryParse()
|
||||
{
|
||||
// Happy Path
|
||||
Assert.True(Point3D.TryParse("(101, 23, 55)", null, out var p));
|
||||
Assert.Equal(new Point3D(101, 23, 55), p);
|
||||
Assert.Equal(new Point3D(101, 23, 55), Point3D.Parse("(101, 23, 55)", null));
|
||||
|
||||
// Trimming
|
||||
Assert.True(Point3D.TryParse(" (101,23 ,55) ", null, out p));
|
||||
Assert.Equal(new Point3D(101, 23, 55), p);
|
||||
Assert.Equal(new Point3D(101, 23, 55), Point3D.Parse(" (101,23 ,55) ", null));
|
||||
|
||||
// No parenthesis
|
||||
Assert.False(Point3D.TryParse("101, 23 55)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("101, 23, 55)", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(101, 23, 55", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(101, 23, 55", null));
|
||||
|
||||
// No numbers
|
||||
Assert.False(Point3D.TryParse("()", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("()", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(,)", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(|)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(|)", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(101)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(101)", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(101,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(101,)", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(,23)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(,23)", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(,23,55)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(,23,55)", null));
|
||||
|
||||
Assert.False(Point3D.TryParse("(,23,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Point3D.Parse("(,23,)", null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,4 +69,64 @@ public class Rectangle2DTests
|
|||
Assert.False(p4.TryFormat(array, out var cp4, null, null));
|
||||
Assert.Equal(0, cp4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRectangle2DTryParse()
|
||||
{
|
||||
// Happy Path
|
||||
Assert.True(Rectangle2D.TryParse("(101, 23)+(55, 89)", null, out var p));
|
||||
Assert.Equal(new Rectangle2D(new Point2D(101, 23), new Point2D(55, 89)), p);
|
||||
Assert.Equal(new Rectangle2D(new Point2D(101, 23), new Point2D(55, 89)), Rectangle2D.Parse("(101, 23)+(55, 89)", null));
|
||||
|
||||
// Trimming
|
||||
Assert.True(Rectangle2D.TryParse(" (101,23)+ (55, 89) ", null, out p));
|
||||
Assert.Equal(new Rectangle2D(new Point2D(101, 23), new Point2D(55, 89)), p);
|
||||
Assert.Equal(new Rectangle2D(new Point2D(101, 23), new Point2D(55, 89)), Rectangle2D.Parse(" (101,23)+ (55, 89) ", null));
|
||||
|
||||
// No parenthesis
|
||||
Assert.False(Rectangle2D.TryParse("101, 23)+( 55, 89)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("101, 23)+( 55, 89)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(101, 23)+(55, 89", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(101, 23)+(55, 89", null));
|
||||
|
||||
// No numbers
|
||||
Assert.False(Rectangle2D.TryParse("()", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("()", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(,)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(|)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(|)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(101)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(101)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(101,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(101,)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(,23)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(,23)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(,23)+(,55)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(,23)+(,55)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(,23,)+(,89)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(,23,)+(,89)", null));
|
||||
|
||||
Assert.False(Rectangle2D.TryParse("(,,)+(55,89)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle2D.Parse("(,,)+(55,89)", null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -69,4 +69,72 @@ public class Rectangle3DTests
|
|||
Assert.False(p4.TryFormat(array, out var cp4, null, null));
|
||||
Assert.Equal(0, cp4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestRectangle3DTryParse()
|
||||
{
|
||||
// Happy Path
|
||||
Assert.True(Rectangle3D.TryParse("(101, 23, 10)+(55, 89, 1)", null, out var p));
|
||||
Assert.Equal(new Rectangle3D(new Point3D(101, 23, 10), new Point3D(55, 89, 1)), p);
|
||||
Assert.Equal(new Rectangle3D(new Point3D(101, 23, 10), new Point3D(55, 89, 1)), Rectangle3D.Parse("(101, 23, 10)+(55, 89, 1)", null));
|
||||
|
||||
// Trimming
|
||||
Assert.True(Rectangle3D.TryParse(" (101,23,10)+ (55, 89,1) ", null, out p));
|
||||
Assert.Equal(new Rectangle3D(new Point3D(101, 23, 10), new Point3D(55, 89, 1)), p);
|
||||
Assert.Equal(new Rectangle3D(new Point3D(101, 23, 10), new Point3D(55, 89, 1)), Rectangle3D.Parse(" (101,23,10)+ (55, 89,1) ", null));
|
||||
|
||||
// No parenthesis
|
||||
Assert.False(Rectangle3D.TryParse("101, 23, 10)+( 55, 89, 1)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("101, 23, 10)+( 55, 89, 1)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(101, 23, 10)+(55, 89, 1", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(101, 23, 10)+(55, 89, 1", null));
|
||||
|
||||
// No numbers
|
||||
Assert.False(Rectangle3D.TryParse("()", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("()", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(,)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(|)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(|)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(101)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(101)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(101,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(101,)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(101,23)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(101,23)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(,23)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(,23)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(,23)+(,55)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(,23)+(,55)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(,23,)+(,89)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(,23,)+(,89)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(101,,10)+(55, 89 1)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(,23,)+(,89)", null));
|
||||
|
||||
Assert.False(Rectangle3D.TryParse("(,,)+(55,89, 1)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => Rectangle3D.Parse("(,,)+(55,89, 1)", null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ using Xunit;
|
|||
|
||||
namespace Server.Tests;
|
||||
|
||||
public sealed class WorldLocationTests
|
||||
public sealed class WorldLocationTests : IClassFixture<ServerFixture>
|
||||
{
|
||||
private static Map CreateMap(string name) => new(0, 0, 0, 1, 1, 0, name, MapRules.Internal);
|
||||
|
||||
|
|
@ -102,4 +102,84 @@ public sealed class WorldLocationTests
|
|||
Assert.False(p4.TryFormat(array, out var cp4, null, null));
|
||||
Assert.Equal(0, cp4);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void TestWorldLocationTryParse()
|
||||
{
|
||||
var validMap = Map.Felucca;
|
||||
// Happy Path
|
||||
Assert.True(WorldLocation.TryParse("(101, 23, 55) [Felucca]", null, out var p));
|
||||
Assert.Equal(new WorldLocation(101, 23, 55, validMap), p);
|
||||
Assert.Equal(new WorldLocation(101, 23, 55, validMap), WorldLocation.Parse("(101, 23, 55) [Felucca]", null));
|
||||
|
||||
// Trimming
|
||||
Assert.True(WorldLocation.TryParse(" (101,23 ,55) [Felucca] ", null, out p));
|
||||
Assert.Equal(new WorldLocation(101, 23, 55, validMap), p);
|
||||
Assert.Equal(new WorldLocation(101, 23, 55, validMap), WorldLocation.Parse(" (101,23 ,55) [Felucca] ", null));
|
||||
|
||||
// Null Map
|
||||
Assert.True(WorldLocation.TryParse(" (101,23 ,55) [(-null-)]", null, out p));
|
||||
Assert.Equal(new WorldLocation(101, 23, 55, null), p);
|
||||
Assert.Equal(new WorldLocation(101, 23, 55, null), WorldLocation.Parse(" (101,23 ,55) [(-null-)]", null));
|
||||
|
||||
// No Brackets
|
||||
Assert.False(WorldLocation.TryParse("(101, 23 55) Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(101, 23, 55) Felucca]", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(101, 23 55) [Felucca", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(101, 23, 55) [Felucca", null));
|
||||
|
||||
// No parenthesis
|
||||
Assert.False(WorldLocation.TryParse("101, 23 55) [Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("101, 23, 55) [Felucca]", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(101, 23, 55 [Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(101, 23, 55 [Felucca]", null));
|
||||
|
||||
// No Map - We don't support maps with no name, sorry.
|
||||
Assert.False(WorldLocation.TryParse("(101, 23, 55) []", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(101, 23, 55) []", null));
|
||||
|
||||
// No numbers
|
||||
Assert.False(WorldLocation.TryParse("()", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("()", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(,)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(,)", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(|)", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(|)", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("() []", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("() []", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(101) [Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(101) [Felucca]", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(101,) [Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(101,) [Felucca]", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(,23) [Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(,23) [Felucca]", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(,23,55) [Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(,23,55) [Felucca]", null));
|
||||
|
||||
Assert.False(WorldLocation.TryParse("(,23,) [Felucca]", null, out p));
|
||||
Assert.Equal(default, p);
|
||||
Assert.Throws<FormatException>(() => WorldLocation.Parse("(,23,) [Felucca]", null));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,11 +88,6 @@ public class TypeAliasAttribute : Attribute
|
|||
public string[] Aliases { get; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class ParsableAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]
|
||||
public class CustomEnumAttribute : Attribute
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@
|
|||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server;
|
||||
|
||||
[Parsable]
|
||||
public struct Point2D
|
||||
: IPoint2D, IComparable<Point2D>, IComparable<IPoint2D>, IEquatable<object>, IEquatable<Point2D>,
|
||||
IEquatable<IPoint2D>, ISpanFormattable
|
||||
IEquatable<IPoint2D>, ISpanFormattable, ISpanParsable<Point2D>
|
||||
{
|
||||
internal int m_X;
|
||||
internal int m_Y;
|
||||
|
|
@ -51,21 +51,6 @@ public struct Point2D
|
|||
{
|
||||
}
|
||||
|
||||
public static Point2D Parse(string value)
|
||||
{
|
||||
var start = value.IndexOfOrdinal('(');
|
||||
var end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(')', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
||||
|
||||
return new Point2D(x, y);
|
||||
}
|
||||
|
||||
public bool Equals(Point2D other) => m_X == other.m_X && m_Y == other.m_Y;
|
||||
|
||||
public bool Equals(IPoint2D other) => m_X == other?.X && m_Y == other.Y;
|
||||
|
|
@ -130,4 +115,79 @@ public struct Point2D
|
|||
// default ToString implementation.
|
||||
return ToString();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Point2D Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Point2D Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Point2D result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Point2D Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (!s.StartsWithOrdinal('(') || !s.EndsWithOrdinal(')'))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var comma = s.IndexOfOrdinal(',');
|
||||
if (comma == -1)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var first = s.Slice(1, comma - 1).Trim();
|
||||
if (!Utility.ToInt32(first, out var x))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var second = s.Slice(comma + 1, s.Length - comma - 2).Trim();
|
||||
if (!Utility.ToInt32(second, out var y))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
return new Point2D(x, y);
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Point2D result)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (!s.StartsWithOrdinal('(') || !s.EndsWithOrdinal(')'))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var comma = s.IndexOfOrdinal(',');
|
||||
if (comma == -1)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var first = s.Slice(1, comma - 1).Trim();
|
||||
if (!Utility.ToInt32(first, out var x))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var second = s.Slice(comma + 1, s.Length - comma - 2).Trim();
|
||||
if (!Utility.ToInt32(second, out var y))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new Point2D(x, y);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,10 +18,9 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
namespace Server;
|
||||
|
||||
[Parsable]
|
||||
public struct Point3D
|
||||
: IPoint3D, IComparable<Point3D>, IComparable<IPoint3D>, IEquatable<object>, IEquatable<Point3D>,
|
||||
IEquatable<IPoint3D>, ISpanFormattable
|
||||
IEquatable<IPoint3D>, ISpanFormattable, ISpanParsable<Point3D>
|
||||
{
|
||||
internal int m_X;
|
||||
internal int m_Y;
|
||||
|
|
@ -79,26 +78,6 @@ public struct Point3D
|
|||
|
||||
public override int GetHashCode() => HashCode.Combine(m_X, m_Y, m_Z);
|
||||
|
||||
public static Point3D Parse(string value)
|
||||
{
|
||||
var start = value.IndexOfOrdinal('(');
|
||||
var end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(')', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var z);
|
||||
|
||||
return new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
public static bool operator ==(Point3D l, Point3D r) => l.m_X == r.m_X && l.m_Y == r.m_Y && l.m_Z == r.m_Z;
|
||||
|
||||
public static bool operator ==(Point3D l, IPoint3D r) =>
|
||||
|
|
@ -183,4 +162,115 @@ public struct Point3D
|
|||
// default ToString implementation.
|
||||
return ToString();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Point3D Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Point3D Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Point3D result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Point3D Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (!s.StartsWithOrdinal('(') || !s.EndsWithOrdinal(')'))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var firstComma = s.IndexOfOrdinal(',');
|
||||
if (firstComma == -1)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var first = s.Slice(1, firstComma - 1).Trim();
|
||||
|
||||
if (!Utility.ToInt32(first, out var x))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var offset = firstComma + 1;
|
||||
|
||||
var secondComma = s[offset..].IndexOfOrdinal(',');
|
||||
if (secondComma == -1 || offset == secondComma)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var second = s.Slice(firstComma + 1, secondComma).Trim();
|
||||
|
||||
if (!Utility.ToInt32(second, out var y))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
offset += secondComma + 1;
|
||||
|
||||
var third = s.Slice(offset, s.Length - offset - 1).Trim();
|
||||
if (!Utility.ToInt32(third, out var z))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
return new Point3D(x, y, z);
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Point3D result)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (!s.StartsWithOrdinal('(') || !s.EndsWithOrdinal(')'))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var firstComma = s.IndexOfOrdinal(',');
|
||||
if (firstComma == -1)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var first = s.Slice(1, firstComma - 1).Trim();
|
||||
if (!Utility.ToInt32(first, out var x))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var offset = firstComma + 1;
|
||||
|
||||
var secondComma = s[offset..].IndexOfOrdinal(',');
|
||||
if (secondComma == -1 || offset == secondComma)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var second = s.Slice(firstComma + 1, secondComma).Trim();
|
||||
if (!Utility.ToInt32(second, out var y))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += secondComma + 1;
|
||||
|
||||
var third = s.Slice(offset, s.Length - offset - 1).Trim();
|
||||
if (!Utility.ToInt32(third, out var z))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new Point3D(x, y, z);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,13 +14,13 @@
|
|||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server;
|
||||
|
||||
[NoSort]
|
||||
[Parsable]
|
||||
[PropertyObject]
|
||||
public struct Rectangle2D : IEquatable<Rectangle2D>, ISpanFormattable
|
||||
public struct Rectangle2D : IEquatable<Rectangle2D>, ISpanFormattable, ISpanParsable<Rectangle2D>
|
||||
{
|
||||
private Point2D _start;
|
||||
private Point2D _end;
|
||||
|
|
@ -118,31 +118,6 @@ public struct Rectangle2D : IEquatable<Rectangle2D>, ISpanFormattable
|
|||
|
||||
public static bool operator !=(Rectangle2D l, Rectangle2D r) => l._start != r._start || l._end != r._end;
|
||||
|
||||
public static Rectangle2D Parse(string value)
|
||||
{
|
||||
var start = value.IndexOfOrdinal('(');
|
||||
var end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var w);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(')', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var h);
|
||||
|
||||
return new Rectangle2D(x, y, w, h);
|
||||
}
|
||||
|
||||
public bool Contains(Point3D p) =>
|
||||
_start.m_X <= p.m_X && _start.m_Y <= p.m_Y && _end.m_X > p.m_X && _end.m_Y > p.m_Y;
|
||||
|
||||
|
|
@ -172,4 +147,64 @@ public struct Rectangle2D : IEquatable<Rectangle2D>, ISpanFormattable
|
|||
// default ToString implementation.
|
||||
return ToString();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Rectangle2D Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Rectangle2D Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Rectangle2D result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Rectangle2D Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
var delimiter = s.IndexOfOrdinal('+');
|
||||
if (delimiter == -1)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
if (!Point2D.TryParse(s[..delimiter], provider, out var start))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
if (!Point2D.TryParse(s[(delimiter + 1)..], provider, out var end))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
return new Rectangle2D(start, end);
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Rectangle2D result)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
var delimiter = s.IndexOfOrdinal('+');
|
||||
if (delimiter == -1)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Point2D.TryParse(s[..delimiter], provider, out var start))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Point2D.TryParse(s[(delimiter + 1)..], provider, out var end))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new Rectangle2D(start, end);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,11 +14,11 @@
|
|||
*************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server;
|
||||
|
||||
[NoSort]
|
||||
[Parsable]
|
||||
[PropertyObject]
|
||||
public struct Rectangle3D : IEquatable<Rectangle3D>, ISpanFormattable
|
||||
{
|
||||
|
|
@ -172,4 +172,64 @@ public struct Rectangle3D : IEquatable<Rectangle3D>, ISpanFormattable
|
|||
// default ToString implementation.
|
||||
return ToString();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Rectangle3D Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Rectangle3D Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Rectangle3D result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Rectangle3D Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
var delimiter = s.IndexOfOrdinal('+');
|
||||
if (delimiter == -1)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
if (!Point3D.TryParse(s[..delimiter], provider, out var start))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
if (!Point3D.TryParse(s[(delimiter + 1)..], provider, out var end))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
return new Rectangle3D(start, end);
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Rectangle3D result)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
var delimiter = s.IndexOfOrdinal('+');
|
||||
if (delimiter == -1)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Point3D.TryParse(s[..delimiter], provider, out var start))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Point3D.TryParse(s[(delimiter + 1)..], provider, out var end))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new Rectangle3D(start, end);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server;
|
||||
|
||||
[Parsable]
|
||||
public struct WorldLocation : IPoint3D, IComparable<WorldLocation>, IEquatable<WorldLocation>, IEquatable<IEntity>,
|
||||
ISpanFormattable
|
||||
ISpanFormattable, ISpanParsable<WorldLocation>
|
||||
{
|
||||
internal Point3D _loc;
|
||||
internal Map _map;
|
||||
|
|
@ -63,7 +63,7 @@ public struct WorldLocation : IPoint3D, IComparable<WorldLocation>, IEquatable<W
|
|||
set => _map = value;
|
||||
}
|
||||
|
||||
public WorldLocation(IEntity e) : this(e.Location.X, e.Location.Y, e.Location.Z, e.Map)
|
||||
public WorldLocation(IEntity e) : this(e.Location, e.Map)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
@ -75,8 +75,10 @@ public struct WorldLocation : IPoint3D, IComparable<WorldLocation>, IEquatable<W
|
|||
{
|
||||
}
|
||||
|
||||
public WorldLocation(Point3D p, Map map) : this(p.X, p.Y, p.Z, map)
|
||||
public WorldLocation(Point3D p, Map map)
|
||||
{
|
||||
_loc = p;
|
||||
_map = map;
|
||||
}
|
||||
|
||||
public WorldLocation(int x, int y, int z, Map map)
|
||||
|
|
@ -88,11 +90,11 @@ public struct WorldLocation : IPoint3D, IComparable<WorldLocation>, IEquatable<W
|
|||
}
|
||||
|
||||
public bool Equals(WorldLocation other) =>
|
||||
_loc.Equals(other._loc) && _map.MapID == other._map.MapID;
|
||||
_loc.Equals(other._loc) && _map?.MapID == other._map?.MapID;
|
||||
|
||||
public bool Equals(IEntity other) =>
|
||||
!ReferenceEquals(other, null) && _loc == other.Location &&
|
||||
_map.MapID == other.Map.MapID;
|
||||
_map?.MapID == other.Map?.MapID;
|
||||
|
||||
public override bool Equals(object obj) =>
|
||||
obj is WorldLocation other && Equals(other);
|
||||
|
|
@ -138,31 +140,6 @@ public struct WorldLocation : IPoint3D, IComparable<WorldLocation>, IEquatable<W
|
|||
public static bool operator <=(WorldLocation l, IEntity r) =>
|
||||
!ReferenceEquals(r, null) && l._loc <= r.Location && l._map == r.Map;
|
||||
|
||||
public static WorldLocation Parse(string value)
|
||||
{
|
||||
var start = value.IndexOfOrdinal('(');
|
||||
var end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var x);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var y);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(',', start + 1);
|
||||
|
||||
Utility.ToInt32(value.AsSpan(start + 1, end - (start + 1)).Trim(), out var z);
|
||||
|
||||
start = end;
|
||||
end = value.IndexOf(')', start + 1);
|
||||
|
||||
var map = Map.Parse(value.AsSpan(start + 1, end - (start + 1)).Trim());
|
||||
|
||||
return new WorldLocation(x, y, z, map);
|
||||
}
|
||||
|
||||
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
|
||||
{
|
||||
if (_map == null)
|
||||
|
|
@ -208,4 +185,77 @@ public struct WorldLocation : IPoint3D, IComparable<WorldLocation>, IEquatable<W
|
|||
// default ToString implementation.
|
||||
return ToString();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static WorldLocation Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static WorldLocation Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out WorldLocation result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static WorldLocation Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (!s.EndsWithOrdinal(']'))
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var mapStartBracket = s.IndexOf('[');
|
||||
if (mapStartBracket == -1)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
var loc = Point3D.Parse(s[..(mapStartBracket - 1)], provider);
|
||||
|
||||
var mapSlice = s.Slice(mapStartBracket + 1, s.Length - mapStartBracket - 2);
|
||||
return mapSlice.EqualsOrdinal("(-null-)")
|
||||
? new WorldLocation(loc, null)
|
||||
: new WorldLocation(loc, Map.Parse(mapSlice, provider));
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out WorldLocation result)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (!s.EndsWithOrdinal(']'))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var mapStartBracket = s.IndexOf('[');
|
||||
if (mapStartBracket == -1)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Point3D.TryParse(s[..(mapStartBracket - 1)], provider, out var loc))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
var mapSlice = s.Slice(mapStartBracket + 1, s.Length - mapStartBracket - 2);
|
||||
if (mapSlice.EqualsOrdinal("(-null-)"))
|
||||
{
|
||||
result = new WorldLocation(loc, null);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!Map.TryParse(mapSlice, provider, out var map))
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
result = new WorldLocation(loc, map);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,8 +313,7 @@ public static class PooledEnumeration
|
|||
}
|
||||
}
|
||||
|
||||
[Parsable]
|
||||
public sealed class Map : IComparable<Map>, ISpanFormattable
|
||||
public sealed class Map : IComparable<Map>, ISpanFormattable, ISpanParsable<Map>
|
||||
{
|
||||
public const int SectorSize = 16;
|
||||
public const int SectorShift = 4;
|
||||
|
|
@ -482,49 +481,6 @@ public sealed class Map : IComparable<Map>, ISpanFormattable
|
|||
return mapValues;
|
||||
}
|
||||
|
||||
// Handles null checks
|
||||
public static Map Parse(string value) => Parse(value ?? ReadOnlySpan<char>.Empty);
|
||||
|
||||
public static Map Parse(ReadOnlySpan<char> value)
|
||||
{
|
||||
value = value.Trim();
|
||||
|
||||
if (value.Length == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value.InsensitiveEquals("Internal"))
|
||||
{
|
||||
return Internal;
|
||||
}
|
||||
|
||||
if (!int.TryParse(value, out var index))
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
else if (index == 127)
|
||||
{
|
||||
return Internal;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Maps.Length; i++)
|
||||
{
|
||||
var map = Maps[i];
|
||||
if (map == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index >= 0 && map.MapIndex == index || value.InsensitiveEquals(map.Name))
|
||||
{
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool TryFormat(Span<char> destination, out int charsWritten, ReadOnlySpan<char> format, IFormatProvider provider)
|
||||
{
|
||||
if (destination.Length >= Name.Length)
|
||||
|
|
@ -1709,4 +1665,98 @@ public sealed class Map : IComparable<Map>, ISpanFormattable
|
|||
}
|
||||
}
|
||||
#pragma warning restore CA1000 // Do not declare static members on generic types
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Map Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Map Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Map result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Map Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (s.Length == 0)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
if (s.InsensitiveEquals("Internal"))
|
||||
{
|
||||
return Internal;
|
||||
}
|
||||
|
||||
if (!int.TryParse(s, provider, out var index))
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
else if (index == 127)
|
||||
{
|
||||
return Internal;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Maps.Length; i++)
|
||||
{
|
||||
var map = Maps[i];
|
||||
if (map == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index >= 0 && map.MapIndex == index || s.InsensitiveEquals(map.Name))
|
||||
{
|
||||
return map;
|
||||
}
|
||||
}
|
||||
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Map result)
|
||||
{
|
||||
s = s.Trim();
|
||||
|
||||
if (s.Length == 0)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (s.InsensitiveEquals("Internal"))
|
||||
{
|
||||
result = Internal;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!int.TryParse(s, provider, out var index))
|
||||
{
|
||||
index = -1;
|
||||
}
|
||||
else if (index == 127)
|
||||
{
|
||||
result = Internal;
|
||||
return true;
|
||||
}
|
||||
|
||||
for (int i = 0; i < Maps.Length; i++)
|
||||
{
|
||||
var map = Maps[i];
|
||||
if (map == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (index >= 0 && map.MapIndex == index || s.InsensitiveEquals(map.Name))
|
||||
{
|
||||
result = map;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ public enum BodyType : byte
|
|||
Equipment
|
||||
}
|
||||
|
||||
[Parsable]
|
||||
public readonly struct Body : IEquatable<object>, IEquatable<Body>, IEquatable<int>, IComparable<int>, IComparable<Body>
|
||||
public readonly struct Body : IEquatable<object>, IEquatable<Body>, IEquatable<int>,
|
||||
IComparable<int>, IComparable<Body>, ISpanParsable<Body>
|
||||
{
|
||||
private static readonly ILogger logger = LogFactory.GetLogger(typeof(Body));
|
||||
|
||||
|
|
@ -148,5 +148,28 @@ public readonly struct Body : IEquatable<object>, IEquatable<Body>, IEquatable<i
|
|||
|
||||
public int CompareTo(int other) => BodyID.CompareTo(other);
|
||||
|
||||
public static Body Parse(string value) => Utility.ToInt32(value);
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Body Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Body Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Body result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Body Parse(ReadOnlySpan<char> s, IFormatProvider provider) => Utility.ToInt32(s);
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Body result)
|
||||
{
|
||||
if (Utility.ToInt32(s, out var value))
|
||||
{
|
||||
result = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server;
|
||||
|
||||
[Parsable]
|
||||
public abstract class Poison
|
||||
public abstract class Poison : ISpanParsable<Poison>
|
||||
{
|
||||
/*public abstract TimeSpan Interval{ get; }
|
||||
public abstract TimeSpan Duration{ get; }*/
|
||||
|
|
@ -44,9 +44,6 @@ public abstract class Poison
|
|||
Poisons.Add(reg);
|
||||
}
|
||||
|
||||
public static Poison Parse(string value) =>
|
||||
(int.TryParse(value, out var plevel) ? GetPoison(plevel) : null) ?? GetPoison(value);
|
||||
|
||||
public static Poison GetPoison(int level)
|
||||
{
|
||||
for (var i = 0; i < Poisons.Count; ++i)
|
||||
|
|
@ -62,13 +59,13 @@ public abstract class Poison
|
|||
return null;
|
||||
}
|
||||
|
||||
public static Poison GetPoison(string name)
|
||||
public static Poison GetPoison(ReadOnlySpan<char> name)
|
||||
{
|
||||
for (var i = 0; i < Poisons.Count; ++i)
|
||||
{
|
||||
var p = Poisons[i];
|
||||
|
||||
if (Utility.InsensitiveCompare(p.Name, name) == 0)
|
||||
if (name.InsensitiveEquals(p.Name))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
|
@ -76,4 +73,49 @@ public abstract class Poison
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Poison Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Poison Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Poison result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Poison Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
if (int.TryParse(s, provider, out var pLevel))
|
||||
{
|
||||
var result = GetPoison(pLevel);
|
||||
if (result != null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
var poison = GetPoison(s.Trim());
|
||||
if (poison == null)
|
||||
{
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
return poison;
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Poison result)
|
||||
{
|
||||
if (int.TryParse(s, provider, out var pLevel))
|
||||
{
|
||||
result = GetPoison(pLevel);
|
||||
if (result != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = GetPoison(s.Trim());
|
||||
return result != null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,12 +4,8 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
namespace Server;
|
||||
|
||||
[Parsable]
|
||||
public abstract class Race
|
||||
public abstract class Race : ISpanParsable<Race>
|
||||
{
|
||||
private static string[] m_RaceNames;
|
||||
private static Race[] m_RaceValues;
|
||||
|
||||
protected Race(
|
||||
int raceID, int raceIndex, string name, string pluralName, int maleBody, int femaleBody,
|
||||
int maleGhostBody, int femaleGhostBody, Expansion requiredExpansion
|
||||
|
|
@ -68,58 +64,6 @@ public abstract class Race
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsAllowedRace(Race race, int allowedRaceFlags) => (allowedRaceFlags & race.RaceFlag) != 0;
|
||||
|
||||
public static string[] GetRaceNames()
|
||||
{
|
||||
CheckNamesAndValues();
|
||||
return m_RaceNames;
|
||||
}
|
||||
|
||||
public static Race[] GetRaceValues()
|
||||
{
|
||||
CheckNamesAndValues();
|
||||
return m_RaceValues;
|
||||
}
|
||||
|
||||
public static Race Parse(string value)
|
||||
{
|
||||
CheckNamesAndValues();
|
||||
|
||||
for (var i = 0; i < m_RaceNames.Length; ++i)
|
||||
{
|
||||
if (m_RaceNames[i].InsensitiveEquals(value))
|
||||
{
|
||||
return m_RaceValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (int.TryParse(value, out var index) && index >= 0 && index < Races.Length &&
|
||||
Races[index] != null)
|
||||
{
|
||||
return Races[index];
|
||||
}
|
||||
|
||||
throw new ArgumentException("Invalid race name");
|
||||
}
|
||||
|
||||
private static void CheckNamesAndValues()
|
||||
{
|
||||
if (m_RaceNames?.Length == AllRaces.Count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_RaceNames = new string[AllRaces.Count];
|
||||
m_RaceValues = new Race[AllRaces.Count];
|
||||
|
||||
for (var i = 0; i < AllRaces.Count; ++i)
|
||||
{
|
||||
var race = AllRaces[i];
|
||||
|
||||
m_RaceNames[i] = race.Name;
|
||||
m_RaceValues[i] = race;
|
||||
}
|
||||
}
|
||||
|
||||
public override string ToString() => Name;
|
||||
|
||||
public virtual bool ValidateHair(Mobile m, int itemID) => ValidateHair(m.Female, itemID);
|
||||
|
|
@ -153,4 +97,67 @@ public abstract class Race
|
|||
public virtual int GhostBody(Mobile m) => GhostBody(m.Female);
|
||||
|
||||
public virtual int GhostBody(bool female) => female ? FemaleGhostBody : MaleGhostBody;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Race Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Race Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Race result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Race Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
if (int.TryParse(s, out var index) && index >= 0 && index < Races.Length)
|
||||
{
|
||||
var race = Races[index];
|
||||
if (race != null)
|
||||
{
|
||||
return race;
|
||||
}
|
||||
}
|
||||
|
||||
s = s.Trim();
|
||||
|
||||
for (var i = 0; i < Races.Length; ++i)
|
||||
{
|
||||
var race = Races[i];
|
||||
if (s.InsensitiveEquals(race.Name) || s.InsensitiveEquals(race.PluralName))
|
||||
{
|
||||
return race;
|
||||
}
|
||||
}
|
||||
|
||||
throw new FormatException($"The input string '{s}' was not in a correct format.");
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Race result)
|
||||
{
|
||||
if (int.TryParse(s, out var index) && index >= 0 && index < Races.Length)
|
||||
{
|
||||
var race = Races[index];
|
||||
if (race != null)
|
||||
{
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
s = s.Trim();
|
||||
|
||||
for (var i = 0; i < Races.Length; ++i)
|
||||
{
|
||||
var race = Races[i];
|
||||
if (s.InsensitiveEquals(race.Name) || s.InsensitiveEquals(race.PluralName))
|
||||
{
|
||||
result = race;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
namespace Server;
|
||||
|
||||
public readonly struct Serial : IComparable<Serial>, IComparable<uint>, IEquatable<Serial>, ISpanFormattable
|
||||
public readonly struct Serial : IComparable<Serial>, IComparable<uint>,
|
||||
IEquatable<Serial>, ISpanFormattable, ISpanParsable<Serial>
|
||||
{
|
||||
public static readonly Serial MinusOne = new(0xFFFFFFFF);
|
||||
public static readonly Serial Zero = new(0);
|
||||
|
|
@ -152,4 +153,28 @@ public readonly struct Serial : IComparable<Serial>, IComparable<uint>, IEquatab
|
|||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public int ToInt32() => (int)Value;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Serial Parse(string s) => Parse(s, null);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static Serial Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool TryParse(string s, IFormatProvider provider, out Serial result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static Serial Parse(ReadOnlySpan<char> s, IFormatProvider provider) => new(Utility.ToUInt32(s));
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out Serial result)
|
||||
{
|
||||
if (Utility.ToUInt32(s, out var value))
|
||||
{
|
||||
result = new Serial(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
result = default;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@ public static class OrdinalStringHelpers
|
|||
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<char> a, char b) =>
|
||||
a.StartsWithOrdinal(new ReadOnlySpan<char>(b));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool StartsWithOrdinal(this ReadOnlySpan<char> a, ReadOnlySpan<char> b) =>
|
||||
a.StartsWith(b, StringComparison.Ordinal);
|
||||
|
|
@ -47,6 +51,9 @@ public static class OrdinalStringHelpers
|
|||
public static bool EndsWithOrdinal(this string a, string b) =>
|
||||
a?.EndsWith(b, StringComparison.Ordinal) == true;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool EndsWithOrdinal(this ReadOnlySpan<char> a, char b) => a.EndsWithOrdinal(new ReadOnlySpan<char>(b));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool EndsWithOrdinal(this ReadOnlySpan<char> a, ReadOnlySpan<char> b) =>
|
||||
a.EndsWith(b, StringComparison.Ordinal);
|
||||
|
|
@ -77,6 +84,10 @@ public static class OrdinalStringHelpers
|
|||
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<char> a, char b) =>
|
||||
a.IndexOfOrdinal(new ReadOnlySpan<char>(b));
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static int IndexOfOrdinal(this ReadOnlySpan<char> a, ReadOnlySpan<char> b) =>
|
||||
a.IndexOf(b, StringComparison.Ordinal);
|
||||
|
|
|
|||
|
|
@ -18,9 +18,8 @@ using System.Runtime.CompilerServices;
|
|||
|
||||
namespace Server;
|
||||
|
||||
[Parsable]
|
||||
[PropertyObject]
|
||||
public class TextDefinition : IEquatable<object>, IEquatable<TextDefinition>
|
||||
public class TextDefinition : IEquatable<object>, IEquatable<TextDefinition>, ISpanParsable<TextDefinition>
|
||||
{
|
||||
public static readonly TextDefinition Empty = new();
|
||||
|
||||
|
|
@ -30,9 +29,15 @@ public class TextDefinition : IEquatable<object>, IEquatable<TextDefinition>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TextDefinition Of(string text) => Of(0, text);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TextDefinition Of(ReadOnlySpan<char> text) => Of(0, text);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TextDefinition Of(int number, string text) => new(number, text);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static TextDefinition Of(int number, ReadOnlySpan<char> text) => new(number, text);
|
||||
|
||||
private TextDefinition()
|
||||
{
|
||||
}
|
||||
|
|
@ -43,6 +48,12 @@ public class TextDefinition : IEquatable<object>, IEquatable<TextDefinition>
|
|||
String = text;
|
||||
}
|
||||
|
||||
private TextDefinition(int number, ReadOnlySpan<char> text)
|
||||
{
|
||||
Number = number;
|
||||
String = text.ToString();
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Number { get; }
|
||||
|
||||
|
|
@ -67,16 +78,6 @@ public class TextDefinition : IEquatable<object>, IEquatable<TextDefinition>
|
|||
|
||||
public static implicit operator string(TextDefinition m) => m?.String;
|
||||
|
||||
public static TextDefinition Parse(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Utility.ToInt32(value, out var i) ? Of(i) : Of(value);
|
||||
}
|
||||
|
||||
public void Deconstruct(out int number, out string s)
|
||||
{
|
||||
if (Number > 0)
|
||||
|
|
@ -118,4 +119,38 @@ public class TextDefinition : IEquatable<object>, IEquatable<TextDefinition>
|
|||
public static bool operator ==(TextDefinition left, TextDefinition right) => Equals(left, right);
|
||||
|
||||
public static bool operator !=(TextDefinition left, TextDefinition right) => !Equals(left, right);
|
||||
|
||||
public static TextDefinition Parse(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return Utility.ToInt32(value, out var i) ? Of(i) : Of(value);
|
||||
}
|
||||
|
||||
public static TextDefinition Parse(string s, IFormatProvider provider) => Parse(s.AsSpan(), provider);
|
||||
|
||||
public static bool TryParse(string s, IFormatProvider provider, out TextDefinition result) =>
|
||||
TryParse(s.AsSpan(), provider, out result);
|
||||
|
||||
public static TextDefinition Parse(ReadOnlySpan<char> s, IFormatProvider provider)
|
||||
{
|
||||
// We don't trim
|
||||
return int.TryParse(s, provider, out var label) ? Of(label) : Of(s);
|
||||
}
|
||||
|
||||
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider provider, out TextDefinition result)
|
||||
{
|
||||
if (int.TryParse(s, provider, out var label))
|
||||
{
|
||||
result = Of(label);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We don't trim
|
||||
result = Of(s);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ namespace Server.Commands.Generic
|
|||
"Parse",
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new[] { typeof(string), typeof(NumberStyles) },
|
||||
Types.ParseStringNumericParamTypes,
|
||||
null
|
||||
);
|
||||
|
||||
|
|
@ -163,12 +163,12 @@ namespace Server.Commands.Generic
|
|||
"Parse",
|
||||
BindingFlags.Public | BindingFlags.Static,
|
||||
null,
|
||||
new[] { typeof(string) },
|
||||
Types.ParseStringParamTypes,
|
||||
null
|
||||
);
|
||||
|
||||
parseMethod = parseGeneral;
|
||||
parseArgs = new object[] { toParse };
|
||||
parseArgs = new object[] { toParse, null };
|
||||
}
|
||||
|
||||
if (parseMethod != null)
|
||||
|
|
@ -183,16 +183,21 @@ namespace Server.Commands.Generic
|
|||
FieldAttributes.Private | FieldAttributes.InitOnly
|
||||
);
|
||||
|
||||
// parseMethod.Invoke(null,
|
||||
// parseArgs.Length == 2 ? new object[] {toParse, (int) parseArgs[1]} : new object[] {toParse});
|
||||
|
||||
il.Emit(OpCodes.Ldarg_0);
|
||||
|
||||
il.Emit(OpCodes.Ldstr, toParse);
|
||||
|
||||
if (parseArgs.Length == 2) // dirty evil hack :-(
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4, (int)parseArgs[1]);
|
||||
if (parseArgs[1]?.GetType() == typeof(NumberStyles))
|
||||
{
|
||||
il.Emit(OpCodes.Ldc_I4, (int)parseArgs[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// IFormatProvider for `IParsable<T>.Parse()` method.
|
||||
il.Emit(OpCodes.Ldnull);
|
||||
}
|
||||
}
|
||||
|
||||
il.Emit(OpCodes.Call, parseMethod);
|
||||
|
|
@ -322,7 +327,9 @@ namespace Server.Commands.Generic
|
|||
}
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid string comparison operator.");
|
||||
{
|
||||
throw new InvalidOperationException("Invalid string comparison operator.");
|
||||
}
|
||||
}
|
||||
|
||||
if (m_Operator is StringOperator.Equal or StringOperator.NotEqual)
|
||||
|
|
@ -437,34 +444,48 @@ namespace Server.Commands.Generic
|
|||
switch (m_Operator)
|
||||
{
|
||||
case ComparisonOperator.Equal:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparisonOperator.NotEqual:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparisonOperator.Greater:
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparisonOperator.GreaterEqual:
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
inverse = true;
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
inverse = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparisonOperator.Lesser:
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Clt);
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparisonOperator.LesserEqual:
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
inverse = true;
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Cgt);
|
||||
inverse = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid comparison operator.");
|
||||
{
|
||||
throw new InvalidOperationException("Invalid comparison operator.");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -477,22 +498,30 @@ namespace Server.Commands.Generic
|
|||
switch (m_Operator)
|
||||
{
|
||||
case ComparisonOperator.Equal:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparisonOperator.NotEqual:
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
{
|
||||
emitter.Compare(OpCodes.Ceq);
|
||||
inverse = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case ComparisonOperator.Greater:
|
||||
case ComparisonOperator.GreaterEqual:
|
||||
case ComparisonOperator.Lesser:
|
||||
case ComparisonOperator.LesserEqual:
|
||||
throw new InvalidOperationException("Property does not support relational comparisons.");
|
||||
{
|
||||
throw new InvalidOperationException("Property does not support relational comparisons.");
|
||||
}
|
||||
|
||||
default:
|
||||
throw new InvalidOperationException("Invalid operator.");
|
||||
{
|
||||
throw new InvalidOperationException("Invalid operator.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,16 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Types
|
||||
{
|
||||
private static readonly Type[] _parseStringParamTypes = { typeof(string) };
|
||||
private static readonly object[] _parseParams = new object[1];
|
||||
public static readonly Type[] ParseStringParamTypes = { typeof(string), typeof(IFormatProvider) };
|
||||
public static readonly Type[] ParseStringNumericParamTypes = { typeof(string), typeof(NumberStyles) };
|
||||
private static object[] _parseParams = { null, null };
|
||||
|
||||
public static readonly Type OfByte = typeof(byte);
|
||||
public static readonly Type OfSByte = typeof(sbyte);
|
||||
|
|
@ -33,7 +37,6 @@ namespace Server
|
|||
|
||||
public static readonly Type OfCPA = typeof(CommandPropertyAttribute);
|
||||
public static readonly Type OfText = typeof(TextDefinition);
|
||||
public static readonly Type OfParsable = typeof(ParsableAttribute);
|
||||
public static readonly Type OfMobile = typeof(Mobile);
|
||||
public static readonly Type OfItem = typeof(Item);
|
||||
public static readonly Type OfCustomEnum = typeof(CustomEnumAttribute);
|
||||
|
|
@ -72,6 +75,8 @@ namespace Server
|
|||
OfULong
|
||||
};
|
||||
|
||||
private static Dictionary<Type, bool> _isParsable;
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsType(Type type, Type check) => check.IsAssignableFrom(type);
|
||||
|
||||
|
|
@ -84,10 +89,25 @@ namespace Server
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsText(Type t) => IsType(t, OfText);
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsParsable(Type t) =>
|
||||
IsChar(t) || IsType(t, OfGuid) ||
|
||||
IsType(t, OfTimeSpan) || IsNumeric(t) || IsDecimal(t) || t.IsDefined(OfParsable, false);
|
||||
public static bool IsParsable(Type t)
|
||||
{
|
||||
_isParsable ??= new();
|
||||
if (_isParsable.TryGetValue(t, out var isParsable))
|
||||
{
|
||||
return isParsable;
|
||||
}
|
||||
|
||||
foreach (var x in t.GetInterfaces())
|
||||
{
|
||||
if (x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IParsable<>))
|
||||
{
|
||||
isParsable = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return _isParsable[t] = isParsable;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsDecimal(Type t) => Array.IndexOf(DecimalTypes, t) >= 0;
|
||||
|
|
@ -98,9 +118,16 @@ namespace Server
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static bool IsEntity(Type t) => OfEntity.IsAssignableFrom(t);
|
||||
|
||||
private static Dictionary<Type, MethodInfo> _parseMethods;
|
||||
|
||||
public static object Parse(Type t, string value)
|
||||
{
|
||||
var method = t.GetMethod("Parse", _parseStringParamTypes);
|
||||
_parseMethods ??= new();
|
||||
if (!_parseMethods.TryGetValue(t, out var method))
|
||||
{
|
||||
_parseMethods[t] = method = t.GetMethod("Parse", ParseStringParamTypes);
|
||||
}
|
||||
|
||||
_parseParams[0] = value;
|
||||
return method?.Invoke(null, _parseParams);
|
||||
}
|
||||
|
|
@ -160,11 +187,11 @@ namespace Server
|
|||
return null;
|
||||
}
|
||||
|
||||
if (value.StartsWithOrdinal("0x") && IsNumeric(type))
|
||||
if (IsNumeric(type))
|
||||
{
|
||||
try
|
||||
{
|
||||
constructed = Convert.ChangeType(Convert.ToUInt64(value[2..], 16), type);
|
||||
constructed = Convert.ChangeType(Convert.ToUInt64(value), type);
|
||||
return null;
|
||||
}
|
||||
catch
|
||||
|
|
|
|||
|
|
@ -416,7 +416,12 @@ namespace Server.Saves
|
|||
var i = 0;
|
||||
foreach (var part in value.Tokenize('-'))
|
||||
{
|
||||
parts[i++] = int.Parse(part);
|
||||
if (!int.TryParse(part, out var partValue))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
parts[i++] = partValue;
|
||||
}
|
||||
|
||||
if (i == 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue