DragonECS-AutoInjections/README-RU.md
2023-06-22 15:40:35 +08:00

8.1 KiB
Raw Blame History

Version License

Auto Injections for DragonECS

Languages: Русский English(WIP)

Расширение призвано сократить объем кода, упростив инъекцию зависимостей, делая их автоматически.

ВАЖНО! Проект в стадии разработки. API может меняться.

Оглавление

Установка

Зависимости

Убедитесь что в проекте установлен фреймворк DragonECS.

  • Unity-модуль

Поддерживается установка в виде Unity-модуля в при помощи добавления git-URL в PackageManager или ручного добавления в Packages/manifest.json:

https://github.com/DCFApixels/DragonECS-AutoInjections.git
  • В виде исходников

Фреймворк так же может быть добавлен в проект в виде исходников.

Версионирование

В DragonECS применяется следующая семантика версионирования: Открыть

Интеграция

Добавьте вызов метода AutoInject() для Builder-а пайплайна. Пример:

_pipeline = EcsPipeline.New()
    .Inject(world)
    .Inject(_timeService)
    .Add(new TestSystem())
    .Add(new VelocitySystem())
    .Add(new ViewSystem())
    .AutoInject() // Готово, автоматические внедрения активированы
    .BuildAndInit();

Инъекция зависимостей

Атрибут [EcsInject] убирает необходимость использования интерфейса IEcsInject<T>, поля помеченные таким атрибутом автоматически подхватят зависимости внедренные в Pipeline. Пример:

[EcsInject] EcsDefaultWorld _world;

Так же можно делать внедрение через свойство или метод

EcsDefaultWorld _world;

//Обязательно наличие set блока.  
[EcsInject] EcsDefaultWorld World { set => _world = value; } 

//Количество аргументов должно быть равно 1.
[EcsInject] void InjectWorld(EcsDefaultWorld world) => _world = world;

Auto Builder аспектов

Так же AutoInjections упрощает построение аспектов. Для начала наследуйте аспект не от EcsAspect, а от EcsAspectAuto, а далее добавьте специальные атрибуты.

Атрибуты для инициализации полей с пулами:

  • [Inc] - кеширует пул и добавит тип компонента в включающее ограничение аспекта, аналог метода Include;
  • [Exc] - кеширует пул и добавит тип компонента в исключающее ограничение аспекта, аналог метода Exclude;
  • [Opt] - только кеширует пул, аналог метода Optional;

Атрибут для комбинирования аспектов:

  • [Combine(order)] - кеширует аспект и скомбинирует ограничения аспектов, аналог метода Combine, аргумент order задает порядок комбинирования, по умлочанию order = 0;

Дополнительные атрибуты только для задания ограничений аспекта. Их можно применить к самому аспекту, либо к любому полю внутри. Используйте атрибуты:

  • [IncImplicit(type)] - добавит в включающее ограничение указанный в конструкторе тип type, аналог метода Include;
  • [ExcImplicit(type)] - добавит в исключающее ограничение указанный в конструкторе тип type, аналог метода Exclude;

Пример кода

class VelocitySystemDI : IEcsRunProcess
{
    class Aspect : EcsAspectAuto
    {
        [ExcImplicit(typeof(FreezedTag))]
        [Inc] public EcsPool<Pose> poses;
        [Inc] public EcsPool<Velocity> velocities;
    }

    [EcsInject] EcsDefaultWorld _world;
    [EcsInject] TimeService _time;

    public void Run(EcsPipeline pipeline)
    {
        foreach (var e in _world.Where(out Aspect a))
        {
            s.poses.Write(e).position += a.velocities.Read(e).value * _time.DeltaTime;
        }
    }
}
Тот же код но без AutoInjections
class VelocitySystem : IEcsRunProcess, IEcsInject<EcsDefaultWorld>, IEcsInject<TimeService>
{
    class Aspect : EcsAspect
    {
        public EcsPool<Pose> poses;
        public EcsPool<Velocity> velocities;
        public Aspect(Builder b)
        {
            b.Exclude<FreezedTag>();
            poses = b.Include<Pose>();
            velocities = b.Include<Velocity>();
        }
    }

    EcsDefaultWorld _world;
    TimeService _time;

    public void Inject(EcsDefaultWorld obj) => _world = obj;
    public void Inject(TimeService obj) => _time = obj;

    public void Run(EcsPipeline pipeline)
    {
        foreach (var e in _world.Where(out Aspect a))
        {
            s.poses.Write(e).position += a.velocities.Read(e).value * _time.DeltaTime;
        }
    }
}

Не null инъекции

Чтобы поле помеченное [EcsInject] было проинициализированно даже в случае отстувия инъекции, в конструктор атрибута можно передать тип болванку. В примере ниже поле foo получит экземпляр класса Foo из инъекции или экземпляр FooDummy : Foo если инъекции небыло.

[EcsInject(typeof(FooDummy))] Foo foo;

Переданный тип должен иметь конструктор без параметров и быть либо того же типа что и тип поля, либо производного типа.

Расширение так же сообщит если по завершению предварительной инъекции, остались не проинициализированные поля с [EcsInject].