{"id":13589698,"url":"https://github.com/Megafunk/MassSample","last_synced_at":"2025-04-08T09:33:55.151Z","repository":{"id":37694692,"uuid":"470057126","full_name":"Megafunk/MassSample","owner":"Megafunk","description":"My understanding of Unreal Engine 5's experimental ECS plugin with a small sample project.","archived":false,"fork":false,"pushed_at":"2024-11-14T04:02:27.000Z","size":149135,"stargazers_count":834,"open_issues_count":36,"forks_count":131,"subscribers_count":30,"default_branch":"main","last_synced_at":"2025-04-06T20:53:39.000Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Megafunk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-03-15T07:53:25.000Z","updated_at":"2025-04-03T21:01:39.000Z","dependencies_parsed_at":"2024-06-28T08:40:24.473Z","dependency_job_id":"0ad5c525-c09a-413f-8e3e-51a5995e86d6","html_url":"https://github.com/Megafunk/MassSample","commit_stats":null,"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Megafunk%2FMassSample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Megafunk%2FMassSample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Megafunk%2FMassSample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Megafunk%2FMassSample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Megafunk","download_url":"https://codeload.github.com/Megafunk/MassSample/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247814416,"owners_count":21000572,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T16:00:33.194Z","updated_at":"2025-04-08T09:33:55.142Z","avatar_url":"https://github.com/Megafunk.png","language":"C++","funding_links":[],"categories":["Documents","Game Development","Stale"],"sub_categories":["Unreal Engine: Resources","C / C++ \u0026 Systems"],"readme":"# Community Mass Sample\n### **Note:** This project requires `Git LFS` for it to work properly, `zip` downloads **won't work**.\n\n#### **Authors:**\n- Karl Mavko - [@Megafunk](https://github.com/Megafunk)\n- Alvaro Jover - [@vorixo](https://github.com/vorixo)\n\nOur **somewhat WIP** understanding of Unreal Engine 5's experimental Entity Component System (ECS) plugin with a small sample project. We are **not** affiliated with Epic Games and this system is actively being changed often so this information might not be totally accurate.\n\nWe are totally open to contributions, If something is wrong or you think it could be improved, feel free to [open an issue](https://github.com/Megafunk/MassSample/issues) or submit a [pull request](https://github.com/Megafunk/MassSample/pulls).\n\nCurrently built for the Unreal Engine 5 latest version binary from the Epic Games launcher.\nThis documentation will be updated often!\n\n#### **Requirements:**\n- Unreal Engine 5.5 (latest version as of writing) from the [Epic Games launcher](https://www.unrealengine.com/en-US/download)\n- `Git` version control:\n  - [Windows](https://gitforwindows.org/)\n  - [Linux/Unix \u0026 macOS](https://git-scm.com/downloads)\n- [Git Large File Storage](https://git-lfs.github.com/)\n\n#### **Download instructions (Windows):**\nAfter installing the requirements from above, follow these steps:\n\n1. Right-Click where you wish to hold your project, then press `Git Bash Here`.\n\n2. Within the terminal, clone the project:\n\t```bash\n\tgit clone https://github.com/Megafunk/MassSample.git\n\t```\n\n3. Pull LFS:\n\t```bash\n\tgit lfs pull\n\t```\n4. Once LFS finishes, close the terminal.\n\n\n\n\u003c!--- Introduce here table of contents --\u003e\n\u003ca name=\"tocs\"\u003e\u003c/a\u003e\n## Table of Contents\n\u003e 1. [Mass](#mass)  \n\u003e 2. [Entity Component System](#ecs)  \n\u003e 3. [Sample Project](#sample)  \n\u003e 4. [Mass Concepts](#massconcepts)  \n\u003e 4.1 [Entities](#mass-entities)   \n\u003e 4.2 [Fragments](#mass-fragments)  \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.2.1 [Shared Fragments](#mass-fragments-sf)  \n\u003e 4.3 [Tags](#mass-tags)  \n\u003e 4.4 [Subsystems](#mass-subsystems)  \n\u003e 4.5 [The archetype model](#mass-arch-mod)   \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.5.1 [Tags in the archetype model](#mass-arch-mod-tags)  \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.5.2 [Fragments in the archetype model](#mass-arch-mod-fragments)  \n\u003e 4.6 [Processors](#mass-processors)  \n\u003e 4.7 [Queries](#mass-queries)  \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.7.1 [Access requirements](#mass-queries-ar)  \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.7.2 [Presence requirements](#mass-queries-pr)  \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.7.3 [Iterating Queries](#mass-queries-iq)  \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.7.3 [Mutating entities with Defer()](#mass-queries-mq)  \n\u003e 4.8 [Traits](#mass-traits)  \n\u003e 4.9 [Observers](#mass-o)  \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.9.1 [Observers limitations](#mass-o-n)                \n\u003e \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;4.9.2 [Observing multiple Fragment/Tags](#mass-o-mft)       \n\u003e 4.10 [Multithreading](#mass-mt)  \n\u003e 5. [Common Mass operations](#mass-cm)   \n\u003e 5.1 [Spawning entities](#mass-cm-spae)  \n\u003e 5.2 [Destroying entities](#mass-cm-dsae)  \n\u003e 5.3 [Operating Entities](#mass-cm-opee)  \n\u003e 6. [Mass Plugins and Modules](#mass-pm)  \n\u003e 6.1 [MassEntity](#mass-pm-me)  \n\u003e 6.2 [MassGameplay](#mass-pm-gp)  \n\u003e 6.3 [MassAI](#mass-pm-ai)  \n\u003e 7. [Other Resources](#mass-or)  \n\n\n\u003c!--ProposalFUNK: How about a \"FAQ\" of sorts for debugging etc? like: --\u003e\n\u003c!--Why isn't anything being used in my query?--\u003e\n\u003c!--When should I use Mass?--\u003e\n\u003c!--General debug UI info etc--\u003e\n\u003c!-- REVIEWMEVORI: I would split it in two different subsections:\n- Common issues\n- Mass FAQ\n\nAlthough I don't know if these should have their own section each one, or if we can group them under the same section (making the subsections).\n --\u003e\n\n\u003ca name=\"mass\"\u003e\u003c/a\u003e\n## 1. Mass\nMass is Unreal's in-house ECS framework! Technically, [Sequencer](https://docs.unrealengine.com/4.26/en-US/AnimatingObjects/Sequencer/Overview/) already used one internally but it wasn't intended for gameplay code. Mass was created by the AI team at Epic Games to facilitate massive crowd simulations, but has grown to include many other features as well. It was featured in the [Matrix Awakens demo](https://www.unrealengine.com/en-US/blog/introducing-the-matrix-awakens-an-unreal-engine-5-experience) Epic released in 2021.\n\n\u003ca name=\"ecs\"\u003e\u003c/a\u003e\n## 2. Entity Component System \nMass is an archetype-based Entity Componenet System. If you already know what that is you can skip ahead to the next section.\n\nIn Mass, some ECS terminology differs from the norm in order to not get confused with existing unreal code:\n| ECS | Mass |\n| ----------- | ----------- |\n| Entity | Entity |\n| Component | Fragment | \n| System | Processor | \n\nTypical Unreal Engine game code is expressed as Actor objects that inherit from parent classes to change their data and functionality based on what they ***are***. \nIn an ECS, an entity is only composed of fragments that get manipulated by processors based on which ECS components they ***have***. \n\nAn entity is really just a small unique identifier that points to some fragments. A Processor defines a query that filters only for entities that have specific fragments. For example, a basic \"movement\" Processor could query for entities that have a transform and velocity component to add the velocity to their current transform position. \n\nFragments are stored in memory as tightly packed arrays of other identical fragment arrangements called archetypes. Because of this, the aforementioned movement processor can be incredibly high performance because it does a simple operation on a small amount of data all at once. New functionality can easily be added by creating new fragments and processors.\n\nInternally, Mass is similar to the existing [Unity DOTS](https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/index.html) and [FLECS](https://github.com/SanderMertens/flecs) archetype-based ECS libraries. There are many more!\n\n\u003ca name=\"sample\"\u003e\u003c/a\u003e\n## 3. Sample Project\nCurrently, the sample features the following:\n\n- A bare minimum movement processor to show how to set up processors.\n- An example of how to use Mass spawners for zonegraph and EQS.\n- Mass-simulated crowd of cones that parades around the level following a ZoneGraph shape with lanes.\n- Linetraced projectile simulation example.\n- Simple 3d hashgrid for entities.\n- Very basic Mass blueprint integration.\n- Grouped niagara rendering for entities.\n\n\n\u003ca name=\"massconcepts\"\u003e\u003c/a\u003e\n## 4. Mass Concepts\n\n#### Sections\n\n\u003e 4.1 [Entities](#mass-entities)  \n\u003e 4.2 [Fragments](#mass-fragments)  \n\u003e 4.3 [Tags](#mass-tags)  \n\u003e 4.4 [Subsystems](#mass-subsystems)  \n\u003e 4.5 [The archetype model](#mass-arch-mod)   \n\u003e 4.6 [Processors](#mass-processors)  \n\u003e 4.7 [Queries](#mass-queries)  \n\u003e 4.8 [Traits](#mass-traits)  \n\u003e 4.9 [Observers](#mass-o)\n\n\u003ca name=\"mass-entities\"\u003e\u003c/a\u003e\n### 4.1 Entities\nSmall unique identifiers that point to a combination of [fragments](#mass-fragments) and [tags](#mass-tags) in memory. Entities are mainly a simple integer ID. For example, entity 103 might point to a single projectile with transform, velocity, and damage data.\n\n\u003c!-- TODO: Document the different ways in which we can identify an entity in mass and their purpose? FMassEntityHandle, FMassEntity, FMassEntityView?? --\u003e\n\n\u003ca name=\"mass-fragments\"\u003e\u003c/a\u003e\n### 4.2 Fragments\nData-only `UStructs` that entities can own and processors can query on. To create a fragment, inherit from [`FMassFragment`](https://docs.unrealengine.com/5.0/en-US/API/Plugins/MassEntity/FMassFragment/). \n\n```c++\nUSTRUCT()\nstruct MASSCOMMUNITYSAMPLE_API FLifeTimeFragment : public FMassFragment\n{\n\tGENERATED_BODY()\n\tfloat Time;\n};\n```\n\nWith `FMassFragment`s each entity gets its own fragment data, to share data across many entities, we can use a [shared fragment](#mass-fragments-sf). \n\n\u003ca name=\"mass-fragments-sf\"\u003e\u003c/a\u003e\n#### 4.2.1 Shared Fragments\nA Shared Fragment is a type of Fragment that multiple entities can point to. This is often used for configuration common to a group of entities, like LOD or replication settings. To create a shared fragment, inherit from [`FMassSharedFragment`](https://docs.unrealengine.com/5.0/en-US/API/Plugins/MassEntity/FMassSharedFragment/).\n\n```c++\nUSTRUCT()\nstruct MASSCOMMUNITYSAMPLE_API FVisibilityDistanceSharedFragment : public FMassSharedFragment\n{\n\tGENERATED_BODY()\n\t\n\tUPROPERTY()\n\tfloat Distance;\n};\n```\n\nIn the example above, all the entities containing the `FVisibilityDistanceSharedFragment` will see the same `Distance` value. If an entity modifies the `Distance` value, the rest of the entities with this fragment will see the change as they share it through the archetype. Shared fragments are generally added from Mass Traits. \n\nMake sure your shared fragments are Crc hashable or else you may not actually create a new instance when you call `GetOrCreateSharedFragmentByHash`. You can actually pass in your own hash with `GetOrCreateSharedFragmentByHash`, which can help if you prefer to control what makes each one unique.\n\nThanks to this sharing data requirement, the Mass entity manager only needs to store one Shared Fragment for the entities that use it.\n\n\u003ca name=\"mass-tags\"\u003e\u003c/a\u003e\n### 4.3 Tags\nEmpty `UScriptStructs` that [processors](#mass-processors) can use to filter entities to process based on their presence/absence. To create a tag, inherit from [`FMassTag`](https://docs.unrealengine.com/5.0/en-US/API/Plugins/MassEntity/FMassTag/).\n\n```c++\nUSTRUCT()\nstruct MASSCOMMUNITYSAMPLE_API FProjectileTag : public FMassTag\n{\n\tGENERATED_BODY()\n};\n```\n**Note:** Tags should never contain member properties.\n\n\u003ca name=\"mass-subsystems\"\u003e\u003c/a\u003e\n### 4.4 Subsystems\nStarting in UE 5.1, Mass enhanced its API to support [`UWorldSubsystems`](https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Subsystems/UWorldSubsystem/) in our [Processors](#mass-processors). This provides a way to create encapsulated functionality to operate Entities. First, inherit from `UWorldSubsystem` and define its basic interface alongside your functions and variables:\n\n```c++\nUCLASS()\nclass MASSCOMMUNITYSAMPLE_API UMyWorldSubsystem : public UWorldSubsystem\n{\n\tGENERATED_BODY()\n\npublic:\n\tvoid Write(int32 InNumber);\n\tint32 Read() const;\n\nprotected:\n\t// UWorldSubsystem begin interface\n\tvirtual void Initialize(FSubsystemCollectionBase\u0026 Collection) override;\n\tvirtual void Deinitialize() override;\n\t// UWorldSubsystem end interface\n\t\nprivate:\n\tUE_MT_DECLARE_RW_ACCESS_DETECTOR(AccessDetector);\n\tint Number = 0;\n};\n```\n\nFollowing next, we present an implementation example of the provided interface above (see `MassEntityTestTypes.h`):\n\n```c++\nvoid UMyWorldSubsystem::Initialize(FSubsystemCollectionBase\u0026 Collection)\n{\n\t// Initialize dependent subsystems before calling super\n\tCollection.InitializeDependency(UMyOtherSubsystemOne::StaticClass());\n\tCollection.InitializeDependency(UMyOtherSubsystemTwo::StaticClass());\n\tSuper::Initialize(Collection);\n\n\t// In here you can hook to delegates!\n\t// ie: OnFireHandle = FExample::OnFireDelegate.AddUObject(this, \u0026UMyWorldSubsystem::OnFire);\n}\n\nvoid UMyWorldSubsystem::Deinitialize()\n{\n\t// In here you can unhook from delegates\n\t// ie: FExample::OnFireDelegate.Remove(OnFireHandle);\n\tSuper::Deinitialize();\n}\n\nvoid UMyWorldSubsystem::Write(int32 InNumber)\n{\n\tUE_MT_SCOPED_WRITE_ACCESS(AccessDetector);\n\tNumber = InNumber;\n}\n\nint32 UMyWorldSubsystem::Read() const\n{\n\tUE_MT_SCOPED_READ_ACCESS(AccessDetector);\n\treturn Number;\n}\n```\nThe code above is multithread-friendly, hence the `UE_MT_X` tokens.\n\n\u003c!-- FIXMEVORI-UE5: Maybe a section exposing the different UE_MT_X tokens? (Get informed about their full scope) --\u003e\n\nFinally, to make this world subsystem compatible with Mass, you must define its subsystem traits, which inform Mass about its [parallel capabilities](#mass-mt). In this case, our subsystem supports parallel reads:\n\n```c++\n/**\n * Traits describing how a given piece of code can be used by Mass. \n * We require author or user of a given subsystem to \n * define its traits. To do it add the following in an accessible location. \n */\ntemplate\u003c\u003e\nstruct TMassExternalSubsystemTraits\u003cUMyWorldSubsystem\u003e final\n{\n\tenum\n\t{\n\t\tThreadSafeRead = true,\n\t\tThreadSafeWrite = false,\n\t};\n};\n/**\n* this will let Mass know it can access UMyWorldSubsystem on any thread.\n*\n* This information is being used to calculate processor and query \n* dependencies as well as appropriate distribution of\n* calculations across threads.\n*/\n```\nIf you want to use a `UWorldSubsystem` that has not had its traits defined before and you cannot modify its header explicitly, you can add the subsystem trait information in a separate header file (see `MassGameplayExternalTraits.h`).\n\n\u003ca name=\"mass-arch-mod\"\u003e\u003c/a\u003e\n### 4.5 The archetype model\nAs mentioned previously, an entity is a unique combination of fragments and tags. Mass calls each of these combinations archetypes. For example, given three different combinations used by our entities, we would generate three archetypes:\n\n![MassArchetypeDefinition](Images/arche-entity-type.png)\n\nThe `FMassArchetypeData` struct represents an archetype in Mass internally. \n\n\u003ca name=\"mass-arch-mod-tags\"\u003e\u003c/a\u003e\n#### 4.5.1 Tags in the archetype model\nEach archetype (`FMassArchetypeData`) holds a bitset (`TScriptStructTypeBitSet\u003cFMassTag\u003e`) that contains the tag presence information, whereas each bit in the bitset represents whether a tag exists in the archetype or not.\n\n![MassArchetypeTags](Images/arche-tags.png)\n\nFollowing the previous example, *Archetype 0* and *Archetype 2* contain the tags: *TagA*, *TagC* and *TagD*; while *Archetype 1* contains *TagC* and *TagD*. Which makes the combination of *Fragment A* and *Fragment B* to be split in two different archetypes.\n\n\u003ca name=\"mass-arch-mod-fragments\"\u003e\u003c/a\u003e\n#### 4.5.2 Fragments in the archetype model\nAt the same time, each archetype holds an array of chunks (`FMassArchetypeChunk`) with fragment data.\n\nEach chunk contains a subset of the entities included in our archetype where data is organized in a pseudo-[struct-of-arrays](https://en.wikipedia.org/wiki/AoS_and_SoA#Structure_of_arrays) way:\n\n![MassArchetypeChunks](Images/arche-chunks.png)\n\nThe following Figure represents the archetypes from the example above in memory:\n\n![MassArchetypeMemory](Images/arche-mem.png)\n\nBy having this pseudo-[struct-of-arrays](https://en.wikipedia.org/wiki/AoS_and_SoA#Structure_of_arrays) data layout divided in multiple chunks, we are allowing a great number of whole-entities to fit in the CPU cache. \n\nThis is thanks to the chunk partitoning, since without it, we wouldn't have as many whole-entities fit in cache, as the following diagram displays:\n\n![MassArchetypeCache](Images/arche-cache-friendly.png)\n\nIn the above example, the Chunked Archetype gets whole-entities in cache, while the Linear Archetype gets all the *A Fragments* in cache, but cannot fit each fragment of an entity.\n\nThe Linear approach would be fast if we would only access the *A Fragment* when iterating entities, however, this is almost never the case. Usually, when we iterate entities we tend to access multiple fragments, so it is convenient to have them all in cache, which is what the chunk partitioning provides.\n\nThe chunk size (`UE::Mass::ChunkSize`) has been conveniently set based on next-gen cache sizes (128 bytes per line and 1024 cache lines). This means that archetypes with more bits of fragment data will contain less entities per chunk.\n\n**Note:** It is relevant to note that a cache miss would be produced every time we want to access a fragment that isn't on cache for a given entity.\n\n\u003ca name=\"mass-processors\"\u003e\u003c/a\u003e\n### 4.6 Processors\nProcessors combine multiple user-defined [queries](#mass-queries) with functions that compute entities.\n\nUnreal classes deriving from UMassProcessor are automatically registered with Mass and added to the `EMassProcessingPhase::PrePhsysics` processing phase by default. Each `EMassProcessingPhase` relates to an `ETickingGroup`, meaning that, by default, processors tick every frame in their given processing phase.\nThey can also be created and registered with the `UMassSimulationSubsystem` but the common case is to create a new type. \nUsers can configure to which processing phase their processor belongs by modifying the `ProcessingPhase` variable included in `UMassProcessor`: \n\n| `EMassProcessingPhase` | Related `ETickingGroup` | Description |\n| ----------- | ----------- | ----------- |\n| `PrePhysics` | `TG_PrePhysics` | Executes before physics simulation starts. |\n| `StartPhysics` | `TG_StartPhysics` | Special tick group that starts physics simulation. | \n| `DuringPhysics` | `TG_DuringPhysics` | Executes in parallel with the physics simulation work. | \n| `EndPhysics` | `TG_EndPhysics` |Special tick group that ends physics simulation. | \n| `PostPhysics` | `TG_PostPhysics` |Executes after rigid body and cloth simulation. | \n| `FrameEnd` | `TG_LastDemotable` | Catchall for anything demoted to the end. | \n\n\nIn their constructor, processors can define rules for their execution order, the processing phase and which type of game clients they execute on:\n```c++\nUMyProcessor::UMyProcessor()\n{\n\t// This processor is registered with mass by just existing! This is the default behaviour of all processors.\n\tbAutoRegisterWithProcessingPhases = true;\n\t// Setting the processing phase explicitly\n\tProcessingPhase = EMassProcessingPhase::PrePhysics;\n\t// Using the built-in movement processor group\n\tExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::Movement;\n\t// You can also define other processors that require to run before or after this one\n\tExecutionOrder.ExecuteAfter.Add(TEXT(\"MSMovementProcessor\"));\n\t// This executes only on Clients and Standalone\n\tExecutionFlags = (int32)(EProcessorExecutionFlags::Client | EProcessorExecutionFlags::Standalone);\n\t// This processor should not be multithreaded\n\tbRequiresGameThreadExecution = true;\n}\n```\n\nOn initialization, Mass creates a dependency graph of processors using their execution rules so they execute in order (ie: In the example above we make sure to move our entities with `MSMovementProcessor` before we call `Execute` in `UMyProcessor`).\n\nThe `ExecutionFlags` variable indicates whether this processor should be executed on `Standalone`, `Server` or `Client`.\n\nBy default [all processors are multithreaded](#mass-mt), however, they can also be configured to run in a single-thread if necessary by setting `bRequiresGameThreadExecution` to `true`.\n\n**Note:** Mass ships with a series of processors that are designed to be inherited and extended with custom logic. ie: The visualization and LOD processors. \n\n\u003ca name=\"mass-queries\"\u003e\u003c/a\u003e\n### 4.7 Queries\nQueries (`FMassEntityQuery`) filter and iterate entities given a series of rules based on Fragment and Tag presence.\n\nProcessors can define multiple `FMassEntityQuery`s and should override the `ConfigureQueries` to add rules to the different queries defined in the processor's header:\n\n```c++\nvoid UMyProcessor::ConfigureQueries()\n{\n\tMyQuery.AddTagRequirement\u003cFMoverTag\u003e(EMassFragmentPresence::All);\n\tMyQuery.AddRequirement\u003cFHitLocationFragment\u003e(EMassFragmentAccess::ReadOnly, EMassFragmentPresence::Optional);\n\tMyQuery.AddSubsystemRequirement\u003cUMassDebuggerSubsystem\u003e(EMassFragmentAccess::ReadWrite);\n\tMyQuery.RegisterWithProcessor(*this);\n\n\tProcessorRequirements.AddSubsystemRequirement\u003cUMassDebuggerSubsystem\u003e(EMassFragmentAccess::ReadWrite);\n}\n```\n\nTo execute queries on a processor, we must register them by calling `RegisterWithProcessor` passing the processor as a parameter. `FMassEntityQuery` also offers a parameter constructor that calls `RegisterWithProcessor`, which is employed in some processors from various Mass modules (ie: `UDebugVisLocationProcessor`).\n\n`ProcessorRequirements` is a special query part of `UMassProcessor` that holds all the `UWorldSubsystem`s that get accessed in the `Execute` function outside the queries scope. In the example above, `UMassDebuggerSubsystem` gets accessed within `MyQuery`'s scope (`MyQuery.AddSubsystemRequirement`) and in the `Execution` function scope (`ProcessorRequirements.AddSubsystemRequirement`).\n\nQueries are executed by calling the `ForEachEntityChunk` member function with a lambda, passing the related `FMassEntityManager` and `FMassExecutionContext`. \n\nProcessors execute queries within their `Execute` function:\n\n```c++\nvoid UMyProcessor::Execute(FMassEntityManager\u0026 EntityManager, FMassExecutionContext\u0026 Context)\n{\n\t//Note that this is a lambda! If you want extra data you may need to pass it in the [] operator\n\tMyQuery.ForEachEntityChunk(EntityManager, Context, [](FMassExecutionContext\u0026 Context)\n\t{\n\t\t//Loop over every entity in the current chunk and do stuff!\n\t\tfor (int32 EntityIndex = 0; EntityIndex \u003c Context.GetNumEntities(); ++EntityIndex)\n\t\t{\n\t\t\t// ...\n\t\t}\n\t});\n}\n```\nBe aware that the index we employ to iterate entities, in this case `EntityIndex`, doesn't identify uniquely your entities along time, since chunks' disposition may change and an entity that has an index this frame, may be in a different chunk with a different index in the next frame.\n\n**Note:** Queries can also be created and iterated outside processors.\n\n\u003ca name=\"mass-queries-ar\"\u003e\u003c/a\u003e\n#### 4.7.1 Access requirements\n\nQueries can define read/write access requirements for Fragments and Subsystems:\n\n| `EMassFragmentAccess` | Description |\n| ----------- | ----------- |\n| `None` | No binding required. |\n| `ReadOnly` | We want to read the data for the fragment/subsystem. | \n| `ReadWrite` | We want to read and write the data for the fragment/subsystem. | \n\n`FMassFragment`s use `AddRequirement` to add access and presence requirement to our fragments. While `FMassSharedFragment`s employ `AddSharedRequirement`. Finally, `UWorldSubsystem`s use `AddSubsystemRequirement`. \n\nHere are some basic examples in which we add access rules in two Fragments from a `FMassEntityQuery MyQuery`:\n\n```c++\t\nvoid UMyProcessor::ConfigureQueries()\n{\n\t// Entities must have an FTransformFragment and we are reading and writing it (EMassFragmentAccess::ReadWrite)\n\tMyQuery.AddRequirement\u003cFTransformFragment\u003e(EMassFragmentAccess::ReadWrite);\n\t\t\n\t// Entities must have an FMassForceFragment and we are only reading it (EMassFragmentAccess::ReadOnly)\n\tMyQuery.AddRequirement\u003cFMassForceFragment\u003e(EMassFragmentAccess::ReadOnly);\n\n\t// Entities must have a common FClockSharedFragment that can be read and written\n\tMyQuery.AddSharedRequirement\u003cFClockSharedFragment\u003e(EMassFragmentAccess::ReadWrite);\n\n\t// Entities must have a UMassDebuggerSubsystem that can be read and written\n\tMyQuery.AddSubsystemRequirement\u003cUMassDebuggerSubsystem\u003e(EMassFragmentAccess::ReadWrite);\n\n\t// Registering the query with UMyProcessor\n\tMyQuery.RegisterWithProcessor(*this);\n}\n```\n\n`ForEachEntityChunk`s can use the following functions to access `ReadOnly` or `ReadWrite` data according to the access requirement:\n\n| `EMassFragmentAccess` | Type | Function |Description |\n| ----------- | ----------- | ----------- | ----------- |\n| `ReadOnly` | Fragment | `GetFragmentView` | Returns a read only `TConstArrayView` containing the data of our `ReadOnly` fragment. |\n| `ReadWrite` | Fragment | `GetMutableFragmentView` | Returns a writable `TArrayView` containing de data of our `ReadWrite` fragment. | \n| `ReadOnly` | Shared Fragment | `GetConstSharedFragment` | Returns a constant reference to our read only shared fragment. |\n| `ReadWrite` | Shared Fragment | `GetMutableSharedFragment` | Returns a reference of our writable shared fragment. | \n| `ReadOnly` | Subsystem | `GetSubsystemChecked` | Returns a read only constant reference to our world subsystem. |\n| `ReadWrite` | Subsystem | `GetMutableSubsystemChecked` | Returns a reference of our writable shared world subsystem. | \n\nFind below an example:\n\n```c++\nMyQuery.ForEachEntityChunk(EntityManager, Context, [this, World = EntityManager.GetWorld()](FMassExecutionContext\u0026 Context)\n{\n\tUMassDebuggerSubsystem\u0026 Debugger = Context.GetMutableSubsystemChecked\u003cUMassDebuggerSubsystem\u003e(World);\n\n\tconst auto TransformList = Context.GetFragmentView\u003cFTransformFragment\u003e();\n\tconst auto ForceList = Context.GetMutableFragmentView\u003cFMassForceFragment\u003e();\n\n\tfor (int32 EntityIndex = 0; EntityIndex \u003c Context.GetNumEntities(); ++EntityIndex)\n\t{\n\t\tFTransform\u0026 TransformToChange = TransformList[EntityIndex].GetMutableTransform();\n\t\tconst FVector DeltaForce = Context.GetDeltaTimeSeconds() * ForceList[EntityIndex].Value;\n\t\tTransformToChange.AddToTranslation(DeltaForce);\n\t\tDebugger.AddShape(EMassEntityDebugShape::Box, TransformToChange.GetLocation(), 10.f);\n\t}\n});\n```\n\n**Note:** Tags do not have access requirements since they don't contain data.\n\n\u003ca name=\"mass-queries-pr\"\u003e\u003c/a\u003e\n#### 4.7.2 Presence requirements\nQueries can define presence requirements for Fragments and Tags:\n\n| `EMassFragmentPresence` | Description                                                                       |\n| ----------- |-----------------------------------------------------------------------------------|\n| All | All of the required fragments/tags must be present. Default presence requirement. |\n| Any | At least one of the fragments/tags marked any must be present.                    | \n| None | None of the required fragments/tags can be present.                               | \n| Optional | If fragment/tag is present we'll use it, but it does not need to be present.      | \n\n##### 4.7.2.1 Presence requirements in Tags\nTo add presence rules to Tags, use `AddTagRequirement`.   \n```c++\nvoid UMyProcessor::ConfigureQueries()\n{\n\t// Entities are considered for iteration without the need of containing the specified Tag\n\tMyQuery.AddTagRequirement\u003cFOptionalTag\u003e(EMassFragmentPresence::Optional);\n\t// Entities must at least have the FHorseTag or the FSheepTag\n\tMyQuery.AddTagRequirement\u003cFHorseTag\u003e(EMassFragmentPresence::Any);\n\tMyQuery.AddTagRequirement\u003cFSheepTag\u003e(EMassFragmentPresence::Any);\n\tMyQuery.RegisterWithProcessor(*this);\n}\n```\n\n`ForEachChunk`s can use `DoesArchetypeHaveTag` to determine if the current archetype contains the the Tag:\n\n```c++\nMyQuery.ForEachEntityChunk(EntityManager, Context, [](FMassExecutionContext\u0026 Context)\n{\n\tif(Context.DoesArchetypeHaveTag\u003cFOptionalTag\u003e())\n\t{\n\t\t// I do have the FOptionalTag tag!!\n\t}\n\n\t// Same with Tags marked with Any\n\tif(Context.DoesArchetypeHaveTag\u003cFHorseTag\u003e())\n\t{\n\t\t// I do have the FHorseTag tag!!\n\t}\n\tif(Context.DoesArchetypeHaveTag\u003cFSheepTag\u003e())\n\t{\n\t\t// I do have the FSheepTag tag!!\n\t}\n});\n```\n\n##### 4.7.2.2 Presence requirements in Fragments\nFragments and shared fragments can define presence rules in an additional `EMassFragmentPresence` parameter through `AddRequirement` and `AddSharedRequirement`, respectively.\n\n```c++\nvoid UMyProcessor::ConfigureQueries()\n{\n\t// Entities are considered for iteration without the need of containing the specified Fragment\n\tMyQuery.AddRequirement\u003cFMyOptionalFragment\u003e(EMassFragmentAccess::ReadWrite, EMassFragmentPresence::Optional);\n\t// Entities must at least have the FHorseFragment or the FSheepFragment\n\tMyQuery.AddRequirement\u003cFHorseFragment\u003e(EMassFragmentAccess::ReadWrite, EMassFragmentPresence::Any);\n\tMyQuery.AddRequirement\u003cFSheepFragment\u003e(EMassFragmentAccess::ReadWrite, EMassFragmentPresence::Any);\n\tMyQuery.RegisterWithProcessor(*this);\n}\n```\n\n`ForEachChunk`s can use the length of the `Optional`/`Any` fragment's `TArrayView` to determine if the current chunk contains the Fragment before accessing it:\n\n```c++\nMyQuery.ForEachEntityChunk(EntityManager, Context, [](FMassExecutionContext\u0026 Context)\n{\n\tconst auto OptionalFragmentList = Context.GetMutableFragmentView\u003cFMyOptionalFragment\u003e();\n\tconst auto HorseFragmentList = Context.GetMutableFragmentView\u003cFHorseFragment\u003e();\t\n\tconst auto SheepFragmentList = Context.GetMutableFragmentView\u003cFSheepFragment\u003e();\n\tfor (int32 i = 0; i \u003c Context.GetNumEntities(); ++i)\n\t{\n\t\t// An optional fragment array is present in our current chunk if the OptionalFragmentList isn't empty\n\t\tif(OptionalFragmentList.Num() \u003e 0)\n\t\t{\n\t\t\t// Now that we know it is safe to do so, we can compute\n\t\t\tOptionalFragmentList[i].DoOptionalStuff();\n\t\t}\n\n\t\t// Same with fragments marked with Any\n\t\tif(HorseFragmentList.Num() \u003e 0)\n\t\t{\n\t\t\tHorseFragmentList[i].DoHorseStuff();\n\t\t}\n\t\tif(SheepFragmentList.Num() \u003e 0)\n\t\t{\n\t\t\tSheepFragmentList[i].DoSheepStuff();\n\t\t}\t\t\n\t}\n});\n```\n\u003c!-- REVIEWMEVORI: Maybe move to common Mass operations!! Spawning/Destroying subsections, although I think that wouldn't hurt having this here, and then referencing it back in the common mass operation section --\u003e\n\u003ca name=\"mass-queries-mq\"\u003e\u003c/a\u003e\n#### 4.7.3 Mutating entities with `Defer()`\n                                                        \nWithin the `ForEachEntityChunk` we have access to the current execution context. `FMassExecutionContext` enables us to get entity data and mutate their composition. The following code adds the tag `FDead` to any entity that has a health fragment with its `Health` variable less or equal to 0, at the same time, as we define in `ConfigureQueries`, after the `FDead` tag is added, the entity won't be considered for iteration (`EMassFragmentPresence::None`):\n\n```c++\nvoid UDeathProcessor::ConfigureQueries()\n{\n\t// All the entities processed in this query must have the FHealthFragment fragment\n\tDeclareDeathQuery.AddRequirement\u003cFHealthFragment\u003e(EMassFragmentAccess::ReadOnly, EMassFragmentPresence::All);\n\t// Entities processed by this queries shouldn't have the FDead tag, as this query adds the FDead tag\n\tDeclareDeathQuery.AddTagRequirement\u003cFDead\u003e(EMassFragmentPresence::None);\n\tDeclareDeathQuery.RegisterWithProcessor(*this);\n}\n\nvoid UDeathProcessor::Execute(FMassEntityManager\u0026 EntityManager, FMassExecutionContext\u0026 Context)\n{\n\tDeclareDeathQuery.ForEachEntityChunk(EntityManager, Context, [\u0026,this](FMassExecutionContext\u0026 Context)\n\t{\n\t\tauto HealthList = Context.GetFragmentView\u003cFHealthFragment\u003e();\n\n\t\tfor (int32 EntityIndex = 0; EntityIndex \u003c Context.GetNumEntities(); ++EntityIndex)\n\t\t{\n\t\t\tif(HealthList[EntityIndex].Health \u003c= 0.f)\n\t\t\t{\n\t\t\t\t// Adding a tag to this entity when the deferred commands get flushed\n\t\t\t\tFMassEntityHandle EntityHandle = Context.GetEntity(EntityIndex);\n\t\t\t\tContext.Defer().AddTag\u003cFDead\u003e(EntityHandle);\n\t\t\t}\n\t\t}\n\t});\n}\n```\n\nIn order to Defer Entity mutations we require to obtain the handle (`FMassEntityHandle`) of the Entities we wish to modify. `FMassExecutionContext` holds an array with all the Entity handles. We can access it through two different methods:\n\n| Plurality | Code |\n| ----------- | ----------- |\n| Singular | `FMassEntityHandle EntityHandle = Context.GetEntity(EntityIndex);` |\n| Plural | `auto EntityHandleArray = Context.GetEntities();` | \n\nThe following Subsections will employ the keywords `EntityHandle` and `EntityHandleArray` when handling singular or plural operations, respectively.\n\n\n##### 4.7.3.1 Basic mutation operations\nThe following Listings define the native mutations that you can defer:\n\nDeferring is commonly done from a processor's `FMassExecutionContext` with `.Defer()` but these can be done outside processing with a `EntityManager-\u003eDefer()` call. \n\nFragments:\n```c++\nContext.Defer().AddFragment\u003cFMyFragment\u003e(EntityHandle);\nContext.Defer().RemoveFragment\u003cFMyFragment\u003e(EntityHandle);\n```\n\nTags:\n```c++\nContext.Defer().AddTag\u003cFMyTag\u003e(EntityHandle);\nContext.Defer().RemoveTag\u003cFMyTag\u003e(EntityHandle);\nContext.Defer().SwapTags\u003cFOldTag, FNewTag\u003e(EntityHandle);\n```\n \nDestroying entities:\n```c++\nContext.Defer().DestroyEntity(EntityHandle);\nContext.Defer().DestroyEntities(EntityHandleArray);\n```\nThese are all convenient wrappers for the internal template based deferred commands.\n\n##### 4.7.3.2 Advanced mutation operations\nThere is a set of `FCommandBufferEntryBase` commands that can be used to defer some more useful entity mutations. The following subsections provide an overview. \n\n###### 4.7.3.2.1 `FMassCommandAddFragmentInstanceList`\nDefers adding new fragment data to an existing entity. \n\nIn the example below we mutate the `FHitResultFragment` with HitResult data, and a `FSampleColorFragment` fragment with a new color and add (or set if already present) them to an existing entity.\n\n```c++\nFHitResultFragment HitResultFragment;\nFSampleColorFragment ColorFragment = FSampleColorFragment(Color);\n\n// Sets fragment data on an existing entity\nEntityManager-\u003eDefer().PushCommand\u003cFMassCommandAddFragmentInstances\u003e(Entity, ColorFragment, HitResultFragment);\n\n// It can add single fragment instances as well, and should set data on existing fragments safely\nEntityManager-\u003eDefer().PushCommand\u003cFMassCommandAddFragmentInstances\u003e(Entity, SomeOtherFragment);\n```\n\n\u003ca name=\"mass-queries-FBuildEntityFromFragmentInstances\"\u003e\u003c/a\u003e\n###### 4.7.3.2.2 `FMassCommandBuildEntity`\nDefers Creating an Entity and adds a list of fragments with data to it.\n\n```c++\nFTransformFragment MyTransformFragment;\nMyTransformFragment.SetTransform(FTransform::Identity);\n\n// We build a new entity and add data to it in one command!\nEntityManager-\u003eDefer().PushCommand\u003cFMassCommandBuildEntity\u003e(ReserverdEntity, MyTransformFragment, SomeOtherFragment);\n));\n```\n\n###### 4.7.3.2.3 `FMassCommandBuildEntityWithSharedFragments` \nSimilar to `FMassCommandBuildEntity` but it takes a `FMassArchetypeSharedFragmentValues` struct to set shared fragment values on the entity as well. This requires some extra work to find or create the shared fragment.\n```c++\nFMassArchetypeSharedFragmentValues SharedFragmentValues;\n// This is what traits use to create their shared fragment info as well\nFConstSharedStruct\u0026 SharedFragment = EntityManager-\u003eGetOrCreateConstSharedFragment(MySharedFragment);\nSharedFragmentValues.AddConstSharedFragment(SharedFragment);\n\n// MoveTemp is required here...\nEntityManager-\u003eDefer().PushCommand\u003cFMassCommandBuildEntityWithSharedFragments\u003e(EntityHandle, MoveTemp(SharedFragmentValues), TransformFragment, AnotherFragmentEtc);\n```\n\n\u003c!-- FIXMEVORI: For consistency, lets add as a title the name of the command, however in this one I'm not sure which ones we should include --\u003e\n##### 4.7.3.2.4 `FMassDeferredSetCommand`\nDefers the execution of the `TFunction` lambda passed in as a parameter. It is useful for performing Mass-related operations that none of the other commands cover. This is a smart way to handle Actor mutations, as [those usually need to happen on the main thread](https://vkguide.dev/docs/extra-chapter/multithreading/#ways-of-using-multithreading-in-game-engines).\n\n```c++\nEntityManager-\u003eDefer().PushCommand\u003cFMassDeferredSetCommand\u003e(\n   [\u0026](FMassEntityManager\u0026 Manager)\n  {\n      \t// This runs when the deferred commands are flushed\n      \tMyActor.DoGameThreadWork();\n      \t// Regular Mass manager calls can happen in here as well. For example:\n  \tEntityManager.BuildEntity(ReservedEntity, InstanceStructs, EntityTemplate.GetSharedFragmentValues());\n  });\n```\n\n**Note:** The `TFunction` lambda does have a FMassEntityManager\u0026 as a function parameter you should include in every lambda using this command.\n\n\u003c!-- FIXMEVORI: What is this? maybe we need a code example, since the example above doesn't cover it --\u003e\n`FMassDeferredCreateCommand`,`FMassDeferredSetCommand` and the other similarly named types are each templated to set specific `EMassCommandOperationType`\n\nThese are designed to organize deferred commands into different operation types. For example: we want to create entities before we change fragments on them!\nHere they are and what they do in order when commands are flushed:\n\n| Operation         |                                                |\n|-------------------|------------------------------------------------|\n| Create            | Creating new entities.                         |\n| Add               | Adding fragments/tags                          |\n| Remove            | Removing fragments/tags                        |\n| ChangeComposition | Adding and removing tags/fragments.            |\n| Set               | Changing fragment data (also adding fragments) |\n| None              | Default value, always executed last.           |\n\n\n\u003c!-- REVIEWMEFUNK: I think this section is a bit overkill and might mislead people to thinking they need to make a new template to do anything. They could probably figure out how to do this on their own by just reading the source. --\u003e\n\u003c!-- Do you think FMassDeferredSetCommand can cover them all? Isn't it worth to mention how to create new commands? Remember that this doc is to show how to use mass, so before having the command from above it was a bit tricky --\u003e\n\n[//]: # ()\n[//]: # (##### 4.7.3.2.7 Custom commands)\n[//]: # (It is possible to create custom mutations by implementing your own commands derived from `FCommandBufferEntryBase`.)\n[//]: # ()\n[//]: # (```c++)\n[//]: # (Context.Defer\u0026#40;\u0026#41;.EmplaceCommand\u003cFMyCustomComand\u003e\u0026#40;...\u0026#41;)\n[//]: # (```)\n[//]: # ()\n[//]: # (The command needs to have a constructor and to override `FCommandBufferEntryBase::Execute\u0026#40;\u0026#41;` but in order to correctly trigger observers two extra steps are required:)\n[//]: # ()\n[//]: # (1. Setting the `Type` definition to either `ECommandBufferOperationType::Remove` or `ECommandBufferOperationType::Add` in the header.)\n[//]: # (```c++)\n[//]: # (enum)\n[//]: # ({)\n[//]: # (\tType = ECommandBufferOperationType::Add)\n[//]: # (};)\n[//]: # (```)\n[//]: # (2. Implementing \u0026#40;not overriding\u0026#41; `AppendAffectedEntitiesPerType` and calling functions on the passed in `FMassCommandsObservedTypes` as needed. Here we are adding a changed `Tag` and changed `Fragment`. `TargetEntity` is a member of the parent struct.)\n[//]: # (```c++)\n[//]: # (void AppendAffectedEntitiesPerType\u0026#40;FMassCommandsObservedTypes\u0026 ObservedTypes\u0026#41;)\n[//]: # ({)\n[//]: # (\tObservedTypes.TagAdded\u0026#40;TagType, TargetEntity\u0026#41;;\t)\n[//]: # (\tObservedTypes.FragmentAdded\u0026#40;FragmentType, TargetEntity\u0026#41;;)\n[//]: # (})\n[//]: # (```)\n[//]: # ()\n\n\u003ca name=\"mass-traits\"\u003e\u003c/a\u003e\n### 4.8 Traits\nTraits are C++ defined objects that declare a set of Fragments, Tags and data for authoring new entities in a data-driven way. \n\nTo start using traits, create a `DataAsset` that inherits from \n`UMassEntityConfigAsset` and add new traits to it. Each trait can be expanded to set properties if it has any. \n\nIn addition, it is possible to inherit Fragments from another `UMassEntityConfigAsset` by setting it in the `Parent` field.\n\n![MassEntityConfigAsset](Images/massentityconfigasset.jpg)\n\nBetween the many built-in traits offered by Mass, we can find the `Assorted Fragments` trait, which holds an array of `FInstancedStruct` that enables adding Fragments to this trait from the editor without the need of creating a new C++ Trait. \n\n![AssortedFragments](Images/assortedfragments.jpg)\n\n\n\u003c!-- FIXME: Please elaborate --\u003e\n\u003c!-- REVIEWMEFUNK kind of hard to talk about it too much here with the other section existing --\u003e\nTraits are often used to add Shared Fragments in the form of settings. For example, our visualization traits save memory by sharing which mesh they are displaying, parameters etc. Configs with the same settings will share the same Shared Fragment.\n\n\n#### 4.8.1 Creating a trait\nTraits are created by inheriting `UMassEntityTraitBase` and overriding `BuildTemplate`. Here is a very basic example:\n\n```c++\nUCLASS(meta = (DisplayName = \"Debug Printing\"))\nclass MASSCOMMUNITYSAMPLE_API UMSDebugTagTrait : public UMassEntityTraitBase\n{\n\tGENERATED_BODY()\npublic:\n\tvirtual void BuildTemplate(FMassEntityTemplateBuildContext\u0026 BuildContext, UWorld\u0026 World) const override\n\t{\n\t\t// Adding a tag\n\t\tBuildContext.AddTag\u003cFMassSampleDebuggableTag\u003e();\n\t\t\n\t\t// Adding a fragment\n\t\tBuildContext.AddFragment\u003cFTransformFragment\u003e();\n\n\t\t// _GetRef lets us mutate the fragment\n\t\tBuildContext.AddFragment_GetRef\u003cFSampleColorFragment\u003e().Color = UserSetColor;\n\t};\n\n\t// Editable in the editor property list for this asset\n\tUPROPERTY(EditAnywhere)\n\tFColor UserSetColor;\n};\n```\n**Note:** We recommend looking at the many existing traits in this sample and the mass modules for a better overview. For the most part, they are fairly simple UObjects that occasionally have extra code to make sure the fragments are all valid and set correctly. \n\n\n \u003c!--REVIEWMEFUNK moved it up to this section \"--\u003e\n##### Shared Fragments\n\n Here is a partial `BuildTemplate` example for adding a shared struct, which can do some extra work to see if a shared fragment identical to the new one already exists:\n```c++\n\t//Create the actual fragment struct and set up the data for it however you like \n\tFMySharedSettings MyFragment;\n\tMyFragment.MyValue = UserSetValue;\n\n\t//Get a hash of a FConstStructView of said fragment and store it\n\tuint32 MySharedFragmentHash = UE::StructUtils::GetStructCrc32(FConstStructView::Make(MyFragment));\n\t\n\t//Search the Mass Entity subsystem for an identical struct with the hash. If there are none, make a new one with the set fragment.\n\tFSharedStruct MySharedFragment = \n\t\tEntityManager.GetOrCreateSharedFragment\u003cFMySharedSettings\u003e(MySharedFragmentHash, MyFragment);\n\n\t//Finally, add the shared fragment to the BuildContext!\n\tBuildContext.AddSharedFragment(MySharedFragment);\n```\n\n\n#### 4.8.2 Validating traits\nTraits can override `ValidateTemplate` to provide custom validation code for the trait. Native traits use this function to log  errors and/or change the `BuildContext` if required. This function is called after `BuildTemplate` and is invoked for all of the traits of the current template.\n\nIn the following snippet, we check if a field of the trait is `nullptr` and log an error:\n```c++\nvoid UMSNiagaraRepresentationTrait::ValidateTemplate(FMassEntityTemplateBuildContext\u0026 BuildContext, UWorld\u0026 World) const\n{\n\t// If our shared niagara system is null, show an error!\n\tif (!SharedNiagaraSystem)\n\t{\n\t\tUE_VLOG(\u0026World, LogMass, Error, TEXT(\"SharedNiagaraSystem is null!\"));\n\t\treturn;\n\t}\n}\n```\n\n\u003ca name=\"mass-o\"\u003e\u003c/a\u003e\n### 4.9 Observers\nThe `UMassObserverProcessor` is a type of processor that operates on entities that have just performed a `EMassObservedOperation` over the Fragment/Tag type observed:\n\n| `EMassObservedOperation` | Description |\n| ----------- | ----------- |\n| Add | The observed Fragment/Tag was added to an entity. |\n| Remove | The observed Fragment/Tag was removed from an entity. | \n\nObservers do not run every frame, but every time a batch of entities is changed in a way that fulfills the observer requirements.\n\nFor example, this observer changes the color to the entities that just had an `FColorFragment` added:\n\n```c++\nUMSObserverOnAdd::UMSObserverOnAdd()\n{\n\tObservedType = FSampleColorFragment::StaticStruct();\n\tOperation = EMassObservedOperation::Add;\n\tExecutionFlags = (int32)(EProcessorExecutionFlags::All);\n}\n\nvoid UMSObserverOnAdd::ConfigureQueries()\n{\n\tEntityQuery.AddRequirement\u003cFSampleColorFragment\u003e(EMassFragmentAccess::ReadWrite);\n}\n\nvoid UMSObserverOnAdd::Execute(FMassEntityManager\u0026 EntityManager, FMassExecutionContext\u0026 Context)\n{\n\tEntityQuery.ForEachEntityChunk(EntityManager, Context, [\u0026,this](FMassExecutionContext\u0026 Context)\n\t{\n\t\tauto Colors = Context.GetMutableFragmentView\u003cFSampleColorFragment\u003e();\n\t\tfor (int32 EntityIndex = 0; EntityIndex \u003c Context.GetNumEntities(); ++EntityIndex)\n\t\t{\n\t\t\t// When a color is added, make it random!\n\t\t\tColors[EntityIndex].Color = FColor::MakeRandomColor();\n\t\t}\n\t});\n}\n```\n\u003c!-- FIXMEFUNK: What happened with this section? :( --\u003e\n\u003c!-- REVIEWMEVORI: Lots of source changes, since it's still not really clear when observers fire I felt the need to get extra specific here... \nIt's getting to the point where the only things that don't trigger them would be easier to list out. I really think Epic should mark the API calls that don't do this with _Internal or something --\u003e\n\u003ca name=\"mass-o-n\"\u003e\u003c/a\u003e\n#### 4.9.1 Entity Manager Observer calls\n - In order for observers to fire, something must call alert the observer manager to the change in composition.\n- [Deferred commands](#mass-queries-mq) that change entities will trigger observers.\n\nIf your code relies on observers firing immediately you should make sure the Mass function calls you are making actually alert observers to changes. \nIn earlier versions there were some functions that skipped calling observers but as of 5.5 nearly all ways of changing entity composition are covered.\n\n[This commit](https://github.com/EpicGames/UnrealEngine/commit/2b883dec5f6c821648f2d6005ac06e704099dbd9\n) on ue5-main has rectified this issue for most mass subsystem-level calls. \n\nIf you need to, asking the observer manager to trigger changes should only require calling `OnCompositionChanged()` with the delta of newly added or removed components.\n\u003c!-- FIXMEFUNK: This is kind of a wacky example. I assume most people who need this might \n```c++\nEntityManager.GetObserverManager().OnCompositionChanged(\n          FMassArchetypeEntityCollection(MyEntityArchetypeHandle, Entity,\n          FMassArchetypeEntityCollection::NoDuplicates)\n\t\t, EntityTemplate.GetCompositionDescriptor()\n\t\t, EMassObservedOperation::Add))\n```\n\u003c!-- FIXMEVORI: I'll review this the next day --\u003e\n\u003ca name=\"mass-o-mft\"\u003e\u003c/a\u003e\n#### 4.9.2 Observing multiple Fragment/Tags\nObservers can also be used to observe multiple operations and/or types. For that, override the `Register` function in `UMassObserverProcessor`: \n\n```c++\n// header file\nUPROPERTY()\nUScriptStruct* MyObserverType = nullptr;\n\nEMassObservedOperation MyOperation = EMassObservedOperation::MAX;\n\n\n// cpp file \nUMyMassObserverProcessor::UMyMassObserverProcessor()\n{\n\tObservedType = FSampleColorFragment::StaticStruct();\n\tOperation = EMassObservedOperation::Add;\n\tExecutionFlags = (int32)(EProcessorExecutionFlags::All);\n\tMyObserverType = FSampleMaterialFragment::StaticStruct();\n\tMyOperation = EMassObservedOperation::Add;\n}\n\nvoid UMyMassObserverProcessor::Register()\n{\n\tcheck(ObservedType);\n\tcheck(MyObservedType);\n\n\tUMassObserverRegistry::GetMutable().RegisterObserver(*ObservedType, Operation, GetClass());\n\tUMassObserverRegistry::GetMutable().RegisterObserver(*ObservedType, MyOperation, GetClass());\n\tUMassObserverRegistry::GetMutable().RegisterObserver(*MyObservedType, MyOperation, GetClass());\n\tUMassObserverRegistry::GetMutable().RegisterObserver(*MyObservedType, Operation, GetClass());\n\tUMassObserverRegistry::GetMutable().RegisterObserver(*MyObservedType, EMassObservedOperation::Add, GetClass());\n}\n```\nAs noted above, it is possible to reuse the same `EMassObservedOperation` operation for multiple observed types, and vice-versa.\n\n\n\u003c!--FIXMEFUNK - Very WIP. I will share some images of Insights in here soon...--\u003e\n\u003ca name=\"mass-mt\"\u003e\u003c/a\u003e\n### 4.10 Multithreading\n\nOut of the box Mass can spread out work to threads in two different ways:\n\u003c!--FIXMEFUNK - we really need to figure out which ini this goes in...--\u003e\n- Per-Processor threading based on the processor dependency graph by setting the console variable `mass.FullyParallel 1`\n\n- Per-query parallelism spreads the job of one query over multiple threads using a `ParallelFor`. This is available by using `Query.ParallelForEachEntityChunk` in place of `Query.ForEachEntityChunk`.\n```c++\nMyQuery.ParallelForEachEntityChunk(EntityManager, Context, [](FMassExecutionContext\u0026 Context)\n{\n\t//Loop over every entity in the current chunk and do stuff!\n\tfor (int32 EntityIndex = 0; EntityIndex \u003c Context.GetNumEntities(); ++EntityIndex)\n\t{\n\t\t// ...\n\t}\n}, FMassEntityQuery::ForceParallelExecution);\n```\nNotes:\n- ParallelForEachEntityChunk will create a dedicated command buffer for each job by default.\n- the Cvar `mass.AllowQueryParallelFor` must be enabled.\n\n\n\n\u003ca name=\"mass-cm\"\u003e\u003c/a\u003e\n## 5. Common Mass operations\nThis section is designed to serve as a quick reference for how to perform common operations with Mass. As usual, we are open to ideas on how to organize this stuff!!\n\nAs a rule of thumb, most entity mutations (adding/removing components, spawning or removing entities) are generally done by deferring them from inside of processors. \n\n\n\u003c!-- You can create your own `FMassExecutionContext` whenever you need one as well! We have one on the `UMSSubsystem` as an example. --\u003e\n\n\n\n\u003c!--FIXMEFUNK: When does changing values require deferrment if ever? need more concurrency info for that--\u003e\n\n\u003ca name=\"mass-cm-spae\"\u003e\u003c/a\u003e\n## 5.1 Spawning entities\n\nIn this Section we are going to review different methods to spawn entities. First, we review the `Mass Spawner`, which is useful to spawn entities with predefined data. Then, we'll move to more complex spawning methods that enable us to have fine grained control over the spawning.\n\n### 5.1.1 Spawn entities with data predefined in the Editor - Mass Spawner\n\nMass Spawners (`AMassSpawner`) are useful to spawn entities with static data in the world (predefined CDO and spawning transform).\n\nMass Spawners require two things to spawn entities:\n- An array of entity types: Define which entities to spawn through a [`UMassEntityConfigAsset`](#mass-traits). \n- An array of Spawn Data Generators (`FMassSpawnDataGenerator`): Define where to spawn entities (their starting transform).\n\nIn the details panel of a `AMassSpawner` we can find the following:\n![MassSpawnerSettings](Images/massspawneractor.jpg)\n\nIn the above image, the `MEC_DebugVisualize` Entity Config is used to spawn 25 entities on `BeginPlay` (`bAutoSpawnOnBeginPlay` is set to `true`).\n\nThe spawning location of these entities is generated by the `EQS SpawnPoints Generator`, which is a built-in generator that uses the [Environmental Query System](https://docs.unrealengine.com/4.27/en-US/InteractiveExperiences/ArtificialIntelligence/EQS/EQSOverview/) to find locations in the world to spawn. In this example, we are creating a circle of locations around the spawner actor: \n\n![EQSCircle](Images/eqscircle.jpg)\n\nThe result in game on BeginPlay:\n\n![SpawnerCircleResult](Images/spawnercircleresult.jpg)\n\nMass Spawners are placed in the level and can be queried in runtime to trigger spawns by calling `DoSpawning()` from C++ or Blueprints:\n\n![aa](Images/massspawner-lvl1minions.jpg)\n\nMass Spawners provide a minimal API to do spawn related operations, following next we provide some of the user-friendly accessible functions from both, blueprints and C++:\n- `DoSpawning()`: Performs the spawning of all the agent types of this spawner.\n- `DoDespawning()`: Despawns all mass agents spawned by this spawner.\n- `ScaleSpawningCount(float Scale)`: Scales the spawning counts. Scale is the number to multiply the all counts of each agent types.\n- `GetCount()`: Returns the unscaled count of entities to spawn.\n- `GetSpawningCountScale()`: Returns the number to multiply the all counts of each agent types.\n\n**Note:** The Matrix demo uses extensively the Mass Spawner system.\n\n\n### 5.1.2 Spawn entities with runtime data\nIn this section we explore more flexible spawn mechanism, in which we are able to spawn entities on demand with runtime data (ie: a passed in location).\n\nThese spawning methods can be benefitial when we require to mutate entities on spawn, or when when the spawning data cannot be predefined (ie: the initial transform data for a projectile spawning from a weapon).\n\n\u003c!-- FIXMEVORI: Karl we need more movement in this section, I kind of repurposed it to make more sense! --\u003e\n\n#### 5.1.2.1 Batch Spawning\nIn C++, you can just call `BatchCreateEntities()` on an instance of a `FMassEntityManager` by passing in a specific archetype with the number you want. This is actually how `AMassSpawner` spawns stuff internally! It calls `BatchSetEntityFragmentsValues()` afterwards to set the initial data on the returned `FEntityCreationContext`.\n\n\u003c!--FIXMEKARL another struct to document (FEntityCreationContext) Weeeeee! It actually might be useful for our mutation merging idea. --\u003e\n\n#### 5.1.2.2 Single Entity Spawning\nSpawning a new Entity only requires asking the Mass Entity Subsystem for a new entity. Here are some common ways to create new entities with data.\n\n#### Entity with Fragment data\n\u003c!--FIXMEFUNK: Aaaagh!! --\u003e\n\u003c!-- FIXMEVORI: Nopers, as I told you don't worry about replicating code and documentation, but let's expose here the best of the bestests practice --\u003e\n\n[Check out this example with `FBuildEntityFromFragmentInstance` from the commands section:](#mass-queries-FBuildEntityFromFragmentInstances)\n\nWe currently recommend not calling `UMassEntitySubsystem::BuildEntity` directly unless you are sure don't need observers to trigger for the entity. The shared fragments go in there as well as the third function argument!\n\n#### Entity with Fragment data and Tags\n\nCurrently, my best guess is to use `FMassCommandBuildEntity` and then defer however many `Context.Defer().AddTag\u003cFTagType\u003e(EntityReservedEarlier);` you need.\n\n\u003c!--REVIEWMEFUNK: Added stuff in observers--\u003e\n#### A note on observers\n\nIt is very important to remember that Observers are only triggered explicitely in certain functions out of the box. [Check out the list here.](#mass-o-n) \n\n\u003c!-- NEW! --\u003e\n\u003ca name=\"mass-cm-dsae\"\u003e\u003c/a\u003e\n## 5.2 Destroying entities\n- Deferred\n\nThe preferred way of destroying entities is to defer it (especially when processing, to stay safe.)\n```c++ \nEntityManager-\u003eDefer().DestroyEntities(Entities);\nEntityManager-\u003eDefer().DestroyEntity(Entity);\n```\n- Directly\n\n`BatchDestroyEntityChunks` is preferred as it calls the observer manager for you. This is only truly safe to call outside of processing on the main thread, like other direct composition changes.\n`UMassSpawnerSubsystem::DestroyEntities` calls this as well.\n\n```c++\nEntityManager-\u003eBatchDestroyEntityChunks(Collection) \n\n```\n\n\n\u003c!-- #### Deferred --\u003e\n\n\u003c!-- #### Direct Call --\u003e\n\n\u003ca name=\"mass-cm-opee\"\u003e\u003c/a\u003e\n## 5.3 Operating Entities\n\nIn this Section we are going to explore the most relevant tools Mass offers to operate Entities. This covers all the get and set operations and structures to work with them (fragment, archetype, tags...).\n\n**Note:** In cases where we need to operate with Entities outside the current processing context (e.g. avoidance between Entity crowds) it is possible to call all of the regular Mass Subsystem functions or deferred actions on them. This is not ideal for cache coherency but it is nearly unavoidable in gameplay code. \n\n## 5.2.1 `FMassEntityView`\n\n`FMassEntityView` is a struct that eases all kinds of Entity operations. One can be constructed with a `FMassEntityHandle` and a `FMassEntityManager`. On construction, the `FMassEntityView` caches the Entity's archetype data, which will later reduce repeated work needed to retrieve information about the Entity.\n\nFollowing next, we expose some of the relevant functions of `FMassEntityView`:\n\n\u003c!--TODO: List of relevant functions interesting for the user:--\u003e\n\u003c!-- REVIEWMEFUNK slighty better example... --\u003e\nIn the following contrived processor example, we check if `NearbyEntity` is an enemy, if it is, we damage it:\n```c++\nFMassEntityView EntityView(Manager, NearbyEntity.Entity);\n\n//Check if we have a tag\nif (EntityView.HasTag\u003cFEnemyTag\u003e())\n{\n\tif(auto DamageOnHitFragment = EntityView.GetFragmentDataPtr\u003cFDamageOnHit\u003e())\n\t{\n\t    // Now we defer something to do to the other entity!\n \t    FDamageFragment DamageFragment;\n \t    DamageFragment.Damage = DamageOnHitFragment.Damage * AttackPower;\n        Context.Defer().PushCommand\u003cFMassCommandAddFragmentInstances\u003e(EntityView.GetEntity, DamageFragment);\n\t}\n}\n```\n\n\n\u003ca name=\"mass-pm\"\u003e\u003c/a\u003e\n## 6. Mass Plugins and Modules\nThis Section overviews the three main Mass plugins and their different modules:\n\n\u003e 6.1 [`MassEntity`](#mass-pm-me)  \n\u003e 6.2 [`MassGameplay`](#mass-pm-gp)  \n\u003e 6.3 [`MassAI`](#mass-pm-ai)  \n\n\u003ca name=\"mass-pm-me\"\u003e\u003c/a\u003e\n### 6.1 [`MassEntity`](https://docs.unrealengine.com/5.0/en-US/overview-of-mass-entity-in-unreal-engine/)\n`MassEntity` is the main plugin that manages everything regarding Entity creation and storage.\n\n\n\u003ca name=\"mass-pm-gp\"\u003e\u003c/a\u003e\n### 6.2 `MassGameplay `\nThe `MassGameplay` plugin compiles a number of useful Fragments and Processors that are used in different parts of the Mass framework. It is divided into the following modules:\n\n\u003e 6.2.1 [`MassCommon`](#mass-pm-gp-mc)  \n\u003e 6.2.2 [`MassMovement`](#mass-pm-gp-mm)  \n\u003e 6.2.3 [`MassRepresentation`](#mass-pm-gp-mr)  \n\u003e 6.2.4 [`MassSpawner`](#mass-pm-gp-ms)  \n\u003e 6.2.5 [`MassActors`](#mass-pm-gp-ma)  \n\u003e 6.2.6 [`MassLOD`](#mass-pm-gp-ml)  \n\u003e 6.2.7 [`MassReplication`](#mass-pm-gp-mre)  \n\u003e 6.2.8 [`MassSignals`](#mass-pm-gp-msi)  \n\u003e 6.2.9 [`MassSmartObjects`](#mass-pm-gp-mso)  \n\n\u003c!-- FIXME: Since there are some modules more interesting than others we will format them in a subsection manner, so we can extend the interesting one easier. --\u003e\n\u003ca name=\"mass-pm-gp-mc\"\u003e\u003c/a\u003e\n#### 6.2.1 `MassCommon`\nBasic fragments like `FTransformFragment`.\n\n\u003ca name=\"mass-pm-gp-mm\"\u003e\u003c/a\u003e\n#### 6.2.2 `MassMovement`\nFeatures an important `UMassApplyMovementProcessor` processor that moves entities based on their velocity and force.\n\n\u003ca name=\"mass-pm-gp-mr\"\u003e\u003c/a\u003e\n#### 6.2.3 `MassRepresentation`\nProcessors and fragments for rendering entities in the world. They generally use an ISMC to do so, but can also swap entities out with full Unreal actors at user specified distances.\n\n\u003ca name=\"mass-pm-gp-ms\"\u003e\u003c/a\u003e\n#### 6.2.4 `MassSpawner`\nA highly configurable actor type that can spawn specific entities where you want. There are two ways of choosing locations built in, one that uses an Environmental Query System asset and one that uses a ZoneGraph tag-based query. The Mass Spawner actor appears to be intended for things that spawn all at once initially like NPCs,trees etc, rather than dynamically spawned things like projectiles, for example.\n\n\u003ca name=\"mass-pm-gp-ma\"\u003e\u003c/a\u003e\n#### 6.2.5 `MassActors`\nA bridge between the general UE5 actor framework and Mass. A type of fragment that turns entities into \"Agents\" that can exchange data in either direction (or both ways).\n\n\u003ca name=\"mass-pm-gp-ml\"\u003e\u003c/a\u003e\n#### 6.2.6 `MassLOD`\nLOD Processors that can manage different kinds of levels of detail, from rendering to ticking at different rates based on fragment settings. They are used in visualization and replication currently as well.\n\n\u003ca name=\"mass-pm-gp-mre\"\u003e\u003c/a\u003e\n#### 6.2.7 `MassReplication`\nReplication support for Mass! Other modules override `UMassReplicatorBase` to replicate stuff. Entities are given a separate Network ID that gets passed over the network, rather than the EntityHandle. An example showing this is planned for much later.\n\n\u003ca name=\"mass-pm-gp-msi\"\u003e\u003c/a\u003e\n#### 6.2.8 `MassSignals`\nA system that lets entities send named signals to each other.\n\n\u003ca name=\"mass-pm-gp-mso\"\u003e\u003c/a\u003e\n#### 6.2.9 [`MassSmartObjects`](https://docs.unrealengine.com/5.0/en-US/smart-objects-in-unreal-engine/)\nLets entities \"claim\" SmartObjects to interact with them.\n\n\u003c!-- This section explicitly for AI specific modules--\u003e\n\u003ca name=\"mass-pm-ai\"\u003e\u003c/a\u003e\n### 6.3 MassAI\n`MassAI` is a plugin that provides AI features for Mass within a series of modules:\n\n\u003e 6.3.1 [`ZoneGraph`](#mass-pm-ai-zg)  \n\u003e 6.3.2 [`StateTree`](#mass-pm-ai-st)  \n\u003e 6.3.3 ...\n\nThis section, like the rest of the document, is still work in progress.\n\n\u003c!-- FIXME: Ideally, this section should be like the previous one. --\u003e\n\u003c!-- FIXME: To what extent do we want to cover the AI side of mass. --\u003e\n\u003c!-- FIXMEFUNK: I think we should cover a brief overview at the minimum. most of Mass is attached to the AI stuff so we kind of have to at least mention all of it. The Zonegraph cones are a good short example. We should suggest to check out the CitySample at least. --\u003e\n\n\u003ca name=\"mass-pm-ai-zg\"\u003e\u003c/a\u003e\n#### 6.3.1 `ZoneGraph`\n\u003c!-- FIXME: Add screenshots and examples. --\u003e\nIn-level splines and shapes that use config defined lanes to direct zonegraph pathing things around! Think sidewalks, roads etc. This is the main way Mass Crowd members get around.\n\n\u003ca name=\"mass-pm-ai-st\"\u003e\u003c/a\u003e\n#### 6.3.2 [`StateTree`](https://docs.unrealengine.com/5.0/en-US/overview-of-state-tree-in-unreal-engine/)\n\u003c!-- FIXME: Add screenshots and examples. --\u003e\nA new lightweight generic statemachine that can work in conjunction with Mass. One of them is used to give movement targets to the cones in the parade in the sample.\n\n\n\n\n\u003ca name=\"mass-or\"\u003e\u003c/a\u003e\n## 7. Other Resources\n\n### 7.1 Mass\nThis section compiles very useful Mass resources to complement this documentation.\n#### **Epic Games Official resources:**\n  - [[Documentation] MassEntity](https://docs.unrealengine.com/5.0/en-US/overview-of-mass-entity-in-unreal-engine/): Overview of Unreal Engine's MassEntity system.\n  - [[Documentation] Mass Avoidance](https://docs.unrealengine.com/5.0/en-US/mass-avoidance-in-unreal-engine/): Mass Avoidance is a force-based avoidance system integrated with MassEntity.\n  - [[Documentation] Smart Objects](https://docs.unrealengine.com/5.0/en-US/smart-objects-in-unreal-engine/): Smart Objects represent a set of activities in the level that can be used through a reservation system.\n  - [[Documentation] StateTree](https://docs.unrealengine.com/5.0/en-US/overview-of-state-tree-in-unreal-engine/): Overview of the Mass AI StateTree system.\n  - [[Video] State of Unreal : Large Numbers of Entities with Mass](https://youtu.be/f9q8A-9DvPo): Mario Palermo (Global Unreal Engine 5 Lead Evangelist) showcases Mass in detail in a 30-minute video.\n\n\u003c!-- Huge credit to this blog for teaching us how to use spawners! --\u003e\n#### **[@quabqi](https://www.zhihu.com/people/quabqi)'s blog posts (Chinese):**\n  - [ECS of UE5: MASS framework (1)](https://zhuanlan.zhihu.com/p/441773595): Mass memory hierarchy, entity and archetype introduction.\n  - [ECS of UE5: MASS framework (2)](https://zhuanlan.zhihu.com/p/446937133): Mass basic execution.\n  - [ECS of UE5: MASS framework (3)](https://zhuanlan.zhihu.com/p/477803528): A deep dive in `MassGameplay`.\n  - [MassAI crowd drawing of UE5 CitySample](https://zhuanlan.zhihu.com/p/496165391): How are the pedestrians of the UE5 CitySample handled?\n \n### 7.2 General Entity Component Systems (ECS)\n\n  - [Sander's Entity Component System FAQ](https://github.com/SanderMertens/ecs-faq): This FAQ is for anyone interested in ECS \u0026 modern, high performance game development.\n  - [Data-Oriented Design by Richard Fabian](https://www.dataorienteddesign.com/dodbook/): A book detailing a style/paradigm of programming called \"Data-Oriented Design\". Entity Component System libraries like Mass make data oriented design easy!\n  - [Evolve Your Hierarchy by Mick West](https://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/): An article demonstrating how to use composition over inheritance to represent game entities.\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMegafunk%2FMassSample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FMegafunk%2FMassSample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FMegafunk%2FMassSample/lists"}