> 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/modular-attachment-subsystem.md).

# Modular Attachment Subsystem

**Header:** `ModularAttachmentSystem/Subsystem/ModularAttachmentSubsystem.h`\
**Module:** `ModularAttachmentSystem`\
**Parent:** `UWorldSubsystem`\
**Specifiers:** *(none — not Blueprintable)*

## Overview

`UModularAttachmentSubsystem` is the **central coordinator** for the Modular Attachment System. It is a `UWorldSubsystem`, meaning:

* **One instance per world** — automatically created when the world initializes, destroyed on teardown
* **Accessible from anywhere** with world context — `GetWorld()->GetSubsystem<UModularAttachmentSubsystem>()`
* **No manual initialization** — the engine manages its lifetime

The subsystem has 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)
```

## Accessing the Subsystem

### C++

```cpp
UModularAttachmentSubsystem* Sub = GetWorld()->GetSubsystem<UModularAttachmentSubsystem>();
```

### Blueprint

Use the engine's built-in **Get World Subsystem** node with class set to `ModularAttachmentSubsystem`.

### From a Component

Components access the subsystem internally via a private `GetSubsystem()` helper. You rarely need to call the subsystem directly — the component API (`LoadAttachment`, `SwapAttachment`, etc.) wraps it.

##

## Methods — Asset Streaming

### `RequestLoad`

```cpp
void RequestLoad(const TSoftObjectPtr<UModularAttachmentDefinition>& DefinitionAsset,
                 UModularAttachmentComponent* Component);
```

Starts the three-phase pipeline for the given definition. Behavior depends on current cache state:

| Cache State  | Behavior                                                        |
| ------------ | --------------------------------------------------------------- |
| Not in cache | Create entry, start Phase 1, add component to Waiters           |
| `Loading`    | Increment RefCount, add component to Waiters (deduped)          |
| `Loaded`     | Increment RefCount, call `OnAttachmentLoadFinished` immediately |

### `ReleaseLoad`

```cpp
void ReleaseLoad(const TSoftObjectPtr<UModularAttachmentDefinition>& DefinitionAsset,
                 UModularAttachmentComponent* Component);
```

Decrements the ref count and removes the component from Waiters. When RefCount reaches 0, schedules `ExecuteDeferredUnload` on the next tick.

> The deferred unload design prevents issues where a component unloads and another component immediately re-requests the same definition in the same frame.

## Next Steps

* [UModularAttachmentComponent](/dante-docs/modular-attachment-system/modular-attachment-component.md) — the mount point that communicates with this subsystem
* [UModularAttachmentDefinition](/dante-docs/modular-attachment-system/modular-attachment-definition.md) — the data assets cached by this subsystem
* [Gameplay Tags](/dante-docs/modular-attachment-system/gameplay-tags.md) — the tag hierarchy used for registration and event routing
