From 644488dde7119463c997b40c9028e64409dda7c6 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:38:23 -0700 Subject: [PATCH] feat(spawners): add typed JSON binding for RegionSpawner MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add RegionSpawner.Json.cs with a `region` shadow property (serializes SpawnRegion.Name) and OnAfterJsonDeserialize override that resolves the region by name using _jsonMap from BaseSpawner. Mark RegionSpawner with [JsonDiscoverableType] and [JsonConstructor] on its parameterless ctor so SpawnerJsonSerializer discovers it for STJ polymorphism. Add RegionSpawnerRoundTripTests: create+register a test BaseRegion on Felucca (game regions are not loaded in the test environment), serialize a RegionSpawner, assert $type and region name in JSON, deserialize, and assert SpawnRegion.Name round-trips correctly. RED → GREEN confirmed. Co-Authored-By: Claude Sonnet 4.6 --- .../Json/RegionSpawnerRoundTripTests.cs | 48 +++++++++++++++++++ .../Engines/Spawners/RegionSpawner.Json.cs | 41 ++++++++++++++++ .../Engines/Spawners/RegionSpawner.cs | 2 + 3 files changed, 91 insertions(+) create mode 100644 Projects/UOContent.Tests/Tests/Engines/Spawners/Json/RegionSpawnerRoundTripTests.cs create mode 100644 Projects/UOContent/Engines/Spawners/RegionSpawner.Json.cs diff --git a/Projects/UOContent.Tests/Tests/Engines/Spawners/Json/RegionSpawnerRoundTripTests.cs b/Projects/UOContent.Tests/Tests/Engines/Spawners/Json/RegionSpawnerRoundTripTests.cs new file mode 100644 index 000000000..9046109e1 --- /dev/null +++ b/Projects/UOContent.Tests/Tests/Engines/Spawners/Json/RegionSpawnerRoundTripTests.cs @@ -0,0 +1,48 @@ +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 RegionSpawnerRoundTripTests +{ + [Fact] + public void RegionSpawner_RoundTrips_RegionByName() + { + // The test environment does not load game regions (no AssemblyHandler.Invoke("Initialize")), + // so we create and register a test BaseRegion on Felucca directly. + var region = new BaseRegion( + "TestSpawnRegion", + Map.Felucca, + 50, + new Rectangle3D(1400, 1670, -128, 40, 40, 256) + ); + region.Register(); + + try + { + var spawner = new RegionSpawner("Fisherman") { SpawnRegion = region }; + spawner.MoveToWorld(new Point3D(1416, 1683, 0), Map.Felucca); + + var json = JsonSerializer.Serialize>( + new List { spawner }, SpawnerJsonSerializer.Options); + Assert.Contains("\"$type\": \"RegionSpawner\"", json); + Assert.Contains(region.Name, json); + + var rt = JsonSerializer.Deserialize>(json, SpawnerJsonSerializer.Options); + var s = Assert.IsType(Assert.Single(rt)); + Assert.Equal(region.Name, s.SpawnRegion?.Name); + + s.Delete(); + spawner.Delete(); + } + finally + { + region.Unregister(); + } + } +} diff --git a/Projects/UOContent/Engines/Spawners/RegionSpawner.Json.cs b/Projects/UOContent/Engines/Spawners/RegionSpawner.Json.cs new file mode 100644 index 000000000..0cbbb802b --- /dev/null +++ b/Projects/UOContent/Engines/Spawners/RegionSpawner.Json.cs @@ -0,0 +1,41 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2026 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: RegionSpawner.Json.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.Text.Json.Serialization; +using Server.Regions; + +namespace Server.Engines.Spawners; + +public partial class RegionSpawner +{ + private string _jsonRegion; + + [JsonInclude] + [JsonPropertyName("region")] + public string JsonRegion + { + get => SpawnRegion?.Name; + set => _jsonRegion = value; + } + + protected internal override void OnAfterJsonDeserialize() + { + base.OnAfterJsonDeserialize(); + + _spawnRegion = Region.Find(_jsonRegion, _jsonMap) as BaseRegion; + _spawnRegion?.InitRectangles(); + SpawnRegionName = _spawnRegion?.Name; + } +} diff --git a/Projects/UOContent/Engines/Spawners/RegionSpawner.cs b/Projects/UOContent/Engines/Spawners/RegionSpawner.cs index c88d774c5..fe26cbe03 100644 --- a/Projects/UOContent/Engines/Spawners/RegionSpawner.cs +++ b/Projects/UOContent/Engines/Spawners/RegionSpawner.cs @@ -22,6 +22,7 @@ using Server.Regions; namespace Server.Engines.Spawners; [SerializationGenerator(0)] +[JsonDiscoverableType] public partial class RegionSpawner : Spawner { [SerializableField(0, getter: "private", setter: "private")] @@ -32,6 +33,7 @@ public partial class RegionSpawner : Spawner public override Region Region => _spawnRegion; [Constructible(AccessLevel.Developer)] + [System.Text.Json.Serialization.JsonConstructor] public RegionSpawner() { }