From b980566288cbf0ff1672ae22945af8e6a8ca2b39 Mon Sep 17 00:00:00 2001 From: Konstantin Dyachenko Date: Wed, 27 May 2026 03:26:56 +0700 Subject: [PATCH] [Add] Agent Task --- .gitignore | 1 + Agent/Agent.md | 32 ++++++++ Agent/TASK.md | 216 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 Agent/Agent.md create mode 100644 Agent/TASK.md diff --git a/.gitignore b/.gitignore index 8ccb1c6..d436863 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ !/ProjectSettings/ !/Packages/ !/docs/ +!/Agent/ !.gitignore !.gitattributes !LICENSE diff --git a/Agent/Agent.md b/Agent/Agent.md new file mode 100644 index 0000000..c12c384 --- /dev/null +++ b/Agent/Agent.md @@ -0,0 +1,32 @@ +# Правила для агента + +## Главный источник задачи + +Перед началом любой работы по проекту агент обязан прочитать файл: + +```text +Agent/TASK.md +``` + +Именно этот файл считается основным описанием задачи, требований и ограничений. + +## Порядок работы + +1. Сначала прочитать `Agent/TASK.md` полностью. +2. После чтения сверять все решения с требованиями из задачи. +3. Не реализовывать вариант B или любую функциональность, которой нет в `Agent/TASK.md`. +4. Не добавлять лишние архитектурные слои, если они не нужны для выполнения задачи. +5. Приоритет: минимальная корректная реализация, чистый жизненный цикл, понятный код. + +## Ограничения + +- Не использовать `FindObjectOfType`. +- Не использовать `Singleton.Instance`. +- Не хранить состояние в `static`. +- Не использовать `async void`, кроме Unity-колбэков. +- Все async-операции выполнять через UniTask и `CancellationToken`. +- Все подписки должны корректно освобождаться. + +## Цель + +Сделать только задачу `Boot Flow` из `Agent/TASK.md` и подготовить проект так, чтобы его можно было проверить по описанным требованиям. diff --git a/Agent/TASK.md b/Agent/TASK.md new file mode 100644 index 0000000..836204a --- /dev/null +++ b/Agent/TASK.md @@ -0,0 +1,216 @@ +# Задача: Unity / C# Middle + +## Кратко + +Нужно реализовать загрузочный поток приложения в Unity через собственную state machine. + +Проект создается с нуля. Базовые абстракции, сервисы, View/ViewModel и state machine нужно написать самостоятельно, потому что это часть оценки. + +Ориентировочное время выполнения: около 1,5 часов. Если ушло больше или меньше времени, это нормально, но нужно честно указать это в документации. + +## Технические требования + +- Unity 2022 LTS+. +- C#. +- Разрешено использовать VContainer, UniTask, UniRx/R3 или собственную реактивную реализацию. +- Опционально можно использовать Odin Inspector и DOTween. + +## Архитектурные требования + +### Reactive + +Можно использовать UniRx/R3 или собственный `ReactiveValue`. + +Если используется собственная реализация, ожидаемая сигнатура подписки: + +```csharp +IDisposable Subscribe(Action cb, bool invokeImmediately = true) +``` + +Требования: + +- каждая подписка должна корректно диспозиться; +- нельзя использовать голые `event Action` без отписки. + +### Async + +Все async-операции должны быть реализованы только через UniTask и `CancellationToken`. + +Запрещено использовать `async void`, кроме Unity-колбэков. + +### Dependency Injection + +Использовать VContainer. + +Все сервисы регистрируются как интерфейсы: + +```csharp +builder.Register(Lifetime.Singleton).As(); +``` + +Запрещено использовать: + +- `FindObjectOfType`; +- `Singleton.Instance`; +- `static`-хранилища состояния. + +### UI + +Нужно сделать базовую пару View/ViewModel: + +```csharp +public class UIView : MonoBehaviour +{ + public virtual void Initialize() { } + public virtual void Release() { } +} + +public class UIView : UIView where TVm : IUIViewModel +{ +} +``` + +Требования: + +- ViewModel должна быть обычным C#-классом, не `MonoBehaviour`; +- логика находится во ViewModel; +- View хранит только Unity-ссылки и биндинги. + +### Services + +Сервисы должны иметь асинхронный жизненный цикл: + +```csharp +UniTask InitializeAsync(CancellationToken ct) +UniTask ReleaseAsync(CancellationToken ct) +``` + +Требования: + +- сервисы оформляются как `Service : IService`; +- фоновые циклы стартуют в `InitializeAsync`; +- фоновые циклы останавливаются через `CancellationTokenSource.Cancel()` в `ReleaseAsync`. + +### Config + +Конфиги должны быть `ScriptableObject` с суффиксом `*Settings`. + +Регистрация в `LifetimeScope`: + +```csharp +[SerializeField] private SomeSettings _settings; + +protected override void Configure(IContainerBuilder builder) +{ + builder.RegisterInstance(_settings); +} +``` + +## Задача: Boot Flow + +Реализовать загрузочный поток приложения через собственную state machine из трех состояний. + +### 1. База state machine + +Нужно реализовать собственные абстракции: + +- `IState`; +- `IStatesController`; +- `StatesController`. + +В `StatesController` должен быть метод: + +```csharp +UniTask EnterStateAsync(TEnum code, CancellationToken ct) +``` + +Контракт перехода между состояниями: + +```csharp +await currentState.ExitAsync(ct); +await newState.EnterAsync(ct); +``` + +Требования: + +- `CancellationToken` пробрасывается через всю цепочку вызовов; +- `CancellationToken` должен реально отменять внутренние ожидания; +- повторные входы в состояния не должны ломать UI и подписки. + +### 2. Состояния + +Нужно реализовать три состояния. + +#### SplashState + +Поведение: + +- показывает лого; +- ждет 1 секунду через `UniTask.Delay(..., ct)`; +- переходит в следующее состояние. + +#### LoadState + +Поведение: + +- имитирует загрузку; +- выполняет 5 шагов по 200 мс; +- хранит `ReactiveValue Progress` со значением от `0` до `1`; +- обновляет `Progress` после каждого шага. + +#### MenuState + +Поведение: + +- показывает `MenuUIView`; +- содержит одну кнопку `Restart`; +- по клику на `Restart` возвращает приложение в `LoadState`. + +### 3. UI + +Нужно реализовать `LoadingUIView`. + +Требования: + +- `LoadingUIView` подписывается на `LoadState.Progress`; +- прогресс-бар обновляется через DOTween или ручной Lerp; +- при `ExitAsync` все подписки должны корректно очищаться; +- при повторном входе в `LoadState` не должно быть `NullReferenceException` и дублирующихся подписок. + +## Что сдать + +- GitHub-репозиторий или zip-архив без `Library/`, `Temp/`, `obj/`. +- `README.md` с инструкцией запуска. +- В `README.md` добавить 5-10 строк о том, что было бы доделано при наличии еще 2 часов. +- `SELF_NOTES.md` с описанием собственных решений. +- `AI_LOG.md` с описанием использования AI. Если AI не использовался, нужно написать почему. + +## SELF_NOTES.md + +В `SELF_NOTES.md` нужно своими словами описать: + +- какие идеи были рассмотрены и почему выбрана текущая реализация; +- какие места в коде были придуманы и написаны самостоятельно, без AI; +- что в коде понятно до последней строки; +- что осталось непонятным или воспринимается как магия; +- ответы на 2-3 ключевых вопроса вида: почему здесь сделано именно так. + +## AI_LOG.md + +В `AI_LOG.md` нужно описать: + +- какие промпты использовались; +- где AI ошибся; +- что было переписано руками; +- если AI не использовался, почему было принято такое решение. + +## Что не требуется + +Не нужно тратить время на: + +- красивый арт; +- сложные анимации; +- звук; +- мобильную сборку. + +Главное: архитектурные слои, стиль кода, корректная работа жизненного цикла и понимание собственных решений.