diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f67f8f1 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,79 @@ +# CLAUDE.md + +Инструкции для Claude Code по работе с этим репозиторием. + +## Проект + +G-WORLD — **2D-симулятор убежища с видом сбоку** (референс Fallout Shelter): +порода, вырытые шахты, комнаты на сетке, жители, время/погода/климат. + +Godot **4.7**, GDScript, рендер Forward+, целевая платформа — Windows. + +Игра двумерная. Если в задаче или в коде появляется 3D-нода (`Node3D`, +`CharacterBody3D`, `Camera3D`) — это ошибка, а не задумка: уточнить у +пользователя, прежде чем продолжать. + +## Где что лежит + +- `src/main/` — точка входа. +- `src/autoload/` — синглтоны. Новую автозагрузку регистрировать через настройки + проекта и описывать в `docs/ARCHITECTURE.md`. +- `src/core/` — утилиты и типы без знания о геймплее. +- `src/data/resources/` — схемы контента (наследники `Resource`), + `src/data/tables/` — сами `.tres`. +- `src/systems/` — симуляция (время, климат, погода, экономика). +- `src/world/` — сетка убежища, порода, комнаты, камера, фон. +- `src/entities/` — жители, предметы. +- `src/ui/` — `screens/`, `components/`, `theme/`. +- `src/debug/` — дев-консоль и оверлеи. +- `assets/` — только сырьё (арт, звук, шрифты, шейдеры), кода там нет. +- `tests/unit/` — логика без сцены, `tests/integration/` — на собранных сценах. + +Правила зависимостей между слоями — в `docs/ARCHITECTURE.md`. Перед тем как +класть новый файл, свериться с таблицей слоёв; не заводить новую папку верхнего +уровня, не обсудив это с пользователем. + +## Стиль кода + +- Файлы и папки — `snake_case`, ноды и `class_name` — `PascalCase`. +- Сцена и её скрипт лежат рядом и называются одинаково. +- Типизировать всё: параметры, возвраты (`-> void` тоже), поля. +- Приватное — с `_`. Константы — `SCREAMING_SNAKE_CASE`. +- Сигналы именовать прошедшим временем факта: `weather_changed`, `day_started`. +- `@onready var` вместо поиска нод по строкам в `_process`. +- Комментарии — по-русски, объясняют «почему», а не пересказывают код. + Комментировать только неочевидное. + +## Архитектурные правила, которые легко нарушить + +1. **Симуляция отделена от рендера.** Классы из `systems/` обязаны работать без + дерева сцены. Ноды в них не хранить. +2. **UI не меняет мир напрямую** — шлёт намерение, изменение делает система. +3. **Контент — данными.** Новая комната/предмет — это `.tres`, а не `if` в коде. +4. **`EventBus` — не свалка.** Туда только события для нескольких несвязанных + слоёв; локальную связь делать обычными сигналами. + +## Работа с редактором через MCP (`godot-ai`) + +Godot-редактор, скорее всего, открыт, и он владеет `project.godot`, `.tscn`, +`.tres` и `.import`. + +- **Не редактировать вручную** `project.godot` и `*.tscn`/`*.tres`: редактор + перезапишет изменения. Использовать MCP-инструменты (`scene_manage`, + `node_create`, `node_set_property`, `script_attach`, `autoload_manage`, + `project_manage`, `resource_manage`) — они работают через живой редактор. +- `.gd`-файлы править обычными Edit/Write — это нормально, редактор их + перечитает. +- Проверять результат: `project_run` + `logs_read` (ошибки парсера и рантайма), + `editor_screenshot` — чтобы увидеть сцену глазами. +- `addons/` — вендорный код плагина, его не трогаем. + +## Чего не делать + +- Не коммитить и не пушить без явной просьбы. +- Не добавлять C#: в `project.godot` есть секция `[dotnet]`, но проект на + GDScript. Не заводить `.cs`, не обсудив. +- Не класть тяжёлое сырьё в `assets/` — для него есть игнорируемые `kits/` и + `ai-input/`. +- Не удалять `.gitkeep` из ещё пустых папок — они держат структуру в git. +- Не менять `.gitattributes`/`.gitignore` мимоходом. diff --git a/README.md b/README.md new file mode 100644 index 0000000..ea7c1dc --- /dev/null +++ b/README.md @@ -0,0 +1,72 @@ +# G-WORLD + +2D-симулятор убежища с видом сбоку: игрок роет шахты в породе, строит комнаты +на сетке и следит за жителями. Визуальный референс — Fallout Shelter. + +| | | +| --- | --- | +| Движок | Godot **4.7**, рендер Forward+ | +| Язык | GDScript (типизированный) | +| Платформа | Windows (desktop), рендер-драйвер D3D12 | + +## Быстрый старт + +1. Установить Godot 4.7. +2. Открыть папку проекта из Project Manager (`project.godot` в корне). +3. `F5` — запуск. Главная сцена задаётся в *Project → Project Settings → Run*. + +Плагин `addons/godot_ai` (MCP-мост для агентов) включается в +*Project → Project Settings → Plugins*. + +## Структура репозитория + +``` +assets/ # Сырьё: то, что рисуется и звучит. Кода нет. + art/sprites/ # спрайты и атласы сущностей + art/tilesets/ # тайлсеты породы, стен, полов + art/ui/ # графика интерфейса: рамки, иконки, курсоры + audio/music/ # музыкальные треки + audio/sfx/ # короткие звуковые эффекты + fonts/ # шрифты + shaders/ # .gdshader, переиспользуемые между сценами + +src/ # Весь код и сцены. Сцена лежит рядом со своим скриптом. + main/ # точка входа: bootstrap-сцена, сборка автозагрузок + autoload/ # синглтоны (EventBus, SaveManager, GameState) + core/ # инфраструктура без знания о геймплее: утилиты, типы + data/resources/ # схемы данных — наследники Resource (RoomDef, ItemDef) + data/tables/ # экземпляры схем — .tres-«база данных» контента + systems/ # симуляция: время, климат, погода, экономика + world/ # убежище: сетка, порода, комнаты, камера, фон + entities/ # жители, предметы и прочие «живые» объекты + ui/screens/ # экраны и HUD целиком + ui/components/ # переиспользуемые контролы + ui/theme/ # Theme-ресурсы и стили + debug/ # дев-консоль, оверлеи, читы + +tests/unit/ # Тесты чистой логики (без дерева сцены) +tests/integration/ # Тесты на собранных сценах + +docs/ # Проектная документация + ARCHITECTURE.md # слои, правила зависимостей, поток данных + adr/ # ADR: почему приняли то или иное решение +``` + +Правила зависимостей между слоями описаны в [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). + +## Соглашения + +- **Файлы и папки** — `snake_case`: `game_clock.gd`, `vault_grid.tscn`. +- **Ноды в сцене и `class_name`** — `PascalCase`: `class_name GameClock`. +- **Скрипт и сцена одного объекта** лежат рядом и называются одинаково: + `src/world/vault_grid.tscn` + `src/world/vault_grid.gd`. +- **Типизация обязательна**: `var speed: float = 1.0`, `func tick(delta: float) -> void:`. +- **Приватное** — с подчёркиванием: `_rebuild_cache()`, `var _cells: Array`. +- **Константы** — `SCREAMING_SNAKE_CASE`, магические числа выносим в константы. +- Переводы строк — LF (см. `.gitattributes`), кодировка — UTF-8. + +## Работа с ассетами + +Тяжёлое сырьё (скачанные наборы, черновики генерации) в репозиторий не попадает: +папки `kits/` и `ai-input/` игнорируются. В `assets/` кладём только то, что +реально используется в сборке. diff --git a/addons/godot_ai/plugin.cfg b/addons/godot_ai/plugin.cfg index fe28f1a..a41f101 100644 --- a/addons/godot_ai/plugin.cfg +++ b/addons/godot_ai/plugin.cfg @@ -3,5 +3,5 @@ name="Godot AI" description="MCP server and AI tools for Godot" author="Godot AI" -version="3.1.4" +version="3.1.5" script="plugin.gd" diff --git a/assets/art/sprites/.gitkeep b/assets/art/sprites/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/assets/art/tilesets/.gitkeep b/assets/art/tilesets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/assets/art/ui/.gitkeep b/assets/art/ui/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/assets/audio/music/.gitkeep b/assets/audio/music/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/assets/audio/sfx/.gitkeep b/assets/audio/sfx/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/assets/fonts/.gitkeep b/assets/fonts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/assets/shaders/.gitkeep b/assets/shaders/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..51c53d5 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,78 @@ +# Архитектура + +Документ описывает, как устроен проект: какие есть слои, кто кому имеет право +звонить и как данные ходят по системе. Структура папок — прямое отражение этих +слоёв, см. [README](../README.md#структура-репозитория). + +## Слои и правила зависимостей + +Стрелка «→» читается как «может знать о». Всё, что не указано, — запрещено. + +``` +main ──→ autoload ──→ core + │ + ├───→ ui ────────→ core, data + ├───→ world ─────→ core, data, entities + ├───→ systems ───→ core, data + ├───→ entities ──→ core, data + └───→ debug ─────→ (всё, только для разработки) +``` + +| Слой | Зачем | Чего в нём быть не должно | +| --- | --- | --- | +| `core` | Утилиты, базовые типы, математика сетки | Ссылок на конкретные сцены и геймплей | +| `data` | Описания контента: схемы (`Resource`) и их экземпляры (`.tres`) | Логики поведения — только данные | +| `systems` | Симуляция мира: время, климат, погода, экономика | Прямого доступа к нодам сцены | +| `world` | Визуализация и взаимодействие с убежищем | Правил симуляции — они в `systems` | +| `entities` | Жители, предметы; их состояние и поведение | Знания о конкретном UI | +| `ui` | Экраны, HUD, контролы | Изменения состояния мира напрямую | +| `debug` | Дев-консоль, оверлеи, читы | Кода, от которого зависит релизная логика | + +Ключевое правило: **`ui` и `world` не меняют состояние мира сами** — они шлют +намерение (сигнал/вызов системы), а изменение делает `systems`. Обратно +`systems` не дёргает ноды: он сообщает об изменении сигналом. + +## Данные и рендер разделены + +Симуляция не должна зависеть от того, нарисовано ли что-то на экране. + +- **Данные** (`systems`, `data`) — чистая логика: считаются от `delta`, полностью + сериализуемы, тестируются без дерева сцены. +- **Рендер** (`world`, `ui`) — читает данные и отображает, подписавшись на сигналы. + +Практический критерий: любой класс из `systems` должен работать в юнит-тесте, +где никакой сцены нет. + +## Обмен сообщениями + +Три способа, в порядке предпочтения: + +1. **Сигнал вверх, вызов вниз.** Родитель знает о детях и вызывает их методы; + ребёнок о родителе не знает и только испускает сигналы. +2. **Ссылка на систему**, полученную из автозагрузки — когда нужен ответ здесь и + сейчас (запрос состояния, валидация постройки). +3. **Глобальная шина (`EventBus` в `autoload`)** — только для событий, которые + слушают несколько несвязанных слоёв (например, «время перескочило», + «погода сменилась»). Не превращать её в свалку: каждый сигнал документируем. + +## Контент — это ресурсы, а не код + +Новая комната, предмет или тип породы добавляются как `.tres` в `data/tables/` +по схеме из `data/resources/`, без правки кода. Если для добавления контента +приходится менять `.gd` — схема неполная, чинить надо схему. + +## Автозагрузки + +Автозагрузка — дорогая вещь: она живёт всю сессию и её видно отовсюду. Заводим +только для того, что действительно глобально и одно на игру. Каждая новая +автозагрузка регистрируется через *Project Settings → Autoload* и упоминается +здесь. + +Сейчас в проекте: `_mcp_game_helper` — служебная, часть плагина `godot_ai`, +к игровой логике отношения не имеет. + +## Решения + +Существенные развилки (выбор подхода к сохранению, к сетке, к тайм-степу) +фиксируем как ADR в [`adr/`](adr/) — короткая заметка «контекст → решение → +последствия». Это дешевле, чем через полгода восстанавливать мотивацию по коду. diff --git a/docs/adr/.gitkeep b/docs/adr/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000..361adf2 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,34 @@ +# ADR — записи об архитектурных решениях + +Короткие заметки о развилках, где выбор был неочевиден: как сохраняем игру, как +устроена сетка, фиксированный тик или переменный. Смысл — сохранить мотивацию +решения, чтобы через полгода не восстанавливать её по коду. + +Файл на решение, имя — `NNNN-краткая-суть.md`, нумерация сквозная и не +переиспользуется. Принятое решение не переписываем: если передумали — новый ADR +со статусом «заменяет NNNN». + +Шаблон: + +```markdown +# NNNN. Заголовок решения + +- Статус: предложено | принято | заменено (NNNN) +- Дата: ГГГГ-ММ-ДД + +## Контекст + +Что за задача и какие ограничения заставили выбирать. + +## Решение + +Что выбрали. Одним абзацем, в настоящем времени. + +## Последствия + +Что стало проще, что сложнее, за что теперь платим. + +## Альтернативы + +Что рассматривали и почему отвергли. +``` diff --git a/project.godot b/project.godot index a3458ca..a94de2f 100644 --- a/project.godot +++ b/project.godot @@ -14,6 +14,10 @@ config/name="g-world" config/features=PackedStringArray("4.7", "Forward Plus") config/icon="res://icon.svg" +[autoload] + +_mcp_game_helper="*res://addons/godot_ai/runtime/game_helper.gd" + [display] window/stretch/mode="canvas_items" @@ -23,6 +27,10 @@ window/stretch/aspect="expand" project/assembly_name="g-world" +[editor_plugins] + +enabled=PackedStringArray("res://addons/godot_ai/plugin.cfg") + [physics] 3d/physics_engine="Jolt Physics" diff --git a/src/autoload/.gitkeep b/src/autoload/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/core/.gitkeep b/src/core/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/data/resources/.gitkeep b/src/data/resources/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/data/tables/.gitkeep b/src/data/tables/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/debug/.gitkeep b/src/debug/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/entities/.gitkeep b/src/entities/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/main/.gitkeep b/src/main/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/systems/.gitkeep b/src/systems/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/ui/components/.gitkeep b/src/ui/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/ui/screens/.gitkeep b/src/ui/screens/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/ui/theme/.gitkeep b/src/ui/theme/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/world/.gitkeep b/src/world/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/integration/.gitkeep b/tests/integration/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/unit/.gitkeep b/tests/unit/.gitkeep new file mode 100644 index 0000000..e69de29