# Город сверху — генератор OSM и клиент-серверная симуляция Добавлен серверный режим по [плану](docs/PLAN.md): подготовленные города, комнаты до 30 наблюдателей, жители по расписанию, общий календарь и голосования, сохранения и очередь генерации. Браузерный генератор ниже остаётся режимом отладки. ## Эксплуатация Для запуска через Docker Compose см. [deploy/README.md](deploy/README.md). Настройки сервера описаны в [server/README.md](server/README.md). Интерфейс оператора: `/?admin`. ## Сетевая игра Нужны Node.js 22+ и Rust stable (на Windows — установленный MSVC linker). Запускать команды из корня репозитория: ```bash npm ci npm run demo # готовый город из локального образца OSM, без запросов к Overpass npm run build npm run server:dev # http://localhost:3000/?play ``` В списке выберите Бальцерс, задайте ник и создайте комнату. Другие игроки входят в ту же комнату из списка. Кнопка «Создать город на сервере» открывает выбор области и запускает отдельную задачу генерации с прогрессом. Можно экспортировать уже готовый мир и открыть только статику без симуляции: ```bash npm run export-city -- world.json public/cities/my-city # http://localhost:3000/?city=/cities/my-city/manifest.json ``` Экспорты не перезаписываются: новая версия города получает новый каталог. Настройки, API, ограничения LOD и описание сохранений находятся в [server/README.md](server/README.md). Проверки: `npm run typecheck`, `npm test`, `npm run server:test`, `npm run server:load`. Изменение протокола: `npm run proto:generate`. ## Браузерный генератор для отладки Выделяете на карте небольшой город или район → по данным OSM строится подробная карта с видом строго сверху: дороги реальной ширины с тротуарами и разметкой, парковки с машинами, деревья, и **у каждого здания — этажи, комнаты, двери, окна, лестницы и мебель**, нарисованные простыми геометрическими фигурами, как на плане квартиры. В отладочном режиме всё работает в браузере: данные берутся из Overpass API, генерация идёт в Web Worker'ах, готовый мир сохраняется в IndexedDB. Машины появляются только на парковках и в гаражах; вдоль улиц они не генерируются. ## Запуск Нужен Node.js 18+. ```bash npm install npm run dev # http://localhost:5173/ (пересборка на лету) npm run build # сборка в dist/ — можно положить на любой статический хостинг npm run typecheck ``` Для автоматических проверок сетевого клиента нужен Node.js 22+: `npm test`. Тесты проверяют таймауты, переключение серверов и отмену без обращения к сети. Данные сначала запрашиваются у `maps.mail.ru`, затем у `overpass-api.de` и `overpass.private.coffee`. На каждый запрос отводится 45 секунд, включая загрузку ответа; после ошибки или таймаута используется следующий сервер. Лимит обработки запроса на стороне Overpass — 30 секунд. Кнопка «Отмена» прерывает запрос и ожидание перед повтором. Без интернета можно проверить на образце: «Другие способы» → «Сгенерировать из выгрузки Overpass» → `samples/balzers-2013.json` (Бальцерс, Лихтенштейн, данные OSM 2013 года). Генерация из файла без браузера (для отладки генератора): ```bash npm run cli -- samples/balzers-2013.json 47.058 9.492 47.074 9.518 world.json ``` ## Управление - перетаскивание — сдвиг, колесо / щипок — масштаб, двойной клик — приблизить; - справа — этаж для всей карты (⌂ — крыши), `PgUp`/`PgDn` или `[` `]`; - клик по зданию — карточка: вид, этажность (из OSM или оценка), квартиры, спальные места, свой переключатель этажей только для этого здания; - «Экспорт мира» в отладочном режиме — весь мир одним файлом `.json.gz`; `export-city` преобразует его в серверный тайловый формат. ## Как устроена генерация ``` Overpass JSON ─► city.ts ──────────────► зоны, дороги, контуры зданий, деревья, парковки │ classify.ts вид здания (по тегам, POI внутри, landuse, площади) и этажность ▼ interior.ts (в воркерах) ─► этажи: сетка 0.5 м в осях здания │ схема: секции с подъездами | коридор | простая раскладка │ деление на комнаты по программе (м²), несколько попыток с оценкой │ двери = остовное дерево по графу смежности, санузлы и спальни — тупики │ вход с фасада к дороге, окна с шагом по типу здания ▼ furnish.ts + catalog.ts ──► мебель по правилам для каждого типа комнаты ▼ finalize.ts ──────────────► общие модели предметов, округление до 1 см ``` - **Сид** здания = OSM-id ⊕ сид мира — один и тот же город всегда генерируется одинаково. - Многоквартирные дома — **секционные**: подъезд с лестницей (и лифтом от 5 этажей), площадка, 1–4 квартиры вокруг неё; на первом этаже — проход к входу, у домов с магазинами вместо квартир магазины со своими входами с улицы. - Офисы, школы, больницы, гостиницы — **коридорная** схема. - Дома, магазины, кафе, цеха, склады, храмы, гаражи — **простая** раскладка (у гаражных рядов — отдельные боксы с воротами). ## Модель данных мира (`src/types.ts`) Статические данные уже используются сервером; для дальнейшего игрового слоя предусмотрены: | Что | Зачем потом | |---|---| | `Door.rooms = [комната, комната \| 'outside']` | рёбра графа навигации внутри здания | | `Stairs` (одно место на всех этажах, `up`/`down`), лифты | переходы между этажами | | `Unit` — квартира / магазин / офис с `roomIds` и `beds` | домохозяйства и рабочие места для жителей | | `Prop.blocksMove`, `Prop.blocksSight`, `tags` (`sleep:2`, `sit:4`, `work`, `cook`, `storage`…) | коллизии, линия обзора, что агент может сделать с предметом | | `Wall` с разрывами под двери и окна, `Window` | коллизии и видимость (окна прозрачны для взгляда) | | `Road` с шириной, тротуарами, `oneway`, слоями | граф улиц для перемещения по городу | | все объекты с `id` | хранение состояния: открытая дверь, взятый предмет | Координаты — метры в локальной проекции вокруг центра области (x — восток, y — юг). ## Ограничения MVP - Область до 25 км²; предупреждение о времени генерации — свыше 10 км². Скорость и расход памяти зависят от плотности застройки и этажности. Публичные серверы Overpass рассчитаны на умеренную нагрузку; для публичной игры понадобится своё зеркало или заранее нарезанные данные (например, экстракт Geofabrik → статические файлы). - Подвалы, мансарды, балконы, береговая линия морей пока не генерируются. - Нестандартные контуры (сильно изломанные) дают менее аккуратные планировки. ## Данные и лицензии Данные карты © участники OpenStreetMap, лицензия ODbL. Если вы распространяете сгенерированные миры, укажите «© OpenStreetMap contributors». Тайлы на экране выбора области — стандартные тайлы OSM по их [правилам использования](https://operations.osmfoundation.org/policies/tiles/); поиск — Nominatim (не чаще раза в секунду). Идеи частично подсказаны проектом [KnoxMap](https://github.com/spytheeuclidean-a11y/knoxmap); код написан с нуля.