using System; using System.Collections.Generic; using System.Text.Json; using Server; using Server.Engines.Spawners; using Server.Regions; using Xunit; namespace UOContent.Tests.Engines.Spawners.Json; [Collection("Sequential UOContent Tests")] public class SpawnerDtoRoundTripTests { [Fact] public void Spawner_NonSquareBounds_WritesSpawnBounds_RoundTrips() { Spawner original = null; BaseSpawner rebuilt = null; try { // Bounds centered on (102,102), placed at (105,105) -> not a homeRange square. original = new Spawner(2, TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(7), 0, new Rectangle3D(100, 100, 0, 5, 5, 0), "Fisherman"); original.MoveToWorld(new Point3D(105, 105, 0), Map.Felucca); var json = JsonSerializer.Serialize(new List { original.ToDto() }, SpawnerJsonSerializer.Options); Assert.Contains("\"$type\": \"Spawner\"", json); Assert.Contains("\"count\": 2", json); Assert.Contains("spawnBounds", json); Assert.DoesNotContain("homeRange", json); var dtos = JsonSerializer.Deserialize>(json, SpawnerJsonSerializer.Options); rebuilt = Assert.Single(dtos).ToSpawner(); var s = Assert.IsType(rebuilt); Assert.Equal(2, s.Count); Assert.Equal(TimeSpan.FromMinutes(3), s.MinDelay); Assert.Equal(new Rectangle3D(100, 100, 0, 5, 5, 0), s.SpawnBounds); Assert.Equal("Fisherman", Assert.Single(s.Entries).SpawnedName); } finally { rebuilt?.Delete(); original?.Delete(); } } [Fact] public void Spawner_HomeRangeSquare_WritesHomeRange_RoundTrips() { Spawner original = null; BaseSpawner rebuilt = null; try { original = new Spawner("Fisherman"); original.MoveToWorld(new Point3D(200, 200, 0), Map.Felucca); // Exactly what homeRange 5 reconstructs (centered square, standard z/depth). original.SpawnBounds = new Rectangle3D(195, 195, -128, 11, 11, 256); var json = JsonSerializer.Serialize(new List { original.ToDto() }, SpawnerJsonSerializer.Options); Assert.Contains("\"homeRange\": 5", json); Assert.DoesNotContain("spawnBounds", json); var dtos = JsonSerializer.Deserialize>(json, SpawnerJsonSerializer.Options); rebuilt = Assert.Single(dtos).ToSpawner(); Assert.Equal(new Rectangle3D(195, 195, -128, 11, 11, 256), rebuilt.SpawnBounds); } finally { rebuilt?.Delete(); original?.Delete(); } } [Fact] public void Spawner_WritesMandatory_OmitsOptionalDefaults() { Spawner original = null; try { // Default delays (5/10), team 0, default maxSpawnAttempts. original = new Spawner("Fisherman"); original.MoveToWorld(new Point3D(110, 110, 0), Map.Felucca); var json = JsonSerializer.Serialize(new List { original.ToDto() }, SpawnerJsonSerializer.Options); // Mandatory — always written, even at default. Assert.Contains("\"guid\":", json); Assert.Contains("minDelay", json); Assert.Contains("maxDelay", json); // Optional defaults — omitted. Assert.DoesNotContain("\"team\"", json); Assert.DoesNotContain("maxSpawnAttempts", json); Assert.DoesNotContain("spawnLocationIsHome", json); } finally { original?.Delete(); } } [Fact] public void RegionSpawner_RoundTrips_RegionByName() { var region = new BaseRegion("DtoTestRegion", Map.Felucca, 50, new Rectangle3D(1400, 1670, 0, 40, 40, 0)); region.Register(); RegionSpawner original = null; BaseSpawner rebuilt = null; try { original = new RegionSpawner("Fisherman") { SpawnRegion = region }; original.MoveToWorld(new Point3D(1416, 1683, 0), Map.Felucca); var json = JsonSerializer.Serialize(new List { original.ToDto() }, SpawnerJsonSerializer.Options); Assert.Contains("\"$type\": \"RegionSpawner\"", json); Assert.Contains("DtoTestRegion", json); Assert.DoesNotContain("homeRange", json); Assert.DoesNotContain("spawnBounds", json); var dtos = JsonSerializer.Deserialize>(json, SpawnerJsonSerializer.Options); rebuilt = Assert.Single(dtos).ToSpawner(); Assert.Equal("DtoTestRegion", Assert.IsType(rebuilt).SpawnRegion?.Name); } finally { rebuilt?.Delete(); original?.Delete(); region.Unregister(); } } [Fact] public void ProximitySpawner_RoundTrips_Fields() { ProximitySpawner original = null; BaseSpawner rebuilt = null; try { original = new ProximitySpawner("Fisherman") { TriggerRange = 4, InstantFlag = true, SpawnMessage = 500000 }; original.MoveToWorld(new Point3D(120, 120, 0), Map.Felucca); var json = JsonSerializer.Serialize(new List { original.ToDto() }, SpawnerJsonSerializer.Options); Assert.Contains("\"$type\": \"ProximitySpawner\"", json); Assert.Contains("\"triggerRange\": 4", json); Assert.Contains("\"instant\": true", json); var dtos = JsonSerializer.Deserialize>(json, SpawnerJsonSerializer.Options); rebuilt = Assert.Single(dtos).ToSpawner(); var p = Assert.IsType(rebuilt); Assert.Equal(4, p.TriggerRange); Assert.True(p.InstantFlag); Assert.Equal(500000, p.SpawnMessage.Number); } finally { rebuilt?.Delete(); original?.Delete(); } } }