Следующая версия | Предыдущая версия |
ru:toolworks:docs:apparatus:architecture [2021/06/13 19:16] – создано + переведено jispar | ru:toolworks:docs:apparatus:architecture [2022/01/05 13:48] (текущий) – [Высокоуровневые детали] jispar |
---|
===== Machine ===== | ===== Machine ===== |
| |
Машина - это основная система Apparatus'а. Она глобально управляет всеми объектами и поэтому является глобальным сингл-тоном. В реальности это объект класса ''UObject'', но его продолжительность жизни определяется внутренним состоянием, а не стандартными механизмами сборщика мусора (garbage collector). Если машина имеет несколько механизмов, | Машина - это основная система Apparatus-а. Она глобально управляет всеми объектами и поэтому является глобальным сингл-тоном. В реальности это объект класса ''UObject'', но его продолжительность жизни определяется внутренним состоянием, а не стандартными механизмами сборщика мусора (garbage collector). Если машина имеет несколько механизмов, |
определённых внутри неё, или на сцене находятся несколько сущностей Subject-ов, то она сохраняется и остаётся доступной. Только если она перестаёт быть необходимой, а её поддержание становится бессмысленным, машина поставляется в очередь на удаление. | определённых внутри неё, или на сцене находятся несколько сущностей Subject-ов, то она сохраняется и остаётся доступной. Только если она перестаёт быть необходимой, а её поддержание становится бессмысленным, машина поставляется в очередь на удаление. |
| |
Внутри машины в частности и в самом Apparatus'е существуют два "мира". В этой статье мы и разберём два уровня обработки ECS-данных, - каждый со своими уникальными особенностями /* нехорошо: тавтология */ и оптимизациями. | Доступна [[appi>class_u_machine.html|документация API]] для класса ''UMachine'', которую вы смело можете использовать в качестве дополнительного источника. |
Конечно, доступна [[appi>class_u_machine.html|документация API]] для класса ''UMachine'', которую вы смело можете использовать в качестве дополнительного источника. | |
| ===== Механизмы ===== |
| |
| //[[ru:toolworks:docs:apparatus:mechanism|Механизмы]]// в Apparatus выполняют ту же роль, что и миры (World) в Unreal Engine. Они обеспечивают конкретное глобальное состояние, контекст выполнения, содержат в себе сущности (Subjects) и сущностные объекты (Subjectives) и механики (Mechanic), определённые над ними. |
| |
| Механизмы привязаны к своим World-аналогам. Если в вашем ''UWorld'' есть несколько механик или сущностных объектов, то механизм создастся автоматически. Конечно, вы можете отделить инстанс механизма, создать свой собственный, получить ссылку на него и манипулировать им по собственному желанию. |
| |
| Внутри машины или механизма в частности и в самом Apparatus-е в целом существуют два "мира". Два уровня обработки ECS-данных, - каждый со своими особенностями и оптимизациями. |
| |
===== Низкоуровневые трейты ===== | ===== Низкоуровневые трейты ===== |
| |
Начнём с низкого уровня. Подсистема //Trait//-ов в реальности была разработана позднее первого релиза, однако теперь она является центром фреймворка и предоставляет необходимую функциональность высокому уровню для полноценной работы плагина. | Начнём с низкого уровня. Подсистема //[[ru:toolworks:docs:apparatus:trait|Trait]]//-ов в реальности была разработана позднее первого релиза, однако теперь она является центром фреймворка и предоставляет необходимую функциональность высокому уровню для полноценной работы плагина. |
| |
Сам подход ECS разрабатывался с производительностью в высшем приоритете. Сборка и линейное хранение данных в памяти, что может быть проще? Хоть и не так просто это реализовать в силу динамически структурируемых сущностей и требований к утончённой "бухгалтерии", сама идея вполне корректна. Аппаратный уровень центрального процессора и оперативной памяти реально настроен на именно эту организацию данных. Сегодня CPU наделены кэшами громадной ёмкости, и вычислительная машина используется более эффективно, если обрабатываемые данные расположены друг за другом. | Сам подход ECS разрабатывался с производительностью в высшем приоритете. Сборка и линейное хранение данных в памяти, что может быть проще? Хоть и не так просто это реализовать в силу динамически структурируемых сущностей и требований к утончённой "бухгалтерии", сама идея вполне корректна. Аппаратный уровень центрального процессора и оперативной памяти реально настроен именно на эту организацию данных. Сегодня CPU наделены кэшами громадной ёмкости, и вычислительная машина используется более эффективно, если обрабатываемые данные расположены друг за другом. |
| |
Модель памяти в Unreal Engine не гарантирует такой уровень линейности; причудливо и зачастую недееспособно используются собственные аллокаторы. Вот почему мы создали подсистему трейтов. | Модель памяти в Unreal Engine не гарантирует такой уровень линейности; причудливо и зачастую недееспособно используются собственные аллокаторы. Вот почему мы создали подсистему трейтов. |
| |
Трейты основаны прежде всего на [[ue>ProgrammingAndScripting/Blueprints/UserGuide/Variables/Structs|структурах]]. | Трейты - это [[ue>ProgrammingAndScripting/Blueprints/UserGuide/Variables/Structs|структуры]]. |
Последние эксклюзивно управляются Apparatus'ом и хранятся в специальных буферах, называемых чанками (//Chunks//), так как и предполагалось - один за другим, последовательно, без пробелов. | Они эксклюзивно управляются Apparatus-ом и хранятся в специальных буферах, называемых чанками (//Chunks//), как и предполагалось - одна за другой, последовательно, без пробелов. |
| |
Трейты, в свою очередь, собираются в коллекции (иначе это вовсе не было бы реализацией ECS). Эти коллекции называются сущностями - //Subjects//. На сущности ссылаются специальные хэндлеры //Handles//, не указатели. Они абсолютно независимы от garbage collector'а (GC-independent) и утилизируются отдельно. | Трейты собираются в коллекции (иначе это вовсе не было бы реализацией ECS). Эти коллекции называются сущностями - //Subjects//. На сущности ссылаются специальные хэндлеры //Handles// (хэндлеры - это не указатели, способ их работы немного другой). Хэндлеры абсолютно независимы от garbage collector-а и утилизируются отдельно. |
| |
Такой дизайн увеличивает производительность механик обрабатывающих сущности, но на самом деле имеет некоторые ограничения по сравнению с высокоуровневыми деталями (//Details//). | Такой дизайн увеличивает производительность механик обрабатывающих сущности, но на самом деле имеет некоторые ограничения по сравнению с высокоуровневыми деталями (//Details//). |
===== Высокоуровневые детали ===== | ===== Высокоуровневые детали ===== |
| |
В отличие от трейтов детали - не структуры. Они относятся к инстанциям высших типов самого Unreal'а - к Объектам | В отличие от трейтов детали - не структуры. Они относятся к инстанциям высших типов самого Unreal-а - к Объектам |
(или к [[ue>API/Runtime/CoreUObject/UObject/UObject|UObject]]-ам, если быть более точным). Это делает их реально универсальными, если говорить об использовании уже существующей функциональности движка. Кроме того, они также поддерживают иерархическую фильтрацию и даже итерирование по мульти-деталям (что очень полезно, когда надо справится с несколькими деталями одного типа на одном Subject-е). | (или к [[ue>API/Runtime/CoreUObject/UObject/UObject|UObject]]-ам, если быть более точным). Это делает их реально универсальными, если говорить об использовании уже существующей функциональности Unreal Engine. Кроме того, они также поддерживают иерархическую фильтрацию и даже итерирование по мульти-деталям (что очень полезно, когда надо справится с несколькими деталями одного типа на одном Subject-е). |
| |
Детали всегда хранятся в соответствующих *Subjective*-вах - в специальных типов контейнеров, которые прямо ассоциируются с обыденными Actor'ами или пользовательскими виджетами (User Widget). Объекты типа "сущностный" (то есть Subjective-вы) не итерируются напрямую, но через специальную кэш-память, называемую ремнями (//Belt//). Ремни - отдельный тип данных, который используется сугубо в целях оптимизации, хранит только ссылки на оригинальные детали. Вы можете назначить собственные ремни вручную на объектах Subjective-а и они будут соответственно расширятся, если потребуется. | Детали всегда хранятся в соответствующих *Subjective*-вах - в специального типа контейнерах, которые прямо ассоциируются с обыденными Actor-ами или пользовательскими виджетами (User Widget). "Сущностные" объекты (то есть Subjective-вы) не итерируются напрямую, но через специальную кэш-память, называемую ремнями (//Belt//). Ремни - отдельный тип данных, который используется сугубо в целях оптимизации, хранит только ссылки на оригинальные детали. Вы можете назначить собственные ремни вручную на объектах Subjective-а. Ремни будут наращивать свои размеры по мере необходимости. |
| |
Пожалуйста, заметьте, что все Subjective-вы внутренне являются сущностями (Subjectives are actually Subjects). Они имеют все сущностные [[appi>lass_i_subjective.html#a0193ef8d2268c03c0aedc5d584383f71|хэндлеры]] в себе. Это, естественно, означает, что вы можете добавлять трейты на них. Вы можете взаимозаменяемо использовать оба мира вместе, если необходимо. Все зависит от вас. | Пожалуйста, заметьте, что все Subjective-вы внутренне являются сущностями (Subjectives are actually Subjects). Они имеют все сущностные [[appi>lass_i_subjective.html#a0193ef8d2268c03c0aedc5d584383f71|хэндлеры]] в себе. Это, естественно, означает, что вы можете добавлять трейты на них. Вы можете взаимозаменяемо использовать оба мира вместе, если необходимо. Все зависит от вас. |
===== Объединение в цепи ===== | ===== Объединение в цепи ===== |
| |
Одним из главных технических целей плагина - эффективно оперировать над большим количеством сущностей и объектами типа "сущностный" (operate over Subjects & Subjectives - введённые нами [[ru:toolworks:docs:apparatus:ecs-glossary|термины]] для ECS сущностей) по заданному фильтру. Таким образом был разработан специальный концепт объединения в цепи (//enchaining//). | Одним из главных технических целей плагина - эффективно оперировать над большим количеством сущностей и сущностными объектами (Subjects & Subjectives - введённые нами [[ru:toolworks:docs:apparatus:ecs-glossary|термины]] для ECS сущностей) по заданному фильтру. Таким образом был разработан специальный концепт объединения в цепи (//enchaining//). |
| |
Объединение в цепи - это процесс сбора всех в текущий момент доступных ремней и чанков, удовлетворяющих определённому фильтру, и сохранение их в специальный тип массива, который и называется цепью (//Chain//). Цепи управляются сингл-тоном машиной, а вы не создаёте их вручную, даже если используете плагин в C++. | Объединение в цепи - это процесс сбора всех в текущий момент доступных ремней (Belt-ов) и чанков (Chunk-ов), удовлетворяющих определённому фильтру, и сохранение их в массив специального типа, который и называется цепью (//Chain//). Цепи управляются соответствующим механизмом, и вы не создаёте их вручную, даже если используете плагин в C++. |
| |
Вместо этого, вам следует использовать глобальные (статические) [[appi>class_u_machine.html#a2e5ea120176a0485076c903cc98e6ea2|методы создания цепей]], передавая им на вход желаемый фильтр отбора. Вы можете объединять в цепи чанки или ремни. Как только они собраны в цепь и сама цепь начинала свой жизнь в коде программы, помещенные в неё ремни и чанки поддерживаются в заблокированном (//locked//) | Вместо этого, вам следует использовать [[appi>class_u_machine.html#a2e5ea120176a0485076c903cc98e6ea2|методы Механизмов для создания цепей]], передавая им на вход желаемый фильтр отбора. Вы можете объединять в цепи чанки или ремни (вместе они являются типами //Iterable// - итерируемые). Когда цепь начала своё существование, помещенные в неё ремни и чанки поддерживаются в заблокированном (//locked//) состоянии. |
состоянии. | |
| |
===== Блокировка ===== | ===== Блокировка ===== |
| |
В процессе итерации по цепям и их соответствующим чанкам и ремням мы должны гарантировать определённый уровень их | В процессе итерации по цепям и по их соответствующим чанкам и ремням мы должны гарантировать определённый уровень их |
неизменности. Мы же не хотим, чтобы произошла операция над одной и той же сущностью дважды, например, если она перемещалась между чанками вследствие структурной модификации внутри текущей итерации. Функции блокировки белтов и чанков были добавлены конкретно для этой цели. | неизменности. Мы не хотим, чтобы произошла операция над одной и той же сущностью дважды, например, если она перемещалась между чанками вследствие структурной модификации внутри текущей итерации. Функции блокировки ремней и чанков были добавлены именно для этой цели. |
| |
Когда чанк (Chunk) или ремень (Belt) поставляется в цепь, его внутренний счётчик блокировок инкрементируется, делая его "замороженным" по отнощению к оперирующей механике (которая и намерена работать с инстанциированной цепью). Вы можете спокойно использовать курсоры (//Cursor//) цепей, позволяя Apparatus'у регулировать все особенности блокировки и деблокировки за вас. | Когда чанк (Chunk) или ремень (Belt) поставляется в цепь, его внутренний счётчик блокировок инкрементируется, делая его "замороженным" по отношению к оперирующей механике (которая и намерена работать с текущей цепью). Вы можете спокойно использовать курсоры (//Cursor//) цепей, позволяя Apparatus-у регулировать все особенности блокировки и деблокировки за вас. |
| |
===== Фильтрация ===== | ===== Фильтрация ===== |
| |
Фильтрация (//Filtering//) - это естественная часть правильной ECS-реализации. Она позволяет вам выбирать определённые сущности и Subjective-вы для работы. Использование слова "выбор"("select") в данном контексте не случайно и может стать очень знакомым для программиста баз данных. С технической точки зрения это достаточно близкие термины. Вы определяете пункт "WHERE" с набором нужных вам условий соответствия. Последние могут быть как включающими (положительными), так и исключающими (отрицательными). | [[ru:toolworks:docs:apparatus:filter|Фильтрация]] (//Filtering//) - это естественная часть правильной ECS-реализации. Она позволяет вам выбирать определённые сущности и сущностные объекты для работы. Использование слова "выбор" ("select") в данном контексте не случайно и может стать очень знакомым для программиста баз данных. С технической точки зрения это достаточно близкие термины. Вы определяете пункт "WHERE" с набором нужных вам условий соответствия. Последние могут быть как включающими (положительными), так и исключающими (отрицательными). |
| |
Apparatus использует все сорта разнообразных оптимизирующих схем и кэшей, чтобы сделать процесс фильтрации настолько быстрым, насколько это возможно. Вы не должны волноваться по этому поводу. | Apparatus использует все сорта разнообразных оптимизирующих схем и кэшей, чтобы сделать процесс фильтрации настолько быстрым, насколько это возможно. Вы не должны волноваться по этому поводу. |
| |
[[appi>struct_f_filter.html|API документация]] для фильтров. | |
| |
===== Итерирование ===== | ===== Итерирование ===== |
| |
Пусть имеется набор инициализированных и настроенных сущностей. Белты и чанки объединены в цепи, и теперь вы готовы итерироваться по ним, чтобы произвести необходимую логику игры или приложения. Это можно сделать при помощи очень распространённого концепта итераторов (//Iterators//) и курсоров (//Cursors//). | Пусть имеется набор инициализированных и настроенных сущностей. Ремни и чанки объединены в цепи, и теперь вы готовы //[[ru:toolworks:docs:apparatus:iterating|итерироваться]]// по ним, чтобы произвести необходимую логику игры или приложения. Это можно сделать при помощи очень распространённого концепта итераторов (//Iterators//) и курсоров (//Cursors//). |
| |
Оба типа - ремни и чанки - имеют собственные итераторы, но вы вряд ли будете использовать их напрямую. Напротив, вы скорее всегда будете использовать курсоры цепей (Chain Cursors). Они, по сути, те же итераторы, с хорошо подобранным названием, которое помогает устранить возможную двусмысленность. Сейчас вам следует только использовать неявные курсоры по умолчанию (default implicit Cursor), поскольку многопоточность является планируемой особенностью и вам редко может понадобится итерироваться по одному белту или чанку несколькими разными курсорами одновременно. | Оба типа - ремни и чанки - имеют собственные итераторы, но вы вряд ли будете использовать их напрямую. Напротив, вы скорее всегда будете использовать курсоры цепей (Chain Cursors). Они, по сути, те же итераторы, с хорошо подобранным названием, которое помогает устранить возможную двусмысленность. /* Сейчас вам следует только использовать неявные курсоры по умолчанию (default implicit Cursor), поскольку многопоточность является планируемой особенностью и вам редко может понадобится итерироваться по одному белту или чанку несколькими разными курсорами одновременно. - TODO: обновить в соответствии с текущей реализацией */ |
| |
Документация для [[appi>struct_f_chunk_chain.html#a81fe6a135e15ca00736cdd6ef527c3f3|простых]] и | Документация для методов [[appi>struct_f_chunk_chain.html#a81fe6a135e15ca00736cdd6ef527c3f3|Begin]] и |
[[appi>struct_f_belt_chain.html#a8552c76ac87bcafb0a8077bbea5ade90|продвинутых]] методов приведена соответственно. | [[appi>struct_f_belt_chain.html#a8552c76ac87bcafb0a8077bbea5ade90|Advance]] приведена соответственно. |
| |
===== Послесловие ===== | ===== Послесловие ===== |
Этот обзор, конечно, является просто обзором на то, что Apparatus представляет собой в реальности, но мы надеемся, что он поможет вам освоить основные идеи предлагаемого набора инструментов. Мы продолжим вдаваться в подробности особенностей реализации в некоторых отдельных статьях этой турбопедии. Следите за обновлениями. | Этот обзор, конечно, является просто обзором на то, что Apparatus представляет собой в реальности, но мы надеемся, что он поможет вам освоить основные идеи предлагаемого набора инструментов. Мы продолжим вдаваться в подробности особенностей реализации в некоторых отдельных статьях этой турбопедии. Следите за обновлениями. |