feat: Add Blueprint Limitations & Workarounds documentation and update GameTagRegistry spec
This commit is contained in:
@@ -54,16 +54,16 @@ None. The registry is a flat collection of tag declarations.
|
||||
|
||||
| Name | Inputs | Outputs | Category | Description |
|
||||
|------|--------|---------|----------|-------------|
|
||||
| `GetAllRegisteredTags` | — | `Array<FGameplayTag>` | Query | Returns all tags defined in this registry (reads from the project's tag table) |
|
||||
| `GetTagDisplayName` | `Tag: FGameplayTag` | `FText` | Query | Returns the human-readable display name from the tag table |
|
||||
| `ValidateTag` | `Tag: FGameplayTag` | `bool` | Validation | Returns `true` if the tag exists in the project's registered tag table |
|
||||
| `GetAllRegisteredTags` | — | `Array<FGameplayTag>` | Query | Reads tags from `DT_ProjectTags` Data Table (see Section 14 for UE5 BP workaround) |
|
||||
| `GetTagDisplayName` | `Tag: FGameplayTag` | `Text` | Query | Returns the human-readable display name via `Get Tag Display Name` node |
|
||||
| `ValidateTag` | `Tag: FGameplayTag` | `Boolean` | Validation | Returns `true` if the tag is valid via `Is Gameplay Tag Valid` node |
|
||||
|
||||
### 6.2 Blueprint Callable Functions
|
||||
|
||||
| Name | Inputs | Outputs | Category | Description |
|
||||
|------|--------|---------|----------|-------------|
|
||||
| `LogAllTags` | — | — | Debug | Prints all registered tags to the output log (Editor-only) |
|
||||
| `ExportTagNamespace` | `NamespacePrefix: FString` | `FString` | Tooling | Exports all tags matching a namespace prefix as a formatted string (for documentation generation) |
|
||||
| `LogAllTags` | — | — | Debug | Prints all tags (from Data Table) to the output log (Editor-only) |
|
||||
| `ExportTagNamespace` | `NamespacePrefix: String` | `String` | Tooling | Exports all tags matching a namespace prefix as a formatted string | |
|
||||
|
||||
---
|
||||
|
||||
@@ -75,17 +75,82 @@ None. This Data Asset is passive — it has no runtime events.
|
||||
|
||||
## 8. Overridden Events
|
||||
|
||||
| Event | Description |
|
||||
|-------|-------------|
|
||||
| `OnAssetLoaded` | Logs a validation warning if no Gameplay Tags are registered in the project |
|
||||
| `PreSaveGameplayTags` | Ensures the tag table is synchronised with the asset's documented namespaces |
|
||||
**Note:** Data Assets do NOT have `BeginPlay`, `Tick`, or `OnAssetLoaded` in Blueprint. All validation logic should be called externally from a GameInstance or Subsystem during initialization.
|
||||
|
||||
---
|
||||
### Initialization Pattern (called externally):
|
||||
```
|
||||
[In GI_GameFramework.Init() or BPC_StateManager.BeginPlay:]
|
||||
├─► Load DA_GameTagRegistry (hard reference or Get Data Asset)
|
||||
├─► Call DA_GameTagRegistry.GetAllRegisteredTags()
|
||||
├─► Array Length == 0?
|
||||
│ ├─► Yes → Print Warning: "No tags in DT_ProjectTags! Framework tags are unregistered."
|
||||
│ └─► No → Log: "N tags registered."
|
||||
└─► Optional: call LogAllTags() for debug output
|
||||
```
|
||||
|
||||
## 9. Blueprint Graph Logic
|
||||
|
||||
### 9.1 Initialisation Flow
|
||||
### 9.1 GetAllRegisteredTags (Data Table Proxy)
|
||||
|
||||
**⚠️ UE5 Limitation:** `UGameplayTagsManager::RequestAllGameplayTags()` is C++ only — not exposed to Blueprints. This function uses a **Data Table proxy** instead. Tags must be registered in `DT_ProjectTags` which mirrors `DefaultGameplayTags.ini`.
|
||||
|
||||
```
|
||||
[Function: GetAllRegisteredTags] → Array<GameplayTag>
|
||||
Step 1: Get Data Table Row Names (DT_ProjectTags)
|
||||
Step 2: Create empty Array<GameplayTag> → LocalTags
|
||||
Step 3: ForEachLoop (RowNames):
|
||||
├─► Get Data Table Row (DT_ProjectTags, RowName)
|
||||
│ → Break the GameplayTagTableRow struct → get "Tag" field
|
||||
├─► Add "Tag" to LocalTags array
|
||||
Step 4: Return LocalTags
|
||||
```
|
||||
|
||||
**Node Search:** `Get Data Table Row Names`, `ForEachLoop`, `Get Data Table Row`, `Break GameplayTagTableRow`, `Add`
|
||||
|
||||
### 9.2 ValidateTag
|
||||
|
||||
**⚠️ UE5 Limitation:** `UGameplayTagsManager::RequestGameplayTag()` is not a direct Blueprint node. Use `Is Gameplay Tag Valid` instead.
|
||||
|
||||
```
|
||||
[Function: ValidateTag(Tag)] → Boolean
|
||||
Step 1: Is Gameplay Tag Valid (Tag)
|
||||
├─► True → Return true
|
||||
└─► False → Print Warning: "Invalid Tag: {Get Tag Name(Tag)}" → Return false
|
||||
```
|
||||
|
||||
**Node Search:** `Is Gameplay Tag Valid`, `Get Tag Name`
|
||||
|
||||
### 9.3 GetTagDisplayName
|
||||
|
||||
```
|
||||
[Function: GetTagDisplayName(Tag)] → Text
|
||||
Step 1: Get Tag Display Name (Tag) → Return
|
||||
```
|
||||
|
||||
**Node Search:** `Get Tag Display Name` (Blueprint pure node, available)
|
||||
|
||||
### 9.4 LogAllTags
|
||||
|
||||
```
|
||||
[Function: LogAllTags] (Blueprint Callable)
|
||||
Step 1: GetAllRegisteredTags() → Store in LocalTags
|
||||
Step 2: ForEachLoop (LocalTags):
|
||||
├─► Get Tag Name → ToString → Print String
|
||||
Step 3: Print String: "Total tags: {Array Length(LocalTags)}"
|
||||
```
|
||||
|
||||
### 9.5 ExportTagNamespace(Prefix: String) → String
|
||||
|
||||
```
|
||||
[Function: ExportTagNamespace]
|
||||
Step 1: GetAllRegisteredTags() → LocalTags
|
||||
Step 2: Create empty String → Output
|
||||
Step 3: ForEachLoop (LocalTags):
|
||||
├─► Get Tag Name → ToString → TagString
|
||||
├─► Branch: Does TagString start with Prefix?
|
||||
│ True → Append TagString + "\n" to Output
|
||||
└─► Continue
|
||||
Step 4: Return Output
|
||||
```
|
||||
[OnAssetLoaded]
|
||||
└─► Call GetAllRegisteredTags()
|
||||
@@ -179,104 +244,151 @@ This asset does not talk to other systems directly. All communication is passive
|
||||
|
||||
## 14. Manual Implementation Guide
|
||||
|
||||
> **For human implementer:** Follow these steps to build `DA_GameTagRegistry` in UE5.
|
||||
> **For human implementer:** Follow these steps to build `DA_GameTagRegistry` in UE5 Blueprints.
|
||||
> **⚠️ UE5 BP Limitation:** `UGameplayTagsManager::RequestAllGameplayTags()` is C++ only. This implementation uses a **Data Table proxy** (`DT_ProjectTags`) as the 100% Blueprint workaround. You must create and maintain `DT_ProjectTags` alongside your `DefaultGameplayTags.ini`.
|
||||
|
||||
### 14.0 Prerequisite: Create the Tag Data Table
|
||||
|
||||
Before implementing the Data Asset, create the proxy Data Table:
|
||||
|
||||
1. Right-click in Content Browser → **Miscellaneous → Data Table**
|
||||
2. Row Structure: `GameplayTagTableRow`
|
||||
3. Name: `DT_ProjectTags`
|
||||
4. Save to: `Content/Framework/Core/`
|
||||
5. Add rows: one per tag (row name = anything, fill the "Tag" field with your GameplayTag)
|
||||
6. Go to **Project Settings → GameplayTags → Gameplay Tag Table List** → click `+` → select `DT_ProjectTags`
|
||||
- This auto-registers these tags with the engine's tag manager.
|
||||
|
||||
### 14.1 Class Setup
|
||||
|
||||
1. Right-click in Content Browser → **Miscellaneous → Data Asset**
|
||||
2. Select parent class: `PrimaryDataAsset`
|
||||
2. Select parent class: `PrimaryDataAsset`
|
||||
3. Name: `DA_GameTagRegistry`
|
||||
4. Save to: `Content/Framework/Core/`
|
||||
|
||||
### 14.2 Variables
|
||||
|
||||
Add to Class Defaults:
|
||||
| Variable | Type | Instance Editable | Default |
|
||||
|----------|------|------------------|---------|
|
||||
| `TagNamespace` | `Text` | ✓ | *Framework tag namespace description* |
|
||||
| `bIsFrameworkTag` | `Boolean` | ✓ | `true` |
|
||||
|
||||
There are NO tag entries stored in this asset. Tags live in `Project Settings → GameplayTags` or `DefaultGameplayTags.ini`.
|
||||
| Variable | Type | Instance Editable | Default | Category |
|
||||
|----------|------|------------------|---------|----------|
|
||||
| `TagNamespace` | `Text` | ✓ | *"Framework tag namespace documentation"* | Documentation |
|
||||
| `bIsFrameworkTag` | `Boolean` | ✓ | `true` | Documentation |
|
||||
| `TagDataTable` | `Data Table` (Object Reference) | ✓ | `DT_ProjectTags` | Config |
|
||||
|
||||
### 14.3 Function Implementations
|
||||
|
||||
#### `GetAllRegisteredTags` → `Array of GameplayTag`
|
||||
#### `GetAllRegisteredTags()` → `Array<GameplayTag>` *(Blueprint Pure)*
|
||||
|
||||
**Purpose:** Returns every tag registered in the project.
|
||||
**Purpose:** Returns all tags from the Data Table proxy. This replaces the C++-only `UGameplayTagsManager::RequestAllGameplayTags()`.
|
||||
|
||||
**Nodes to Use (Blueprint Implementable Function):**
|
||||
**Node-by-Node Logic:**
|
||||
```
|
||||
[Function: GetAllRegisteredTags]
|
||||
└─ Get All Gameplay Tags (from GameplayTags subsystem)
|
||||
└─ Return the array
|
||||
[Function: GetAllRegisteredTags] (Pure, no execution pins)
|
||||
Step 1: Get Data Table Row Names (TagDataTable) → returns Array<Name>
|
||||
Step 2: Create empty Array<GameplayTag> → LocalTags
|
||||
Step 3: ForEachLoop over RowNames:
|
||||
├─► Get Data Table Row (TagDataTable, Array Element)
|
||||
│ → Struct Pin: Break GameplayTagTableRow
|
||||
│ → Get "Tag" field (type: GameplayTag)
|
||||
├─► Add "Tag" to LocalTags array
|
||||
Step 4: Return LocalTags
|
||||
```
|
||||
|
||||
**Node Search:** Right-click → "Get All Gameplay Tags"
|
||||
**Nodes to Search:** `Get Data Table Row Names`, `ForEachLoop`, `Get Data Table Row`, `Break GameplayTagTableRow`, `Add`, `Array`
|
||||
|
||||
#### `GetTagDisplayName(Tag)` → `Text`
|
||||
**⚠️ Note:** Since this is a **Pure** function, the ForEachLoop must be inside a **Pure function graph** (which supports loops in UE5). If your UE version doesn't support loops in Pure functions, make this a **BlueprintCallable** (impure) function instead.
|
||||
|
||||
**Nodes to Use (Blueprint Pure):**
|
||||
#### `GetTagDisplayName(Tag: GameplayTag)` → `Text` *(Blueprint Pure)*
|
||||
|
||||
**Node-by-Node Logic:**
|
||||
```
|
||||
[Function: GetTagDisplayName]
|
||||
Input Tag → Get Tag Display Name (from GameplayTags)
|
||||
└─ Return the text
|
||||
Input Tag → Get Tag Display Name (Tag) → Return
|
||||
```
|
||||
|
||||
**Node Search:** Right-click → "Get Tag Display Name"
|
||||
**Node Search:** `Get Tag Display Name` — this IS available in Blueprint (part of GameplayTags plugin).
|
||||
|
||||
#### `ValidateTag(Tag)` → `Boolean`
|
||||
#### `ValidateTag(Tag: GameplayTag)` → `Boolean` *(Blueprint Pure)*
|
||||
|
||||
**Nodes to Use (Blueprint Pure / Callable):**
|
||||
**⚠️ UE5 Limitation:** `UGameplayTagsManager::RequestGameplayTag()` is not directly available in BP. Use `Is Gameplay Tag Valid` instead.
|
||||
|
||||
**Node-by-Node Logic:**
|
||||
```
|
||||
[Function: ValidateTag]
|
||||
Input Tag → Is Valid Tag (from GameplayTags)
|
||||
Branch on result:
|
||||
True → Return true
|
||||
False → Print Warning: "Invalid Tag: {Tag}" → Return false
|
||||
Step 1: Is Gameplay Tag Valid (Tag)
|
||||
├─► True → Return true
|
||||
└─► False → Print Warning: "Invalid Tag: " + Get Tag Name(Tag) → Return false
|
||||
```
|
||||
|
||||
**Node Search:** Right-click → "Is Gameplay Tag Valid"
|
||||
**Node Search:** `Is Gameplay Tag Valid`, `Get Tag Name`
|
||||
|
||||
#### `LogAllTags` → *(void)*
|
||||
**⚠️ Note:** `Is Gameplay Tag Valid` returns true only if the tag is registered in the engine's tag table (which `DT_ProjectTags` populates via Project Settings). Tags NOT in the table will return false.
|
||||
|
||||
**Blueprint Callable — Editor Only:**
|
||||
#### `LogAllTags()` → *(void)* *(Blueprint Callable)*
|
||||
|
||||
**Editor Only.** Prints all tags from the Data Table to the output log.
|
||||
|
||||
**Node-by-Node Logic:**
|
||||
```
|
||||
[Function: LogAllTags]
|
||||
├─ Get All Gameplay Tags → ForEachLoop
|
||||
│ └─ Print String: Tag.ToString()
|
||||
└─ Print String: "Total tags: {Array Length}"
|
||||
Step 1: Call GetAllRegisteredTags() → LocalTags
|
||||
Step 2: ForEachLoop (LocalTags):
|
||||
├─► Get Tag Name (Array Element) → ToString → Print String
|
||||
Step 3: Print String: "Total tags: " + Array Length(LocalTags)
|
||||
```
|
||||
|
||||
**Node Search:** Right-click → "ForEachLoop", "Print String"
|
||||
**Node Search:** `ForEachLoop`, `Get Tag Name`, `ToString (String)`, `Print String`, `Array Length`
|
||||
|
||||
#### `ExportTagNamespace(NamespacePrefix)` → `String`
|
||||
#### `ExportTagNamespace(NamespacePrefix: String)` → `String` *(Blueprint Callable)*
|
||||
|
||||
**Blueprint Callable:**
|
||||
**Node-by-Node Logic:**
|
||||
```
|
||||
[Function: ExportTagNamespace]
|
||||
├─ Get All Gameplay Tags
|
||||
├─ ForEachLoop:
|
||||
│ └─ Get Tag Name → ToString
|
||||
│ └─ Does string start with NamespacePrefix?
|
||||
│ True → Append to output string with newline
|
||||
└─ Return output string
|
||||
Step 1: Call GetAllRegisteredTags() → LocalTags
|
||||
Step 2: Create String variable → Output = ""
|
||||
Step 3: ForEachLoop (LocalTags):
|
||||
├─► Get Tag Name (Array Element) → ToString → TagString
|
||||
├─► Branch: Does TagString start with NamespacePrefix? (use "Starts With" string node)
|
||||
│ True → Append TagString + "\n" to Output (use "Append" or "Build String")
|
||||
└─► Continue
|
||||
Step 4: Return Output
|
||||
```
|
||||
|
||||
### 14.4 Networking
|
||||
**Node Search:** `Starts With (String)`, `Append`, `Build String`, `ForEachLoop`
|
||||
|
||||
No replication needed. This is a read-only Data Asset. All clients load identical copies from disk.
|
||||
### 14.4 External Initialization
|
||||
|
||||
### 14.5 Blueprint Build Checklist
|
||||
Since Data Assets have no `BeginPlay`, call validation from your GameInstance or StateManager:
|
||||
|
||||
- [ ] Create Data Asset: `DA_GameTagRegistry` (Parent: `PrimaryDataAsset`)
|
||||
- [ ] Add `TagNamespace` (Text) and `bIsFrameworkTag` (Bool) variables
|
||||
- [ ] Implement `GetAllRegisteredTags` function (Pure)
|
||||
- [ ] Implement `GetTagDisplayName` function (Pure)
|
||||
- [ ] Implement `ValidateTag` function (Pure)
|
||||
- [ ] Implement `LogAllTags` (Editor-only)
|
||||
- [ ] Implement `ExportTagNamespace` (Tooling)
|
||||
- [ ] Document all tag namespaces in the asset's Description field (use Section 10 as reference)
|
||||
- [ ] Verify: all tag namespaces from Section 10 exist in `DefaultGameplayTags.ini`
|
||||
**In `GI_GameFramework.Init()` or `BPC_StateManager.BeginPlay()`:**
|
||||
```
|
||||
Step 1: Get DA_GameTagRegistry (hard reference or Load Asset)
|
||||
Step 2: Call DA_GameTagRegistry.GetAllRegisteredTags() → LocalTags
|
||||
Step 3: Branch: Array Length(LocalTags) == 0
|
||||
├─► True → Print Warning: "No tags in DT_ProjectTags!"
|
||||
└─► False → Print String: "N tags registered: " + Array Length
|
||||
Step 4: [Debug builds only] Call DA_GameTagRegistry.LogAllTags()
|
||||
```
|
||||
|
||||
### 14.5 Networking
|
||||
|
||||
No replication needed. This is a read-only Data Asset with a read-only Data Table reference. All clients load identical copies from disk.
|
||||
|
||||
### 14.6 Blueprint Build Checklist
|
||||
|
||||
- [ ] Create Data Table `DT_ProjectTags` (Row Structure: `GameplayTagTableRow`)
|
||||
- [ ] Populate `DT_ProjectTags` with all framework tags from Section 10
|
||||
- [ ] Add `DT_ProjectTags` to `Project Settings → GameplayTags → Gameplay Tag Table List`
|
||||
- [ ] Create Data Asset `DA_GameTagRegistry` (Parent: `PrimaryDataAsset`)
|
||||
- [ ] Add variables: `TagNamespace` (Text), `bIsFrameworkTag` (Boolean), `TagDataTable` (Data Table Ref → DT_ProjectTags)
|
||||
- [ ] Implement `GetAllRegisteredTags` using Data Table Row iteration
|
||||
- [ ] Implement `GetTagDisplayName` using `Get Tag Display Name` node
|
||||
- [ ] Implement `ValidateTag` using `Is Gameplay Tag Valid` node
|
||||
- [ ] Implement `LogAllTags` (editor-only, prints all tags)
|
||||
- [ ] Implement `ExportTagNamespace` (string prefix filtering)
|
||||
- [ ] Add external initialization call from `GI_GameFramework.Init()` or `BPC_StateManager.BeginPlay()`
|
||||
- [ ] Verify: all tags from Section 10 exist in `DT_ProjectTags`
|
||||
- [ ] Verify: `ValidateTag` returns true for registered tags, false for unregistered
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user