Перейти к основному содержимому
Модель игры

Эта страница ещё не переведена — показана английская версия.

Наследование и композиция

Модули опираются друг на друга, но ни один из них не наследуется от другого. Базового модуля, от которого можно унаследоваться, нет, как нет и иерархии для расширения: модули образуют граф. На этой странице — что здесь понимают под «наследованием» и какие шесть механизмов работают вместо него.

Что здесь значит наследование

one lista decorator, narrowing what is borrowedthe room owns who is inthe chat owns who hears under entry rulesunder delivery rules
Один список, дважды заимствованный через декоратор: комната решает, кто внутри, а чат — кто слышит

Под этим словом скрываются четыре разных механизма:

  • 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.