Решили: карту акта показывает Лаборатория, а генерирует её настоящий MapGenerator, собранный обычным dotnet из ИСХОДНИКОВ и запущенный мимо Unity (tools/MapDump, scripts/map-dump.ps1). Топология приходит дампом, раскладка пока крутится в стенде.

Почему: проверять композицию карты — воздух между узлами, место под имена зон, во что превращается веер дорог — надо до того, как это уедет в игру, и на разных сидах. Схема, нарисованная руками под вывод, всегда красива и потому бесполезна для такого решения.

Развилка была в том, ЧТО скармливать дамперу:

  • Готовую Library/ScriptAssemblies/Guildmaster.Guild.dll — дешевле на один шаг сборки, но она обновляется только на domain reload, а код мы правим файлами мимо редактора. Стенд начал бы молча рисовать вчерашнюю карту — ровно та тихая ложь, ради которой стенд и заводился. Отвергнуто.
  • Порт генератора в TypeScript (как в map-shapes.ts) — у одного факта появилось бы два владельца, и они разъехались бы на первой правке. Годится для схемы, не годится для решения.
  • Исходники + ссылки на готовые сборки — принято. MapGenerator, MapGenConfig и XorShiftRng не используют ни одного символа Unity (using UnityEngine в генераторе оказался мёртвым), поэтому собираются за секунды; Guildmaster.Core, Guildmaster.Data и UnityEngine.CoreModule берутся готовыми — заглушки вместо них подделали бы типы и разъехались бы с настоящими молча.

Числа — из ассетов, а не из дефолтов кода: ActConfig.asset (топология), MapStyle.asset (шаги сетки, поля листа, шаг дорожки, floorsInView), MapNode.prefab (радиус узла). Играет ассет.

Грабли:

  • Ссылки с Private=false компилируются, но падают на запуске: рантайм не ищет Guildmaster.Core в чужой папке. Сборки надо класть рядом.
  • Парсеру YAML нужны РАЗНЫЕ правила строгости, и это не непоследовательность. Конфиг акта читается целиком, поэтому незнакомый ключ — повод упасть: пропустив его, дампер сгенерирует правдоподобную чужую карту. Из стиля берётся горсть полей из полусотни — там падать надо на исчезновении нужного, а не на появлении лишнего.
  • На общем плане больший шаг сетки не даёт воздуха — он мельчит узлы. Карта вписывается в тот же кадр, и «просторнее» превращается в «мельче». Воздух виден только в рабочем кадре камеры (floorsInView этажей), потому что игрок смотрит карту так. Отсюда -View frame у снимков: без него спор о плотности беспредметен.
  • MaxEdgesPerNode физически не соблюдается на сужениях: этаж из пяти узлов, входящий в привал шириной один, даёт пять входящих рёбер при лимите четыре. Это следствие якоря-горловины, а не дефект связывания.

Владелец правды: tools/MapDump/Program.cs (дамп и чтение ассетов), docs/lab/src/sections/map-act.ts (показ), scripts/map_shots.py (снимки для разговора).