## Summary Removes the dated `DynamicJson` JSON helper and migrates spawner JSON (de)serialization to a polymorphic `record SpawnerDto` hierarchy. `DynamicJson` was the last remaining consumer (regions moved off it in #1400). The key correctness improvement: **System.Text.Json deserializes plain DTO records, never a live `Item`.** Previously, deserializing directly into an `Item` meant STJ constructed world-registered objects *before* the data was validated — a malformed/hand-edited spawn file could leave orphaned spawner Items in the world save. Now a parse failure is GC-only; `dto.ToSpawner()` constructs the spawner only from a fully-validated DTO and self-cleans on failure. ## What changed - **New:** `SpawnerDto` (abstract) + `SpawnerDataDto` / `RegionSpawnerDto` / `ProximitySpawnerDto`, each marked with a reusable `[JsonDiscoverableType]` opt-in attribute. Auto-discovered at the `Configure` phase — no manual registration list (avoids the regions `Register<T>()` footgun), open to custom spawner subtypes. - **Symmetric mapping:** `BaseSpawner.ToDto()` (export) ⇄ `SpawnerDto.ToSpawner()` (import). `ToSpawner()` deletes-and-rethrows on any failure, so the importer can never orphan an Item. - **`SpawnerJsonSerializer`** wires `$type` polymorphism on the `SpawnerDto` root with loud collision/constructibility validation. - **Import/export commands** rewired to the typed DTO path (reflection `FindTypeByName`/`CreateInstance` removed). - **Data migration:** the 109 `Distribution/Data/Spawns/**` files moved from `"type"`→`"$type"` and legacy `homeRange`→`spawnBounds`. The runtime still *reads* legacy `homeRange` for external files. The `homeRange→spawnBounds` formula is proven equivalent to the runtime conversion (`BoundsEquivalenceTests`, hr=0/1/3/7). - **Deleted:** `Projects/Server/Json/DynamicJson.cs`. Sparse export output matches the legacy `ToJson` (nullable DTO properties + `WhenWritingNull`). Binary world-save serialization is untouched. ## Tests - DTO round-trip per spawner type; sparse-default omission; legacy `homeRange` read; export/import file round-trip. - `Import_MalformedFile_LeaksNoWorldItems` — proves a mid-array parse failure constructs zero world Items. - `AllSpawnFilesLoadTests` — every migrated spawn file deserializes and builds. - Duplicate-discriminator validation. - UOContent.Tests 485/485, Server.Tests 710/710, build clean. ## Follow-up (not in this PR) `Rectangle3DConverter.Write` (in `Projects/Server/`) omits `z1/z2` when `Start.Z == -128`, so a future server-side export of a `homeRange`-style spawner round-trips depth 256→255. Pre-existing and out of scope here (Server change); the migrated data reads correctly. Worth a separate small converter PR.
761 lines
18 KiB
JSON
761 lines
18 KiB
JSON
[
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "03112703-010a-4495-90de-3dceafabf6bb",
|
|
"name": "Spawner (504)",
|
|
"location": [502, 589, 24],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "0360875a-9408-4f4a-a42c-200f359baccb",
|
|
"name": "Spawner (504)",
|
|
"location": [756, 1302, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Armorer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1159a610-a01a-4cac-841f-ca37fcf2ab21",
|
|
"name": "Spawner (504)",
|
|
"location": [1177, 985, 38],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "117e79c9-e92c-4094-89af-ceef02b6d875",
|
|
"name": "Spawner (504)",
|
|
"location": [724, 1297, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Jeweler", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "11f9b7fa-b1ea-4a93-848a-5339c852afa5",
|
|
"name": "Spawner (504)",
|
|
"location": [695, 1297, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Mage", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1457ebfc-398e-415e-b091-20427af4fb70",
|
|
"name": "Spawner (504)",
|
|
"location": [691, 1264, 47],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Mapmaker", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "152e7156-8c9c-4aae-a560-7972868cbc57",
|
|
"name": "Spawner (504)",
|
|
"location": [789, 1278, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "AnimalTrainer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "15590b9b-8815-4906-8e9e-d08a54b6a2f1",
|
|
"name": "Spawner (504)",
|
|
"location": [773, 1248, 26],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Blacksmith", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "16523597-999a-4504-aa59-7b01c881978d",
|
|
"name": "Spawner (504)",
|
|
"location": [689, 1255, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Scribe", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1990cbea-3f71-44da-aec2-0af4e07e3618",
|
|
"name": "Spawner (504)",
|
|
"location": [702, 1298, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Alchemist", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1b386724-c26f-4714-80b3-edaaa46b3ab4",
|
|
"name": "Spawner (504)",
|
|
"location": [683, 1298, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Herbalist", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1bef801b-5ac8-4cde-a3bd-71fff904d997",
|
|
"name": "Spawner (504)",
|
|
"location": [679, 1207, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 0,
|
|
"entries": [
|
|
{ "name": "InnKeeper", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "1f9e3288-f988-4ea3-95e8-251aa38d064c",
|
|
"name": "Spawner (504)",
|
|
"location": [692, 1213, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "TavernKeeper", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "21467215-aae1-4e1c-bf72-1137b91b71eb",
|
|
"name": "Spawner (504)",
|
|
"location": [730, 1282, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Provisioner", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "294130b1-fd5a-4cef-9c68-a5491f5e59c6",
|
|
"name": "Spawner (504)",
|
|
"location": [226, 786, 57],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "30f1eaf5-633e-494a-aadb-2997f3e8d0a4",
|
|
"name": "Spawner (504)",
|
|
"location": [735, 1256, 30],
|
|
"map": "Tokuno",
|
|
"count": 30,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 60,
|
|
"walkingRange": 80,
|
|
"entries": [
|
|
{ "name": "Noble", "maxCount": 10, "probability": 100 },
|
|
{ "name": "Peasant", "maxCount": 10, "probability": 100 },
|
|
{ "name": "hirebeggar", "maxCount": 10, "probability": 100 },
|
|
{ "name": "Samurai", "maxCount": 10, "probability": 100 },
|
|
{ "name": "Ninja", "maxCount": 10, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "33f10364-0097-42d5-95b1-c3f73750fda0",
|
|
"name": "Spawner (504)",
|
|
"location": [720, 1213, 45],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Tinker", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "3df1960a-2e81-4997-ab85-3f1062065c7d",
|
|
"name": "Spawner (504)",
|
|
"location": [763, 247, 71],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "448a5e8c-0682-488b-ba85-4a457ed8329c",
|
|
"name": "Spawner (504)",
|
|
"location": [742, 1304, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Armorer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "4830fbdc-9c83-4e22-af7a-cd868807eb9c",
|
|
"name": "Spawner (504)",
|
|
"location": [297, 637, 15],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 2,
|
|
"walkingRange": 2,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "57f4d4ba-3841-4d12-bec6-37b059c49840",
|
|
"name": "Spawner (504)",
|
|
"location": [248, 1089, 10],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "5ada367e-0bcb-487e-9e44-ef259bfec2c7",
|
|
"name": "Spawner (504)",
|
|
"location": [781, 1219, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Healer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "67fe5dc9-67d2-4e5f-afab-03691f497fed",
|
|
"name": "Spawner (504)",
|
|
"location": [661, 1209, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Blacksmith", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "698d030e-cf3f-40fd-be6e-4a92866dbfb1",
|
|
"name": "Spawner (504)",
|
|
"location": [668, 1254, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "BardGuildmaster", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "7dad1cc2-dfab-490e-915f-8d00ed39f14c",
|
|
"name": "Spawner (504)",
|
|
"location": [749, 1303, 25],
|
|
"map": "Tokuno",
|
|
"count": 2,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Armorer", "maxCount": 1, "probability": 100 },
|
|
{ "name": "Weaponsmith", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "80122c8e-85c4-41a7-a347-d8c0074e6031",
|
|
"name": "Spawner (504)",
|
|
"location": [371, 431, 32],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 5,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "840e2e09-7a7e-43cc-a5d0-a5be3d4e00d6",
|
|
"name": "Spawner (504)",
|
|
"location": [669, 1266, 47],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Shipwright", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "876d5b73-9f59-4446-8144-dd997bf93916",
|
|
"name": "Spawner (504)",
|
|
"location": [1152, 936, 65],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "8c714386-6b61-4f4e-9eec-f75cd78010a6",
|
|
"name": "Spawner (504)",
|
|
"location": [732, 1256, 30],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 0,
|
|
"entries": [
|
|
{ "name": "TownCrier", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "901b6857-11f1-4c9f-bb1f-1399406dc3b6",
|
|
"name": "Spawner (504)",
|
|
"location": [399, 549, 15],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "95447e64-a9d3-45ca-81c7-318441ca97d4",
|
|
"name": "Spawner (504)",
|
|
"location": [1111, 495, 18],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "97d04faf-bf2f-4085-bdb9-2a6538c4a97a",
|
|
"name": "Spawner (504)",
|
|
"location": [720, 1211, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Tanner", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "a4b62432-203b-4b3e-894c-651e62d68567",
|
|
"name": "Spawner (504)",
|
|
"location": [739, 1223, 45],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Carpenter", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "af820fc2-57d8-4b19-9a54-9bb57f9736cb",
|
|
"name": "Spawner (504)",
|
|
"location": [1221, 494, 27],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "b4b940cb-17ef-4234-842c-2bdcbd7827f0",
|
|
"name": "Spawner (504)",
|
|
"location": [779, 1259, 26],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Weaponsmith", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "b5b2efe1-d96b-4d37-ac13-ec6251ad23f9",
|
|
"name": "Spawner (504)",
|
|
"location": [895, 519, 53],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 2,
|
|
"walkingRange": 2,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "b65649fc-1b3a-4124-b063-0f0e7b35d3d2",
|
|
"name": "Spawner (504)",
|
|
"location": [979, 238, 21],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 5,
|
|
"walkingRange": 5,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "bdc0117b-2e5b-458b-90ca-0f3bfa5489e8",
|
|
"name": "Spawner (504)",
|
|
"location": [703, 1262, 25],
|
|
"map": "Tokuno",
|
|
"count": 3,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 10,
|
|
"entries": [
|
|
{ "name": "Baker", "maxCount": 1, "probability": 100 },
|
|
{ "name": "Butcher", "maxCount": 1, "probability": 100 },
|
|
{ "name": "Cook", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "cfc1714e-8851-4cf8-a9a5-bb1d4d9236b0",
|
|
"name": "Spawner (504)",
|
|
"location": [558, 534, 32],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "d001030a-99d7-4146-83f9-b5e1aff453b0",
|
|
"name": "Spawner (504)",
|
|
"location": [729, 1249, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Banker", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "d64f79d1-bb69-4aab-8099-04cc92244b60",
|
|
"name": "Spawner (504)",
|
|
"location": [806, 1308, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Weaponsmith", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "dc6b9648-9165-491e-87b2-f5950d8e38ad",
|
|
"name": "Spawner (504)",
|
|
"location": [744, 1210, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Weaver", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "e081b4f9-5c48-4808-82e7-f8bb95309a19",
|
|
"name": "Spawner (504)",
|
|
"location": [744, 1219, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Tailor", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "f44766ae-31e3-46fa-94ce-869a53621012",
|
|
"name": "Spawner (504)",
|
|
"location": [662, 1210, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Blacksmith", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "f50b6789-7be4-43f0-a1be-c53e85a6997b",
|
|
"name": "Spawner (504)",
|
|
"location": [675, 1265, 25],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 4,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Bard", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "f6481ae3-b345-40ab-aaa2-2eea59aee211",
|
|
"name": "Spawner (504)",
|
|
"location": [781, 1301, 26],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 0,
|
|
"walkingRange": 4,
|
|
"entries": [
|
|
{ "name": "Bowyer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
},
|
|
{
|
|
"$type": "Spawner",
|
|
"guid": "fb70140d-b0d9-41c7-9975-c8136c4ee686",
|
|
"name": "Spawner (504)",
|
|
"location": [1166, 802, 27],
|
|
"map": "Tokuno",
|
|
"count": 1,
|
|
"minDelay": "00:05:00",
|
|
"maxDelay": "00:10:00",
|
|
"team": 0,
|
|
"homeRange": 3,
|
|
"walkingRange": 3,
|
|
"entries": [
|
|
{ "name": "WanderingHealer", "maxCount": 1, "probability": 100 }
|
|
]
|
|
}
|
|
]
|