> For the complete documentation index, see [llms.txt](https://dante-3.gitbook.io/dante-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://dante-3.gitbook.io/dante-docs/modular-attachment-system/core-concepts.md).

# Core Concepts

## The Three Pillars

The system is built on three core objects that form a composition chain:

```
UModularAttachmentFragment  (atom — one mesh, one effect, one stat)
    └── composed into ──►
UModularAttachmentDefinition  (molecule — data asset grouping N fragments)
    └── loaded by ──►
UModularAttachmentComponent  (mount point — scene component on any actor)
```

## Fragment — `UModularAttachmentFragment`

A Fragment is the **smallest unit of behavior**. Each fragment does exactly one thing: spawn a mesh, apply a material, modify a stat, play a sound, etc.

**Design principles:**

* **Single responsibility** — one fragment = one effect
* **Self-contained** — declares its own soft refs, applies its own logic, cleans up after itself
* **Nestable** — fragments can contain child fragments via `AttachedFragments`
* **Tag-identified** — each fragment has a `FragmentTag` for lookup and event routing

### Lifecycle

| Phase   | Method                  | When                                                                     |
| ------- | ----------------------- | ------------------------------------------------------------------------ |
| Declare | `CollectSoftRefs()`     | Phase 2 — report all `TSoftObjectPtr` / `TSoftClassPtr` that must stream |
| Apply   | `ApplyToComponent()`    | Phase 3 — all assets loaded; create runtime components                   |
| Remove  | `RemoveFromComponent()` | Unload — destroy spawned components, revert modifications                |

All three are `BlueprintNativeEvent` — override in C++ (`_Implementation`) or Blueprint.

### Built-in Fragments

| Class                                    | Spawns                                                  |
| ---------------------------------------- | ------------------------------------------------------- |
| `ModularAttachmentFragment_StaticMesh`   | `UStaticMeshComponent` with socket attachment           |
| `ModularAttachmentFragment_SkeletalMesh` | `USkeletalMeshComponent` with optional leader pose sync |

### Fragment Hierarchy

Fragments can nest child fragments for complex compositions:

```
ScopeBodyFragment          (StaticMesh — housing)
├── LensFragment           (StaticMesh — glass, attaches to ScopeBody mesh)
├── ReticleFragment        (Custom — draws decal on ScopeBody mesh)
└── ZoomModifierFragment   (Custom — modifies FOV on aim)
```

Children are applied recursively. The system automatically propagates the parent's spawned mesh to children via `SetParentMeshComponent()` / `GetParentMeshComponent()`. A child fragment can call `GetParentMeshComponent()` in `ApplyToComponent` to attach to or modify the parent's mesh (e.g., `SetMaterial`).

Removing the root removes all children.

## Definition — `UModularAttachmentDefinition`

A Definition is a `UPrimaryDataAsset` that composes multiple fragments into a complete attachment.

### Key Properties

| Property              | Type                                  | Description                                                  |
| --------------------- | ------------------------------------- | ------------------------------------------------------------ |
| `AttachmentFragments` | `TArray<UModularAttachmentFragment*>` | Ordered list of top-level fragments (instanced, inline edit) |

### Key Methods

| Method                        | Returns           | Description                                                                 |
| ----------------------------- | ----------------- | --------------------------------------------------------------------------- |
| `GetPrimaryAssetId()`         | `FPrimaryAssetId` | Returns `"AttachmentDefinition:<AssetName>"`                                |
| `CollectAllSoftRefs(OutRefs)` | `void`            | Recursively walks all fragments + children, collects every soft object path |

> `CollectAllSoftRefs` is the key to the streaming pipeline — it ensures the subsystem knows every asset that must be loaded before any fragment's `ApplyToComponent` runs.

## Component — `UModularAttachmentComponent`

A Component (`USceneComponent`) is the **runtime mount point**. It represents a single attachment slot on an actor.

### Key Properties

| Property                    | Type                                           | Description                                            |
| --------------------------- | ---------------------------------------------- | ------------------------------------------------------ |
| `AttachmentDefinitionAsset` | `TSoftObjectPtr<UModularAttachmentDefinition>` | Definition to load (set in editor or runtime)          |
| `ComponentTag`              | `FGameplayTag`                                 | Slot identifier (e.g., `ModularAttachment.Slot.Optic`) |

### Key Methods

| Method                                         | Description                                                          |
| ---------------------------------------------- | -------------------------------------------------------------------- |
| `LoadAttachment()`                             | Begin async load of current definition                               |
| `UnloadAttachment()`                           | Remove all fragment components, release cache                        |
| `SwapAttachment(NewDef)`                       | Atomic unload → load                                                 |
| `GetFragmentByTag(Tag)`                        | Find a specific fragment object by `FragmentTag`                     |
| `GetMeshComponentByFragmentTag(Tag)`           | Any mesh component (static or skeletal) — ideal for `SetMaterial`    |
| `GetStaticMeshComponentByFragmentTag(Tag)`     | Direct access to the spawned `UStaticMeshComponent`                  |
| `GetSkeletalMeshComponentByFragmentTag(Tag)`   | Direct access to the spawned `USkeletalMeshComponent`                |
| `GetSpawnedComponentByFragmentTag(Tag, Class)` | First component matching class (BP: output pin type follows `Class`) |

### Auto-Load

If `AttachmentDefinitionAsset` is set in the editor, the component calls `LoadAttachment()` automatically on `BeginPlay`. No additional Blueprint wiring needed.

### Editor Preview

When the definition is set in the editor, the component synchronously loads all assets and applies fragments for WYSIWYG preview. Changes to the definition trigger `RefreshEditorPreview()` automatically.

## Subsystem — `UModularAttachmentSubsystem`

The Subsystem (`UWorldSubsystem`) is the **central coordinator**. One instance per `UWorld`, managing three responsibilities:

```
UModularAttachmentSubsystem
├── Asset Cache          ref-counted FStreamableHandle pool
│                        (same definition shared by N components = 1 handle)
├── Tag Registry         FGameplayTag → TArray<UModularAttachmentComponent*>
│                        (fast lookup, auto-cleans stale pointers)
└── Event Broadcast      BroadcastToTag(TargetTag, Payload)
                         (routes to all components under that tag)
```

### Three-Phase Load Pipeline

{% stepper %}
{% step %}

### Phase 1 — Stream definition asset

`FStreamableManager::RequestAsyncLoad(DefinitionPath)`
{% endstep %}

{% step %}

### Phase 2 — Stream all soft refs

`Definition→CollectAllSoftRefs()` → batch `RequestAsyncLoad`
{% endstep %}

{% step %}

### Phase 3 — Apply to component

`Fragment→ApplyToComponent()` ×N\
`Component→OnAttachmentLoadCompleted.Broadcast()`
{% endstep %}
{% endstepper %}

### Deferred Unload

When a component unloads, cleanup is scheduled on the **next tick** via `ExecuteDeferredUnload()` to prevent mid-frame destruction issues.

## Event System

Events are tag-routed packets that let fragments react to gameplay without hard-coded coupling:

```cpp
FAttachmentEventPayload Payload;
Payload.EventTag   = FGameplayTag::RequestGameplayTag("ModularAttachment.Event.Aim");
Payload.TargetTag  = FGameplayTag::RequestGameplayTag("ModularAttachment.Slot.Optic");
Payload.Instigator = OwnerActor;
Payload.Values.Add(
    FGameplayTag::RequestGameplayTag("ModularAttachment.Value.Zoom"), 4.0f
);

Subsystem->BroadcastToTag(Payload.TargetTag, Payload);
```

All components registered under `ModularAttachment.Slot.Optic` receive this event via their `OnAttachmentEvent` delegate. Fragments can inspect `EventTag` and `Values` to react accordingly.

### Event Flow

```
BroadcastToTag(TargetTag, Payload)
  │
  ├─► OnTagEventNative.Broadcast()        (C++ global listeners)
  │
  └─► For each Component under TargetTag:
        Component→OnAttachmentEvent.Broadcast(Payload)   (Blueprint-bindable)
```

## Next Steps

* [Gameplay Tags](/dante-docs/modular-attachment-system/gameplay-tags.md) — complete tag hierarchy and extension guide
* [Creating Fragments](/dante-docs/modular-attachment-system/creating-fragments.md) — C++ and Blueprint authoring
* [API Reference](/dante-docs/modular-attachment-system/api-reference.md) — full class and method signatures
