ue-mass-entity
Use this skill when working with Mass Entity, MassEntity, Mass AI, MassProcessor, MassFragment, MassTag, MassObserver, MassSpawner, MassCrowd, Mass ECS, entity archetype, ForEachEntityChunk, FMassEntityQuery, FMassEntityManager, ISM crowd, or large-scale entity simulation in Unreal Engine. See references/mass-entity-patterns.md for processor and observer templates. See references/mass-fragment-reference.md for built-in fragment types.
What this skill does
# UE Mass Entity Framework
You are an expert in Unreal Engine's Mass Entity framework -- an archetype-based Entity Component System (ECS) designed for high-performance simulation of thousands of entities using cache-friendly data layouts and parallel processing.
## Context Check
Before proceeding, read `.agents/ue-project-context.md` to determine:
- Whether the MassEntity plugin is enabled (and MassAI, MassCrowd, MassGameplay if needed)
- The target entity count and performance budget
- Whether MassCrowd lane navigation or ZoneGraph is in use
- Existing processors, fragments, traits, and entity config assets
## Information Gathering
Ask the developer:
1. What kind of entities are being simulated? (crowds, projectiles, traffic, wildlife, custom)
2. What data does each entity carry? (position, velocity, health, custom state)
3. Are entities visualized? If so, what LOD strategy? (ISM, skeletal, actor promotion)
4. Is this multiplayer? If so, which entities replicate?
5. How many entities at peak? (hundreds vs. tens of thousands)
---
## ECS Concepts
Mass Entity uses an archetype ECS model where entity composition determines memory layout:
| Concept | Class Base | Purpose |
|---------|-----------|---------|
| Entity | `FMassEntityHandle` | 8-byte identity handle (Index + SerialNumber) |
| Fragment | `FMassFragment` | Per-entity mutable data (position, velocity, health) |
| Tag | `FMassTag` | Zero-size boolean marker for filtering |
| Shared Fragment | `FMassSharedFragment` | Per-archetype mutable data |
| Const Shared Fragment | `FMassConstSharedFragment` | Per-archetype immutable data (mesh params) |
| Chunk Fragment | `FMassChunkFragment` | Per-memory-chunk data (custom chunk-level state) |
| Archetype | `FMassArchetypeHandle` | Unique combination of fragment/tag types |
**Why archetypes matter:** Entities with identical fragment/tag composition share the same archetype. All fragments of the same type within a chunk are stored contiguously, enabling cache-friendly iteration over thousands of entities per frame.
---
## Fragment and Tag Definitions
All types require `USTRUCT()` with `GENERATED_BODY()`:
```cpp
// Per-entity mutable data
USTRUCT()
struct FHealthFragment : public FMassFragment
{
GENERATED_BODY()
float Current = 100.f;
float Max = 100.f;
};
// Zero-size marker — no data members
USTRUCT()
struct FDeadTag : public FMassTag
{
GENERATED_BODY()
};
// Shared across all entities in an archetype (mutable)
USTRUCT()
struct FTeamSharedFragment : public FMassSharedFragment
{
GENERATED_BODY()
int32 TeamID = 0;
};
```
**Chunk fragments** (`FMassChunkFragment`) store per-memory-chunk state shared across all entities in a chunk. Note: `FMassRepresentationLODFragment` inherits from `FMassFragment` (per-entity), not `FMassChunkFragment`. **Const shared fragments** (`FMassConstSharedFragment`) are immutable after archetype creation -- use for configuration data like `FMassRepresentationParameters`. See `references/mass-fragment-reference.md` for built-in types.
---
## FMassEntityManager
The entity manager is NOT a `UObject` -- it is a struct (`TSharedFromThis<FMassEntityManager>`, `FGCObject`). Access it through `UMassEntitySubsystem` (a `UWorldSubsystem`):
```cpp
UMassEntitySubsystem* MassSubsystem = GetWorld()->GetSubsystem<UMassEntitySubsystem>();
FMassEntityManager& EntityManager = MassSubsystem->GetMutableEntityManager();
// const ref: MassSubsystem->GetEntityManager()
```
### Entity Lifecycle
```cpp
// One-shot creation
FMassEntityHandle Entity = EntityManager.CreateEntity(ArchetypeHandle);
// With shared fragments
FMassArchetypeSharedFragmentValues SharedValues;
FMassEntityHandle Entity = EntityManager.CreateEntity(ArchetypeHandle, SharedValues);
// Two-phase (reserve then build)
FMassEntityHandle Handle = EntityManager.ReserveEntity();
EntityManager.BuildEntity(Handle, ArchetypeHandle);
// Batch creation (thousands at once)
// BatchCreateEntities returns TSharedRef<FEntityCreationContext> — retain it until
// observer processors should fire (dropping it early suppresses observer execution).
TArray<FMassEntityHandle> Entities;
TSharedRef<FEntityCreationContext> CreationContext =
EntityManager.BatchCreateEntities(ArchetypeHandle, 5000, Entities);
// Destruction
EntityManager.DestroyEntity(Handle);
EntityManager.BatchDestroyEntities(EntityArray);
```
### Validity Checks
`FMassEntityHandle::IsSet()` (aliased as `IsValid()`) only checks non-zero Index/SerialNumber -- it does NOT verify the entity exists. Always use the entity manager:
```cpp
EntityManager.IsEntityValid(Handle) // entity exists
EntityManager.IsEntityBuilt(Handle) // fully constructed
EntityManager.IsEntityActive(Handle) // active in simulation
```
### Direct Fragment/Tag Mutations (Outside Processors)
```cpp
EntityManager.AddFragmentToEntity(Handle, FHealthFragment::StaticStruct());
EntityManager.RemoveFragmentFromEntity(Handle, FHealthFragment::StaticStruct());
EntityManager.AddTagToEntity(Handle, FDeadTag::StaticStruct());
EntityManager.RemoveTagFromEntity(Handle, FDeadTag::StaticStruct());
EntityManager.SwapTagsForEntity(Handle, FOldTag::StaticStruct(), FNewTag::StaticStruct());
```
---
## UMassProcessor
Processors iterate over entities matching a query each frame. Subclass `UMassProcessor` (abstract), override `ConfigureQueries()` and `Execute()`:
```cpp
UCLASS()
class UMyMovementProcessor : public UMassProcessor
{
GENERATED_BODY()
public:
UMyMovementProcessor();
protected:
virtual void ConfigureQueries(const TSharedRef<FMassEntityManager>& EntityManager) override;
virtual void Execute(FMassEntityManager& EntityManager,
FMassExecutionContext& Context) override;
private:
FMassEntityQuery MovementQuery;
};
```
### Constructor Configuration
```cpp
UMyMovementProcessor::UMyMovementProcessor()
{
ProcessingPhase = EMassProcessingPhase::PrePhysics;
ExecutionFlags = static_cast<int32>(
EProcessorExecutionFlags::Server |
EProcessorExecutionFlags::Standalone);
ExecutionOrder.ExecuteInGroup = UE::Mass::ProcessorGroupNames::Movement;
ExecutionOrder.ExecuteAfter.Add(TEXT("UMassApplyVelocityProcessor"));
bRequiresGameThreadExecution = false; // true if accessing UObjects
}
```
**`EMassProcessingPhase`:** `PrePhysics`, `StartPhysics`, `DuringPhysics`, `EndPhysics`, `PostPhysics`, `FrameEnd`
**`EProcessorExecutionFlags`:** `None`(0), `Standalone`(1), `Server`(2), `Client`(4), `Editor`(8), `AllNetModes`(7 = Standalone|Server|Client)
**Execution ordering:** `ExecutionOrder.ExecuteInGroup`, `ExecuteAfter`, `ExecuteBefore` control processor scheduling relative to named groups and other processors.
---
## FMassEntityQuery
Queries define which entities a processor operates on. Configure in `ConfigureQueries()`, then call `RegisterQuery()`:
```cpp
void UMyMovementProcessor::ConfigureQueries(const TSharedRef<FMassEntityManager>& EntityManager)
{
MovementQuery.AddRequirement<FTransformFragment>(
EMassFragmentAccess::ReadWrite, EMassFragmentPresence::All);
MovementQuery.AddRequirement<FMassVelocityFragment>(
EMassFragmentAccess::ReadOnly, EMassFragmentPresence::All);
MovementQuery.AddRequirement<FHealthFragment>(
EMassFragmentAccess::ReadOnly, EMassFragmentPresence::Optional);
MovementQuery.AddTagRequirement<FDeadTag>(EMassFragmentPresence::None);
MovementQuery.AddSharedRequirement<FTeamSharedFragment>(
EMassFragmentAccess::ReadOnly, EMassFragmentPresence::All);
MovementQuery.AddConstSharedRequirement<FMassRepresentationParameters>(
EMassFragmentPresence::All);
MovementQuery.AddRequirement<FMassRepresentationLODFragment>(
EMassFragmentAccess::ReadWrite, EMassFragmentPresence::Optional);
MovementQuery.AddSubsystemRequirement<UMassRepresentationSubsystem>(
EMassFragmentAccess::ReadWrite);
RegisterQuery(MovementQuery);
}
```
| `EMassFragmentAccess` | Usage |
|------Related in General
modeling-omnistudio-epc-catalog
IncludedSalesforce Industries CME EPC product-modeling skill for Product2-based catalog creation. Use when creating EPC products, configuring product attributes, building offer bundles with Product Child Items, or reviewing EPC DataPack JSON metadata for product catalog changes. TRIGGER when: user creates or updates Product2 EPC records, AttributeAssignment payloads, AttributeMetadata/AttributeDefaultValues, Offer bundles, or ProductChildItem relationships. DO NOT TRIGGER when: designing OmniScripts/FlexCards/Integration Procedures (use building-omnistudio-omniscript, building-omnistudio-flexcard, or building-omnistudio-integration-procedure), implementing Apex business logic (use generating-apex), or troubleshooting deployment pipelines (use deploying-metadata).
relationship-science-coach
IncludedUse this skill for direct, practical adult relationship coaching: couples conflict, repair, trust, marriage, dating, flirting, attachment patterns, emotional connection, sex, desire differences, eroticism, kink negotiation, affection, love languages, breakups, and long-term passion. Draw on Gottman, EFT and Hold Me Tight, attachment science, modern sex research, Perel, Nagoski, Kerner, Schnarch, Love and Stosny, and flexible love-language tools. Be concrete and low-hedge. Redirect only for imminent danger, abuse, coercive control, minors, non-consent, self-harm, stalking, or medical/legal/psychiatric decisions.
building-sf-integrations
IncludedSalesforce integration architecture and runtime plumbing with 120-point scoring. Use this skill to set up Named Credentials, External Credentials, External Services, REST/SOAP callout patterns, Platform Events, and Change Data Capture. TRIGGER when: user sets up Named Credentials, External Services, REST/SOAP callouts, Platform Events, CDC, or touches .namedCredential-meta.xml files. DO NOT TRIGGER when: Connected App/OAuth config (use configuring-connected-apps), Apex-only logic (use generating-apex), or data import/export (use handling-sf-data).
venue-templates
IncludedAccess comprehensive LaTeX templates, formatting requirements, and submission guidelines for major scientific publication venues (Nature, Science, PLOS, IEEE, ACM), academic conferences (NeurIPS, ICML, CVPR, CHI), research posters, and grant proposals (NSF, NIH, DOE, DARPA). This skill should be used when preparing manuscripts for journal submission, conference papers, research posters, or grant proposals and need venue-specific formatting requirements and templates.
let-fate-decide
IncludedDraws the 12 Houses of the Zodiac Tarot spread to inject entropy into planning when prompts are vague, ambiguous, or casually delegated. Interprets the spread to guide next steps. Use when the user says 'let fate decide', 'YOLO', 'whatever', 'idk', or other nonchalant phrases, makes Yu-Gi-Oh references, or when you are about to arbitrarily pick between multiple reasonable approaches. Prefer over ask-questions-if-underspecified when the user's tone is casual or playful rather than precision-seeking.
net-ops
IncludedCross-platform network troubleshooting (Windows, macOS, Linux) via local or remote shell. Use for: DNS broken, can't resolve hostnames, nslookup/dig works but apps fail, NRPT, WFP, scutil, /etc/resolver, systemd-resolved, /etc/resolv.conf, NetworkManager, VPN DNS leak residue (ProtonVPN/Mullvad/WireGuard/AnyConnect), AV/firewall blocking DNS or DoH, Tailscale DNS interaction, intermittent connectivity, remote diagnostics over SSH.