ExtensibleEnumSystem (Unity)
Namespace: Vortex.Unity.ExtensibleEnumSystem.*
Сборка: ru.vortex.unity.extenums (Editor-only логика под #if UNITY_EDITOR в том же asmdef)
Назначение
Тонкая Unity-обвязка над абстракцией ExtensibleEnum (Layer 1):
- Inspector-атрибут
[ExtEnumKey(typeof(MoveState))]с дропдауном допустимых ключей. - Мост
ExtensibleEnumValueSwitcherHandlerдля связкиExtEnumData<T>→UIStateSwitcherчерез рефлексию.
Eager-инициализация реестра ([RuntimeInitializeOnLoadMethod] + [InitializeOnLoadMethod]) уже выполняется в L1 — отдельный Unity-инициализатор не нужен.
Вне ответственности:
- Кодогенерация, парные SO-ассеты, валидаторы — отсутствуют намеренно. Конкретные
ExtensibleEnum-наследники пишутся руками (см. README Layer 1). - UI-интеграция (overload
UIStateSwitcher.Set(ExtensibleEnum)и расширениеStateSwitcherAttribute) — на стороне пакетаVortex.Unity.UI.StateSwitcher.
Зависимости
| Зависимость | Назначение |
|---|---|
Vortex.Core.ExtensibleEnumSystem |
ExtensibleEnum, ExtEnumData<T> |
Vortex.Core.Extensions.ReactiveValues |
IReactiveData для подписки в ExtensibleEnumValueSwitcherHandler |
Vortex.Unity.UI.StateSwitcher |
UIStateSwitcher для моста |
Архитектура
Attributes/
ExtEnumKeyAttribute — [ExtEnumKey(typeof(TEnum))] для string-полей в Inspector;
хранит ExtEnumType, валидирует наследование от ExtensibleEnum
Handlers/
ExtensibleEnumValueSwitcherHandler — MonoBehaviour: source + property name + UIStateSwitcher;
подписка на IReactiveData.OnUpdateData,
switcher.Set(extEnumData.Index) при изменении
Editor/ (под #if UNITY_EDITOR, в том же runtime asmdef)
ExtensibleEnumKeyAttributeDrawer — popup с ключами для [ExtEnumKey].
Реестр ExtensibleEnum уже наполнен eager-инициализацией
в L1 — drawer просто читает GetAll(Type).
[ExtEnumKey] Inspector-атрибут
public class CharacterPreset : ScriptableObject
{
[ExtEnumKey(typeof(MoveState))]
[SerializeField] private string defaultMoveState;
public MoveState GetDefault() => ExtensibleEnum.GetByKey<MoveState>(defaultMoveState);
}
Drawer показывает popup с ключами, считанными из ExtensibleEnum.GetAll(typeof(MoveState)). Реестр уже наполнен L1-инициализатором при загрузке домена / старте сцены — никаких отдельных триггеров на стороне drawer'а не требуется.
Конструктор атрибута проверяет, что переданный Type наследует ExtensibleEnum; в противном случае — ArgumentException.
ExtensibleEnumValueSwitcherHandler — мост
Late-binding мост ExtEnumData<T> → UIStateSwitcher. Конфигурируется в инспекторе:
- source — MonoBehaviour-источник, на котором есть свойство типа
ExtEnumData<TEnum>. - property — имя этого свойства.
- switcher — целевой
UIStateSwitcher.
Жизненный цикл:
Awake— резолвитPropertyInfoдляproperty, читает значение в_extEnumData, кешируетIndex-property через рефлексию, подписывается наIReactiveData.OnUpdateData. На любую ошибку —Debug.LogError+enabled = false.Start— первыйOnDataChanged()(после всехAwakeсцены потребитель уже подписался на switcher).OnDataChanged— читаетIndexчерез рефлексию, приindex >= 0дёргаетswitcher.Set(index).OnDestroy— отписка + зануление кеша.
Связь между ключом и слотом switcher'а — через Index значения: handler читает ExtEnumData.Index и при index >= 0 дёргает switcher.Set(index). Слоты switcher'а должны быть в том же порядке, что и значения в типе.
Editor-helper GetExtEnumDataProperties() под #if UNITY_EDITOR собирает список свойств source, тип которых — наследник ExtEnumData<>. Готов для подключения к будущему drawer'у с дропдауном (сейчас поле property — обычный string-input).
Граничные случаи
| Ситуация | Поведение |
|---|---|
[ExtEnumKey] для не-ExtensibleEnum типа |
ArgumentException в конструкторе атрибута |
[ExtEnumKey] на не-string поле |
Drawer пишет "[ExtEnumKey] only on string fields" |
[ExtEnumKey] для типа без значений |
Popup пустой, рисуется warning-helpbox |
ExtensibleEnumValueSwitcherHandler без source / property |
Awake логирует ошибку, enabled = false |
property у source не найден / возвращает null / не ExtEnumData<> |
Awake логирует ошибку, enabled = false |
ExtEnumData.Index == -1 (значение не зарегистрировано) |
Switcher не переключается, no-op |
Контракт публичного API
namespace Vortex.Unity.ExtensibleEnumSystem.Attributes
{
public class ExtEnumKeyAttribute : PropertyAttribute
{
public Type ExtEnumType { get; }
public ExtEnumKeyAttribute(Type extEnumType);
}
}
namespace Vortex.Unity.ExtensibleEnumSystem.Handlers
{
public class ExtensibleEnumValueSwitcherHandler : MonoBehaviour { }
}
Editor-классы (ExtensibleEnumKeyAttributeDrawer) — internal, под #if UNITY_EDITOR в том же asmdef.