- О проекте
- Суть проекта и ключевые особенности
- Технологии и архитектура
- Локальный запуск
- Подготовка к production и Portainer
- Контрибьютинг и обратная связь
- Планы развития
- Лицензия
ByteFight — это образовательный проект, в котором пользователь программирует поведение игрового персонажа, запускает бой и наблюдает его развитие в реальном времени.
Проект выступает как полноценная площадка для практики разработки интерактивных систем и игровых механик:
- проектирование доменной модели и игрового цикла.
- разработка серверной и клиентской части.
- организация обмена событиями в реальном времени.
- проектирование и реализация Intellisense для работы с кодом.
- безопасная компиляция и выполнение пользовательского кода.
- проектирование и реализация игровой логики (правила боя, поведение юнитов, взаимодействие объектов).
- работа с визуальной частью: спрайты, анимации, игровые ассеты.
- построение клиентского рендера сцены (арена, персонажи, эффекты).
ByteFight — это программируемая игровая арена, в которой поведение персонажа полностью определяется кодом пользователя:
- Пользователь регистрируется и создает персонажа.
- Выбирает игровой режим и арену.
- Описывает поведение персонажа с помощью кода.
- Запускает игровую сессию.
- Наблюдает пошаговое развитие боя и его результат в реальном времени.
- Поддержка режимов:
Тренировка,PvE - Пошаговый игровой цикл
- Поведение игрока определяется пользовательским кодом
- Встроенный AI для противников на арене
- Запуск и завершение игровых сессий
- Фиксация результатов
- Логирование каждого хода
- Просмотр истории боев
- Подключение к сессии
- Поток игровых событий (тики)
- Событие завершения боя
- Построен на базе Monaco Editor
- Возможность работы с несколькими версиями кода для персонажа
- Стартовые шаблоны
- Проверка кода (diagnostics)
- Автодополнение (completions)
- Подсказки по типам и методам (hover)
- Подсказки по сигнатурам методов (signature help)
- Ограничение доступа к небезопасным API
- Изолированное выполнение пользовательского кода
- Ограничения на длительность выполнения и параллельный запуск нескольких боев
- Отрисовка арены и персонажей
- Анимации действий
- Журнал боя
- Отображение результата
- .NET 10
- ASP.NET Core (Minimal API)
- OpenAPI + Scalar
- Entity Framework Core
- PostgreSQL
- Разделение контекстов данных
- S3-совместимое хранилище (MinIO)
- JWT Bearer Authentication
- Refresh Tokens
- Permission-based authorization
- SignalR для передачи событий
- Roslyn для компиляции и анализа пользовательского кода
- Изолированный исполнитель пользовательского кода
- Aspire.ServiceDefaults
- HealthChecks
- OpenTelemetry
- Оркестрация сервисов через .NET Aspire
- Слоистая архитектура с разделением на
Domain,Application,Infrastructure,Web.Api,GameRuntime. - Подход близок к Clean Architecture:
- доменная модель изолирована и не зависит от инфраструктуры,
- внешние зависимости подключаются через слой
Infrastructure.
- В слое
Applicationиспользуется упрощённый CQRS-подход:- разделение команд и запросов (
ICommandHandler,IQueryHandler), - применение декораторов для валидации и логирования.
- разделение команд и запросов (
Web.Apiвыступает как тонкий слой доставки (HTTP) без бизнес-логики.- Выделен отдельный контур выполнения —
GameRuntime:- реализует игровой цикл,
- выполняет пользовательский код (изолированно от основного процесса),
- содержит API и IntelliSense для пользовательского кода
- React 19 + TypeScript
- Vite
- react-router-dom
- tanstack/react-query
- zustand
- microsoft/signalr
- monaco-editor + @monaco-editor/react
- pixi.js + @pixi/react
- Tailwind CSS 4 + Radix UI + shadcn/ui-паттерны.
- Структура построена по принципу Feature-Sliced (feature-oriented):
- код разделён по функциональным модулям, а не по техническим слоям.
- Разделение состояния:
- server-state — управление и кеширование данных через TanStack Query,
- client-state — локальное состояние интерфейса через Zustand.
- Используется event-driven подход:
- состояние игры обновляется через поток событий в реальном времени.
- Игровой рендер вынесен в отдельный слой:
- используется Pixi.js (WebGL с fallback на Canvas),
- реализована 2D-отрисовка сцены, спрайтов и анимаций.
- UI и игровой рендер разделены:
- интерфейс управляет состоянием,
- рендер отвечает за визуализацию.
src/
Domain/ # бизнес-сущности и правила
Application/ # команды/запросы
Infrastructure/ # EF Core, auth, MinIO, policy provider
GameRuntime/ # игровой цикл, AI, user code compilation/execution, realtime
Chronicles/ # витрина хроник, номинации, inbox/projection worker
Migrator/ # миграции, seed и первичная догонка outbox/inbox
Web.Api/ # HTTP endpoint'ы, DI, middleware
ClientApp/ # React SPA
Aspire.AppHost/ # оркестрация локального окружения
- Visual Studio с поддержкой .NET и Aspire
- Docker Desktop
- .NET SDK 10
- Node.js LTS 22+
- pnpm
- .NET SDK: https://dotnet.microsoft.com/download
- Visual Studio: https://visualstudio.microsoft.com/
- Docker Desktop: https://www.docker.com/products/docker-desktop/
- Node.js: https://nodejs.org/
- pnpm: https://pnpm.io/installation
- .NET Aspire: https://learn.microsoft.com/dotnet/aspire/
При первом запуске приложения, если база данных отсутствует, она будет автоматически создана. Все необходимые начальные данные (seed) также будут добавлены.
- Email: admin@bytefight.ru
- Пароль: admin123
После входа можно изменить учетные данные администратора через веб-интерфейс приложения.
git clone https://github.com/Ari100kratov/ByteFight.git
cd ByteFightcd src/ClientApp
pnpm install
cd ../..- Откройте
ByteFight.sln - Выберите стартовый проект
Aspire.AppHost - Запустите проект (
F5илиCtrl+F5)
dotnet run --project src/Aspire.AppHost/Aspire.AppHost.csprojAspire автоматически поднимет PostgreSQL, MinIO, Migrator, Web API и Chronicles.Worker. Runtime-сервисы стартуют после успешного завершения Migrator.
Перед запуском клиентского приложения необходимо подготовить файловое хранилище MinIO.
-
Скачайте ассеты по ссылке: https://disk.yandex.ru/d/-kMKjfv1s9MeTg
-
Откройте веб-интерфейс MinIO: http://localhost:9000
-
Войдите в систему, используя учетные данные по умолчанию:
- Логин: admin
- Пароль: password123
-
В MinIO необходимо:
- вручную создать бакеты (bucket = корневая директория);
- перенести каталоги и файлы из архива напрямую в соответствующие бакеты (MinIO поддерживает загрузку папок целиком).
📌 Как устроено хранилище:
- Бакеты — это верхний уровень (аналог корневых папок);
- Внутри бакетов размещаются папки и файлы;
- Структура должна полностью совпадать с той, что находится в архиве.
💡 Note: Aspire автоматически поднимает MinIO с дефолтными учетными данными, однако ассеты не загружаются автоматически. Если пропустить этот шаг или нарушить структуру файлов, клиентское приложение не сможет корректно отображать ресурсы (изображения, медиа и т.д.).
cd src/ClientApp
pnpm dev- Клиент:
http://localhost:5173 - API:
http://localhost:5000 - Хранилище MinIO:
http://localhost:9000 - Консоль MinIO:
http://localhost:9001
dotnet restore ByteFight.sln
dotnet build ByteFight.sln --no-restore
dotnet test tests\SharedKernel.UnitTests\SharedKernel.UnitTests.csproj --no-build
dotnet test tests\Domain.UnitTests\Domain.UnitTests.csproj --no-build
dotnet test tests\Application.UnitTests\Application.UnitTests.csproj --no-build
dotnet test tests\Infrastructure.UnitTests\Infrastructure.UnitTests.csproj --no-build
dotnet test tests\Web.Api.UnitTests\Web.Api.UnitTests.csproj --no-build
dotnet test tests\IntegrationContracts.UnitTests\IntegrationContracts.UnitTests.csproj --no-build
dotnet test tests\GameRuntime.Common.UnitTests\GameRuntime.Common.UnitTests.csproj --no-build
dotnet test tests\GameRuntime.UnitTests\GameRuntime.UnitTests.csproj --no-build
dotnet test tests\Chronicles.Domain.UnitTests\Chronicles.Domain.UnitTests.csproj --no-build
dotnet test tests\Chronicles.Application.UnitTests\Chronicles.Application.UnitTests.csproj --no-build
dotnet test tests\Chronicles.Infrastructure.UnitTests\Chronicles.Infrastructure.UnitTests.csproj --no-build
dotnet test tests\ArchitectureTests\ArchitectureTests.csproj --no-build
cd src/ClientApp
pnpm buildПодробная стратегия и PowerShell-цикл для запуска всех test projects описаны в docs/testing.md.
dotnet test ByteFight.sln тоже можно использовать, но он оценивает все проекты solution, включая Aspire.AppHost, и требует корректно установленный Aspire SDK/workload.
- Убедитесь, что Docker Desktop запущен
- Проверьте, что порты
5000,5173,5432,9000,9001свободны - Проверьте установленную версию .NET командой
dotnet --info - При ошибках зависимостей клиента удалите
node_modulesи выполнитеpnpm installповторно - При проблемах с запуском Aspire проверьте, что установлены необходимые компоненты Visual Studio и актуальная версия .NET SDK
- Определить публичные адреса: домен клиента, домен/API-путь, способ доступа к MinIO Console и Aspire Dashboard. Для текущего
docker-compose.ymlклиент работает как основной вход, а запросы к API идут через/api. - Подготовить секреты: скопировать
.env.exampleв.envи заменить всеchange-me-*значения. Минимально обязательныPOSTGRES_PASSWORD,MINIO_ROOT_USER,MINIO_ROOT_PASSWORD,JWT_SECRET,PGADMIN_DEFAULT_PASSWORD. - Решить вопрос TLS: в production ставьте обратный прокси перед Portainer stack (Traefik, Nginx Proxy Manager, Caddy или внешний балансировщик) и публикуйте наружу только нужные HTTP(S)-точки.
- Загрузить ассеты в MinIO: после первого запуска создать/проверить bucket
assetsи загрузить файлы из архива ассетов с сохранением структуры. - Проверить порядок старта:
Migratorдолжен завершиться успешно до запускаweb-apiиchronicles-worker. Он применяет EF migrations, выполняет seed, создает недостающие outbox-события для старых завершенных сессий и догоняет витрину Chronicles. - Ограничить доступ к диагностике: Aspire Dashboard показывает логи, traces, метрики и потенциально чувствительные данные. Не публикуйте его без авторизации/VPN/IP allowlist.
В корне репозитория добавлены файлы для Portainer/Docker Compose:
docker-compose.yml— stack из PostgreSQL, pgAdmin, MinIO,migrator, Web API,chronicles-worker, React/Nginx клиента и standalone Aspire Dashboard..env.example— шаблон переменных окружения для Portainer stack..dockerignore— исключаетbin,obj,node_modules,.envи локальные контейнерные данные из Docker build context.src/Web.Api/Dockerfile— production-сборка API на .NET 10 с публикациейuser-code-worker.src/Migrator/Dockerfile— one-shot host для миграций, seed и первичной догонки Chronicles.src/Chronicles/Chronicles.Worker/Dockerfile— production-сборка фонового обработчика Chronicles.src/ClientApp/Dockerfileиsrc/ClientApp/nginx.conf— production-сборка SPA и reverse proxy для/apiи/game-runtime-hub.
Архитектурное решение по порядку запуска описано в docs/adr/0001-production-hosting-topology.md.
cp .env.example .env
# Отредактируйте .env: задайте надежные POSTGRES_PASSWORD, MINIO_ROOT_PASSWORD и JWT_SECRET.
docker compose up -d --buildПри первом запуске migrator может работать дольше обычного: он применяет миграции и догоняет старые завершенные сессии для Chronicles. web-api и chronicles-worker начнут работу только после успешного завершения этого шага.
Адреса по умолчанию:
- Клиент:
http://localhost - API напрямую:
http://localhost:5000 - MinIO API:
http://localhost:9000 - MinIO Console:
http://localhost:9001 - Aspire Dashboard:
http://localhost:18888 - pgAdmin: внешний порт выбирает Docker, если
PGADMIN_PORTоставлен пустым; фактический порт смотрите вdocker compose ps pgadmin.
- Откройте Stacks → Add stack.
- Выберите репозиторий Git или вставьте содержимое
docker-compose.yml. - В секции Environment variables перенесите значения из
.env.exampleи замените секреты. - Нажмите Deploy the stack.
- Проверьте, что контейнер
migratorзавершился с кодом0. - После запуска проверьте health endpoint API:
http://<host>:5000/health. - Зайдите в MinIO Console и загрузите ассеты в bucket
assets. - При необходимости откройте опубликованный порт
pgadminи подключитесь к PostgreSQL hostpostgres, port5432.
В stack используется standalone dashboard image mcr.microsoft.com/dotnet/aspire-dashboard. Web API отправляет телеметрию через OTLP/gRPC:
OTEL_EXPORTER_OTLP_ENDPOINT=http://aspire-dashboard:18889
OTEL_EXPORTER_OTLP_PROTOCOL=grpc
Dashboard UI доступен на порту ASPIRE_DASHBOARD_PORT (по умолчанию 18888). По умолчанию ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=false, поэтому токен входа нужно взять из логов контейнера aspire-dashboard в Portainer. Для локальной разработки можно временно поставить ASPIRE_DASHBOARD_UNSECURED_ALLOW_ANONYMOUS=true, но для публичного production так делать нельзя.
Важно: standalone Aspire Dashboard хранит телеметрию в памяти и предназначен для разработки/краткосрочной диагностики. Для долгосрочного production-monitoring дополнительно планируйте постоянное хранилище логов/метрик (например, Grafana stack, Seq, Azure Monitor и т.п.).
web-apiиchronicles-workerне применяют миграции на старте. Все DDL-операции, seed и первичная догонка выполняются только черезmigrator.ConnectionStrings__ChroniclesDatabaseуказывает на отдельную БД Chronicles. Ее создает и мигрируетmigratorчерез EF Core; пользователь PostgreSQL должен иметь право создавать БД, если она еще не существует.REBUILD_CHRONICLES_PROJECTIONS=trueвключает полный ручной пересбор витрины Chronicles вmigrator. Для обычного деплоя оставляйтеfalse: необработанные сессии догоняются инкрементально.pgadminхранит пользовательские настройки в volumepgadmin-data; внешний порт можно зафиксировать черезPGADMIN_PORT, а если оставить пустым, Docker назначит случайный.- CORS настраивается через
Cors__AllowedOrigins__0,Cors__AllowedOrigins__1и т.д. При размещении клиента и API за одним Nginx (/api) CORS почти не используется, но настройка оставлена для отдельных доменов. src/ClientApp/.env.productionиспользуетVITE_API_URL=/apiиVITE_GAME_HUB_URL=/game-runtime-hub; Nginx в клиентском контейнере проксирует/api/*в Web API с удалением префикса/api, а SignalR идет через отдельный WebSocket location.- Значения
CLIENT_API_URLиCLIENT_GAME_HUB_URLпопадают в Vite на этапе сборки клиентского Docker image. Если меняете публичную схему маршрутизации, пересоберите контейнер клиента.
- Заменить все дефолтные пароли и
JWT_SECRETна секреты из password manager/Portainer secrets. - Настроить TLS и безопасные cookies/headers на внешнем reverse proxy.
- Закрыть прямые порты PostgreSQL и MinIO API снаружи, если они не нужны публично.
- Настроить backup volumes
postgres-data,minio-dataи при необходимостиpgadmin-data. - Настроить мониторинг контейнеров
migratorиchronicles-worker: ошибка migrator блокирует старт runtime-сервисов, а остановка worker замораживает обновление Зала славы. - Проверить политику выполнения пользовательского кода и лимиты ресурсов контейнера
web-api. - Прогнать
dotnet build ByteFight.sln --no-restore, тестовые проекты изdocs/testing.mdиpnpm buildперед публикацией образов.
Вклад в проект приветствуется.
Вы можете работать двумя способами:
- Сделайте fork репозитория
- Создайте отдельную ветку
- Внесите изменения
- Откройте Pull Request
Если у вас есть права на запись в репозиторий, можно:
- Создать ветку в основном репозитории
- Сделать изменения
- Открыть Pull Request
- Делайте небольшие и атомарные изменения
- Пишите понятные сообщения коммитов
- Описывайте в Pull Request:
- что сделано
- зачем это нужно
- как это проверить
- Issues: https://github.com/Ari100kratov/ByteFight/issues
- Telegram: https://t.me/whatislovesir
- Google-форма: https://docs.google.com/forms/d/e/1FAIpQLSd-krD2U1ENQKC0zog9loBzZQvXJMm3sfrzJ-w8HAjb2lGZOw/viewform?usp=dialog
- PvP режим
- Полноценный PvE режим (сюжет)
- Кооперативный PvE режим (совместное прохождение)
- Больше особенностей классов/специализаций
- Пассивные и активные способности, заклинания
- Больше интерактивности на арене
- Новые арены с различной механикой
- Более структурный код поведения
- Возможность работы с состоянием между ходами
- Несколько взаимодействующих файлов/модулей
- Дальнейшие улучшения IntelliSense
- Поддержка TypeScript/JavaScript для программирования
- Инфраструктурные улучшения и оптимизации
- Редизайн игрового процесса: эффекты, ассеты, анимации
- Расширение покрытия юнит и архитектурными тестами
Смотрите файл LICENSE.