diff --git a/Distribution/Data/teleporters.json b/Distribution/Data/teleporters.json index f4e8abba4..82a4fe684 100644 --- a/Distribution/Data/teleporters.json +++ b/Distribution/Data/teleporters.json @@ -6869,4 +6869,4 @@ "dst": { "map": "TerMur", "loc": [511, 585, 9] }, "back": false } -] \ No newline at end of file +] diff --git a/Projects/Server/Geometry/WorldLocation.cs b/Projects/Server/Geometry/WorldLocation.cs index 2a7fa4597..91d24802c 100644 --- a/Projects/Server/Geometry/WorldLocation.cs +++ b/Projects/Server/Geometry/WorldLocation.cs @@ -104,12 +104,7 @@ namespace Server public int CompareTo(WorldLocation other) { var locComparison = m_Loc.CompareTo(other.m_Loc); - if (locComparison != 0) - { - return locComparison; - } - - return Comparer.Default.Compare(m_Map, other.m_Map); + return locComparison != 0 ? locComparison : Comparer.Default.Compare(m_Map, other.m_Map); } public static implicit operator Point3D(WorldLocation worldLocation) => worldLocation.Location; diff --git a/Projects/Server/JsonConfiguration/Converters/MapConverter.cs b/Projects/Server/JsonConfiguration/Converters/MapConverter.cs index f93a412e3..71109ef88 100644 --- a/Projects/Server/JsonConfiguration/Converters/MapConverter.cs +++ b/Projects/Server/JsonConfiguration/Converters/MapConverter.cs @@ -21,10 +21,15 @@ namespace Server.Json { public class MapConverter : JsonConverter { - public override Map Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => Map.Parse(reader.GetString()); + public override Map Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => + reader.TokenType switch + { + JsonTokenType.String => Map.Parse(reader.GetString()), + JsonTokenType.Number => Map.Maps[reader.GetInt32()], + _ => throw new JsonException($"Value must be a number or string") + }; - public override void Write(Utf8JsonWriter writer, Map value, JsonSerializerOptions options) - => writer.WriteStringValue(value.Name); + public override void Write(Utf8JsonWriter writer, Map value, JsonSerializerOptions options) => + writer.WriteStringValue(value.Name); } } diff --git a/Projects/Server/JsonConfiguration/Converters/WorldLocationConverter.cs b/Projects/Server/JsonConfiguration/Converters/WorldLocationConverter.cs index 8a9ec6885..5cdfc909a 100644 --- a/Projects/Server/JsonConfiguration/Converters/WorldLocationConverter.cs +++ b/Projects/Server/JsonConfiguration/Converters/WorldLocationConverter.cs @@ -21,6 +21,9 @@ namespace Server.Json { public class WorldLocationConverter : JsonConverter { + private static Point3DConverter _point3DConverter; + private static MapConverter _mapConverter; + private WorldLocation DeserializeArray(ref Utf8JsonReader reader) { Span data = stackalloc int[3]; @@ -45,6 +48,7 @@ namespace Server.Json else if (count == 3) { map = Map.Maps[reader.GetInt32()]; + hasMap = true; } count++; @@ -52,12 +56,20 @@ namespace Server.Json if (reader.TokenType == JsonTokenType.String) { - map = Map.Parse(reader.GetString()); + var key = reader.GetString(); + + if (count != 3 || hasMap) + { + throw new JsonException($"Value {key} is not valid for this element."); + } + + map = Map.Parse(key); + hasMap = true; break; } } - if (!hasMap || count < 3 || count > 4) + if (!hasMap || count != 3) { throw new JsonException("WorldLocation must be an array of x, y, z, and map"); } @@ -131,7 +143,10 @@ namespace Server.Json } hasLoc = true; - var loc = new Point3DConverter().Read(ref reader, typeof(Point3D), options); + + _point3DConverter ??= new Point3DConverter(); + + var loc = _point3DConverter.Read(ref reader, typeof(Point3D), options); data[0] = loc.X; data[1] = loc.Y; data[2] = loc.Z; @@ -139,15 +154,13 @@ namespace Server.Json continue; } - map = reader.TokenType switch - { - JsonTokenType.String => Map.Parse(reader.GetString()), - JsonTokenType.Number => Map.Maps[reader.GetInt32()], - _ => throw new JsonException($"Value for {key} must be a number or string") - }; + _mapConverter ??= new MapConverter(); + map = _mapConverter.Read(ref reader, typeof(Map), options); + + hasMap = true; } - if (!hasMap || count < 2) + if (!hasMap || count != 3) { throw new JsonException("WorldLocation must have an x, y, z, and map properties"); } diff --git a/Projects/Server/JsonConfiguration/JsonConfig.cs b/Projects/Server/JsonConfiguration/JsonConfig.cs index fb25de5e1..bfd8c70a8 100644 --- a/Projects/Server/JsonConfiguration/JsonConfig.cs +++ b/Projects/Server/JsonConfiguration/JsonConfig.cs @@ -30,10 +30,10 @@ namespace Server.Json // In the future this should be optimized by cloning DefaultOptions var options = new JsonSerializerOptions { - ReadCommentHandling = JsonCommentHandling.Skip, WriteIndented = true, AllowTrailingCommas = true, - IgnoreNullValues = true + IgnoreNullValues = true, + ReadCommentHandling = JsonCommentHandling.Skip }; options.Converters.Add(new MapConverterFactory()); @@ -43,6 +43,7 @@ namespace Server.Json options.Converters.Add(new IPEndPointConverterFactory()); options.Converters.Add(new NullableStructSerializerFactory()); options.Converters.Add(new TypeConverterFactory()); + options.Converters.Add(new WorldLocationConverterFactory()); for (var i = 0; i < converters.Length; i++) { diff --git a/Projects/Server/Map.cs b/Projects/Server/Map.cs index 73f3a47b2..0281086f8 100644 --- a/Projects/Server/Map.cs +++ b/Projects/Server/Map.cs @@ -404,10 +404,28 @@ namespace Server if (!int.TryParse(value, out var index)) { - return Maps.FirstOrDefault(m => m != null && Insensitive.Equals(m.Name, value)); + index = -1; + } + else if (index == 127) + { + return Internal; } - return index == 127 ? Internal : Maps.FirstOrDefault(m => m?.MapIndex == index); + for (int i = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map == null) + { + continue; + } + + if (index >= 0 && map.MapIndex == index || Insensitive.Equals(map.Name, value)) + { + return map; + } + } + + return null; } public override string ToString() => Name; diff --git a/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs b/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs index 4c4a1c17c..274972601 100644 --- a/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs +++ b/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs @@ -1,20 +1,22 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; -using System.Text.Json; using System.Text.Json.Serialization; using Server.Items; +using Server.Json; namespace Server.Commands { public struct TeleporterDefinition { - [JsonPropertyName("src")] public WorldLocation Source { get; set; } + [JsonPropertyName("src")] + public WorldLocation Source { get; set; } - [JsonPropertyName("dst")] public WorldLocation Destination { get; set; } + [JsonPropertyName("dst")] + public WorldLocation Destination { get; set; } - [JsonPropertyName("back")] public bool Back { get; set; } + [JsonPropertyName("back")] + public bool Back { get; set; } public override string ToString() => $"{{{Source},{Destination},{Back}}}"; @@ -29,14 +31,7 @@ namespace Server.Commands public static class GenTeleporter { private const int SuccessHue = 72, WarningHue = 53, ErrorHue = 33; - private static readonly string TeleporterJsonDataPath = Path.Combine("Data", "teleporters.json"); - - private static readonly JsonSerializerOptions JsonOptions = new JsonSerializerOptions - { - AllowTrailingCommas = true, - PropertyNameCaseInsensitive = true, - ReadCommentHandling = JsonCommentHandling.Skip - }; + private static readonly string TeleporterJsonDataPath = Path.Combine(Core.BaseDirectory, "Data/teleporters.json"); public static void Initialize() { @@ -108,17 +103,7 @@ namespace Server.Commands { try { - string json; - using (var reader = new StreamReader(TeleporterJsonDataPath)) - { - json = reader.ReadToEnd(); - } - - var teleporters = JsonSerializer.Deserialize>(json, JsonOptions); - for (var i = 0; i < teleporters.Count; i++) - { - processor(teleporters[i]); - } + JsonConfig.Deserialize>(TeleporterJsonDataPath).ForEach(processor); } catch (Exception ex) { @@ -140,13 +125,15 @@ namespace Server.Commands public static int DeleteTeleporters(WorldLocation worldLocation) { var eable = worldLocation.Map.GetItemsInRange(worldLocation, 0); - var items = eable - .Where(x => !(x is KeywordTeleporter || x is SkillTeleporter) && IsWithinZ(x.Z - worldLocation.Z)); + var count = 0; - foreach (var item in items) + foreach (var item in eable) { - count++; - item.Delete(); + if (!(item is KeywordTeleporter || item is SkillTeleporter) && IsWithinZ(item.Z - worldLocation.Z)) + { + count++; + item.Delete(); + } } eable.Free();