Эта страница ещё не переведена — показана английская версия.
Наследование и композиция
Модули опираются друг на друга, но ни один из н их не наследуется от другого. Базового модуля, от которого можно унаследоваться, нет, как нет и иерархии для расширения: модули образуют граф. На этой странице — что здесь понимают под «наследованием» и какие шесть механизмов работают вместо него.
Что здесь значит наследование
Под этим словом скрываются четыре разных механизма:
- RPC сущности — часть самой сущности. Они есть только у сущности (entity): ни у родителя, ни в общем реестре их нет. См. Entity.
- Пресет — это именованный набор, а не базовый класс. Характеристики, способности, снаряды, генераторы добычи и объекты мира — это пресеты
entity, то есть наборы аспектов, которые применяет представление сущности (entity view). Поэтому они описаны на одной странице, Entity Presets, а не как пять модулей. Пресет добавляет вашему типу аспекты, но ни подо что этот тип не ставит. - Чтобы переопределить шаг платформы, достаточно поставить атрибут на свою замену. Наследоваться от нашего шага не нужно: вы объявляете свой, версии выбираются по условию, а шаг платформы по умолчанию остаётся запасным вариантом. См. Extensibility.
- Один модуль заимствуе т другой через декоратор, который сужает или дополняет заимствованный интерфейс, а реализацию за ним можно подменить. Разобранный пример — чат внутри комнаты (room) — есть на странице Groups.
Иерархии классов для модулей нет: дерево допускает только ветки, а реальные возможности игры их пересекают. Модуль Matchmaking резервирует места (seat) в комнатах. Выпавшие предметы размещаются через карту (map). Таблицу лидеров (leaderboard) пополняет хук, который срабатывает при закрытии комнаты.
Шесть механизмов
Каждый из них объявляется атрибутом рядом с тем, что он связывает, — по тому же декларативному правилу, что и всё остальное в SDK.
Точки монтирования, как в файловой системе. Модуль монтируется в корень, объединяя несколько интерфейсов в один, или в пространство имён. Если второй модуль претендует на уже занятую точку, его отклоняют при монтировании, а не при первом вызове. Как это устроено — на странице Под капотом.
Лексическая видимость. Видимость имён следует вложенности: глобальное объявление видно внутри модуля, а локальное никогда не просачивается наверх. Что модуль порождает — отдельный вопрос, и ответ на него объявляется в собственном контракте модуля: модуль знает только те события, которые объявил сам или которые у него зарегистрировали.
Инкапсуляция как контракт. Модуль никогда не знает, кто и зачем его вызывает. То, что он открывает наружу, и то, что он порождает, — это весь его публичный контракт. Из всего, что касается вызывающего, на поведение модуля влияют только выданные ему права.
Переиспользование через декоратор и инверсия управления. Модуль обращается к другому через декоратор, а не лезет в его внутренности, и реализацию за интерфейсом можно подменить. Именно этот механизм позволяет заменить любой наш модуль своим так, что зависящие от него модули ничего не заметят.
Объявления расширяют API. Объявите событие на группе — и появится group.Send.ChatMessage(…) со своим контрактом. Объявите данные members — появится типизированный геттер. Объявление служит входом для кодогенерации, поэтому версионируют именно объявление, а не сгенерированный код.
Три оси адресации из одного модуля. Все экземпляры, один экземпляр и администратор одного экземпляра — это три разных API, а не один API с флагом. Подробно — на странице Groups.
Неявные аргументы
Внутри сущности её саму передавать не нужно. Получатель, вызывающий и окружающий контекст подставляются автоматически: все три уже определены тем, где сделан вызов и кто его сделал. Как это работает, описано на странице RPC.