[Add] Agent Task

This commit is contained in:
2026-05-27 03:26:56 +07:00
parent 9d28d1bc39
commit b980566288
3 changed files with 249 additions and 0 deletions
+1
View File
@@ -5,6 +5,7 @@
!/ProjectSettings/ !/ProjectSettings/
!/Packages/ !/Packages/
!/docs/ !/docs/
!/Agent/
!.gitignore !.gitignore
!.gitattributes !.gitattributes
!LICENSE !LICENSE
+32
View File
@@ -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` и подготовить проект так, чтобы его можно было проверить по описанным требованиям.
+216
View File
@@ -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<T>`.
Если используется собственная реализация, ожидаемая сигнатура подписки:
```csharp
IDisposable Subscribe(Action<T> cb, bool invokeImmediately = true)
```
Требования:
- каждая подписка должна корректно диспозиться;
- нельзя использовать голые `event Action` без отписки.
### Async
Все async-операции должны быть реализованы только через UniTask и `CancellationToken`.
Запрещено использовать `async void`, кроме Unity-колбэков.
### Dependency Injection
Использовать VContainer.
Все сервисы регистрируются как интерфейсы:
```csharp
builder.Register<Impl>(Lifetime.Singleton).As<IInterface>();
```
Запрещено использовать:
- `FindObjectOfType`;
- `Singleton.Instance`;
- `static`-хранилища состояния.
### UI
Нужно сделать базовую пару View/ViewModel:
```csharp
public class UIView : MonoBehaviour
{
public virtual void Initialize() { }
public virtual void Release() { }
}
public class UIView<TVm> : 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<TEnum>`;
- `StatesController<TEnum>`.
В `StatesController<TEnum>` должен быть метод:
```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<float> 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 не использовался, почему было принято такое решение.
## Что не требуется
Не нужно тратить время на:
- красивый арт;
- сложные анимации;
- звук;
- мобильную сборку.
Главное: архитектурные слои, стиль кода, корректная работа жизненного цикла и понимание собственных решений.