# 07 — Item Data Asset (`DA_ItemData`)

## Purpose
The single source of truth for every item in the game. Each item is represented by one `DA_ItemData` Primary Data Asset. No item data lives in Blueprint logic; all item definitions are data-driven from these assets.

**C++ Status:** ✅ Full — `Source/PG_Framework/Public/Inventory/DA_ItemData.h` + `.cpp`. All enums, structs, variables, and editor validation are implemented in C++ with `UPROPERTY` metadata (EditCondition, EditConditionHides, ClampMin/Max) for designer-friendly editor UX.

> **Concrete examples:** See [`docs/game/`](../../game/README.md) for step-by-step walkthroughs of building actual items: [Flashlight Tool](../../game/item-flashlight.md), [Pistol Weapon](../../game/item-pistol.md), [MedKit Consumable](../../game/item-medkit.md), [Keycard Key Item](../../game/item-keycard.md). Each shows exact Blueprint graphs, component lists, and verification checklists.

> **Critical distinction:** `DA_ItemData` is a **Data Asset** — it lives in the Content Browser, NOT in the level. It defines *what* an item is (name, weight, icon, effects, type). To place an item in the world, create a `BP_ItemPickup` actor (spec #25) and assign the `DA_ItemData` to it. The Data Asset is the item's *identity card*; `BP_ItemPickup` is its *physical body* in the world. See [How to Set Up](#how-to-set-up) below.

---

## How to Set Up

### Step 1 — Create the Data Asset

```
Content Browser → Framework/DataAssets/Items/
  Right-click → Miscellaneous → Data Asset
  Class: DA_ItemData
  Name: DA_Item_[ShortName]  (e.g., DA_Item_MedKit, DA_Item_RustyKey, DA_Item_Pistol)
```

### Step 2 — Fill in Core Properties

Open the Data Asset and fill in:

| Property | Purpose | Example |
|----------|---------|---------|
| `Item Tag` | **Unique identifier** — registered in `DA_GameTagRegistry` | `Framework.Item.Consumable.MedKit` |
| `Display Name` | Player-visible name | "MedKit" |
| `Description` | Flavor text / gameplay hint | "A standard medical kit. Restores 25 health." |
| `Icon` | Inventory thumbnail texture | `T_MedKit_Icon` |
| `World Mesh` | 3D mesh when dropped in world | `SM_MedKit` |
| `Weight` | Weight units for carry limit | `1.0` |
| `Stack Limit` | Max per slot (weapons = 1, ammo = 999, consumables = 5) | `5` |
| `Item Type` | Category enum — controls which sub-data to fill | `Consumable` |

### Step 3 — Fill Type-Specific Sub-Data

Based on `Item Type`, fill the relevant sub-struct (other sub-panels auto-hide via `EditCondition`):

| Item Type | Sub-Struct to Fill | Example Values |
|-----------|-------------------|-----------------|
| `Weapon` / `Tool` | `Equipment Data` | Damage=0, FireRate=0, MagazineSize=0, Slot=PrimaryWeapon |
| `Consumable` | `Consumable Data` | HealthRestore=25, UseDuration=2.0, bConsumedOnUse=true |
| `Ammo` | `AmmoData` (legacy) | AmmoTypeTag, PerPickupCount |
| `KeyItem`, `Document`, `Collectible`, `Resource`, `Misc` | None — core properties only | |

### Step 4 — Build the BP_ItemPickup Blueprint (one-time)

The Data Asset does **not** appear in the world. You need a Blueprint Actor that references it. Here is the exact setup:

#### 4.1 — Create the Blueprint

```
Content Browser → Framework/Inventory/
  Right-click → Blueprint Class → Actor
  Name: BP_ItemPickup
```

#### 4.2 — Add Components

Open `BP_ItemPickup` → **Viewport** tab → **Add Component** (top-left button):

| # | Component Class | Name | Purpose |
|---|----------------|------|---------|
| 1 | `StaticMeshComponent` | `Mesh` | Renders the item's 3D model in the world |
| 2 | `SphereComponent` | `InteractionCollision` | Detects when the player is near enough to pick up |
| 3 | *(optional)* `AudioComponent` | `PickupSound` | Plays a sound when collected |

**Select `InteractionCollision` → Details panel:**
- `Sphere Radius` → `150.0` (how close the player must be)
- Under **Collision Presets** → set to `OverlapOnlyPawn` (only the player triggers it)

#### 4.3 — Create the Config Variable

1. In the **My Blueprint** panel (left side), click **+ Variable**
2. Name: `Config`
3. Variable Type: **Struct → `S_PickupConfig`** (you may need to create this struct first — see spec #25 for its fields)

If `S_PickupConfig` doesn't exist yet, create it manually:
```
Content Browser → Framework/Inventory/
  Right-click → Blueprints → Structure
  Name: S_PickupConfig
  Add fields:
    ItemData      → Type: DA_ItemData (Object Reference)
    Quantity      → Type: Integer, default: 1
    bAutoRotate   → Type: Boolean, default: true
    bBobUpDown    → Type: Boolean, default: true
    BobAmplitude  → Type: Float, default: 10.0
    BobFrequency  → Type: Float, default: 1.0
```

4. After creating the variable, select it → Details panel:
   - **Instance Editable** → ✓ checked (so you can set it per-instance in the level)
   - **Category** → `Pickup Config`
   - **Tooltip** → "The item data asset this pickup represents"

#### 4.4 — Wire the Construction Script

Go to the **Construction Script** tab (or open the Construction Script graph). This runs every time you change the Config in the editor, so the mesh updates immediately.

```
Construction Script
  │
  ├─ Get Config → Break S_PickupConfig → ItemData
  │    │
  │    ├─ Is Valid (ItemData)?
  │    │    ├─ True → continue
  │    │    └─ False → Print String "No ItemData assigned" (Editor-only) → Return
  │    │
  │    └─ ItemData → Get World Mesh (this is a soft reference — may not be loaded)
  │         │
  │         ├─ Is Valid (WorldMesh)?
  │         │    ├─ True:
  │         │    │     → Set Static Mesh (Mesh component, New Mesh = WorldMesh)
  │         │    │     → ItemData → Get Display Name → Set Actor Label
  │         │    └─ False:
  │         │          → ItemData → World Mesh → Async Load Asset
  │         │          → On Load Complete → Set Static Mesh
  │         │
  │         └─ ItemData → Get Icon → (cache for UI prompt)
```

**Key node-by-node:**
1. Drag the `Config` variable from My Blueprint → **Get Config**
2. **Break S_PickupConfig** (right-click the pin → Split Struct Pin, or drag off → "Break")
3. From the `ItemData` pin, drag off → Create a `IsValid` node
4. From the valid `ItemData` output, drag off → type `Get World Mesh` (this appears because `WorldMesh` is a `UPROPERTY` on `DA_ItemData`; if using soft reference, you'll get a `TSoftObjectPtr<UStaticMesh>` — connect to **Async Load Asset** or **Load Synchronous** for Construction Script)
5. From the resolved mesh, connect to `Set Static Mesh` node → target is the `Mesh` component (drag Mesh from the Components panel into the graph → Get)

#### 4.5 — Wire Interaction (I_Interactable)

**Step A — Add the Interface:**
1. **Class Settings** (toolbar button) → **Interfaces** → **Add** → select `UInteractable` (the C++ interface from `I_InterfaceLibrary.h`)
2. Compile. Now `Interact`, `Can Interact`, `Get Interaction Prompt` events appear in the right-click menu.

**Step B — Wire the Events:**

```
Event Interact (from I_Interactable)
  │ Interactor: AActor*
  │
  ├─ Get Config → Break → ItemData
  │
  ├─ Interactor → Get Component by Class (BPC_InventorySystem)
  │    │
  │    └─ Is Valid?
  │         ├─ False → Return (no inventory system on interactor)
  │         └─ True → InventorySystem
  │              │
  │              ├─ Call Can Add Item(ItemData, Quantity from Config)
  │              │    │
  │              │    ├─ False → Print "Inventory Full" → Return
  │              │    └─ True:
  │              │         ├─ Call Add Item(ItemData, Quantity)
  │              │         ├─ Play Sound at Location (PickupSound, GetActorLocation)
  │              │         ├─ Destroy Actor
  │              │         └─ Return
  │              │
  │              └─ (If ItemData has bIsInfinite or respawn logic — skip Destroy)

Event Can Interact (from I_Interactable)
  │ Interactor, OutBlockReason (by ref)
  │
  ├─ Is Config.ItemData Valid?
  │    ├─ False → OutBlockReason = "No item data" → Return False
  │    └─ True → Return True

Event Get Interaction Prompt (from I_Interactable)
  │
  ├─ Get Config → ItemData → Get Display Name
  └─ Return "Pick up [ItemName]"
```

#### 4.6 — Add Bobbing Rotation (optional polish)

In **Event Graph → Event BeginPlay**:

```
Event BeginPlay
  │
  ├─ Get Config → Break → bAutoRotate
  │    └─ True → Add Timeline → name: "BobAndRotate"
  │         ├─ Update track:
  │         │    ├─ Mesh → Add World Rotation (DeltaRotation = 0,0,Timeline.Rotation * 90)
  │         │    └─ Mesh → Add World Offset (Delta = 0,0,Timeline.Bob * BobAmplitude * sin(time), ...)
  │         │
  │         └─ Timeline: float track 0→1 looping over 2 seconds
  ├─ Enable collision on InteractionCollision
  └─ Bind OnComponentBeginOverlap(InteractionCollision) → Highlight mesh, show prompt
```

#### 4.7 — Compile and Use

1. **Compile → Save**
2. **Drag `BP_ItemPickup` into your level**
3. Select the instance → Details panel → **Pickup Config → Item Data** → select `DA_Item_MedKit`
4. Set `Quantity` → `1` (or more for stacked items)
5. The **Construction Script** runs immediately — the mesh should appear in the viewport
6. Position the actor where you want it

**Verification in PIE (Play In Editor):**
- The pickup should show its mesh, slowly rotating
- Walk up to it — the overlap event fires
- Press Interact — item goes into inventory, pickup disappears
- Open inventory → item should be in a slot with the correct name and icon

```
DA_Item_MedKit (Content Browser)        ← defines IDENTITY
        ↑ referenced by
BP_ItemPickup (Actor in level)          ← physical BODY in world
  ├── StaticMeshComponent "Mesh"        ← renders WorldMesh from Data Asset
  ├── SphereComponent "Collision"       ← detects player proximity
  └── Config struct                     ← holds pointer to DA_ItemData + quantity
        ↑ interacts via
BPC_InteractionDetector → I_Interactable → BPC_InventorySystem.AddItem()
```

> **For concrete, step-by-step examples** of building specific item types (flashlight, pistol, medkit, keycard) with complete Blueprint graphs, component lists, and wiring diagrams, see the [`docs/game/`](../../game/README.md) directory.

---

## Single Identity Tag — Why One Tag Is Enough

Each item has exactly one `ItemTag` GameplayTag. This is intentional — the tag is the item's **unique identifier**, not a categorization bucket.

Categorization and behavioral flags are handled by separate, purpose-built properties:

| Concern | Mechanism | Example |
|---------|-----------|---------|
| **Identity** | `ItemTag` (single GameplayTag) | `Framework.Item.Consumable.MedKit` |
| **Category** | `ItemType` (enum) | Consumable, Weapon, KeyItem, Document, etc. |
| **Is non-droppable?** | `bIsKeyItem` (bool) | Key items are auto-protected from drop/clear |
| **Can be dropped?** | `bCanBeDropped` (bool) | Ammo/documents can be dropped; key items cannot |
| **Has 3D inspection?** | `bHasInspectMode` (bool) | Enables rotate-examine on pickup |
| **Crafting relationships** | `CombinesWith` (array of GameplayTag) | `MedKit` + `Bandage` → `SuperMedKit` |
| **Project-specific data** | `CustomProperties` (TMap<FName, FString>) | Key=`"QuestRewardID"`, Value=`"Q12"` |
| **Tag-based queries** | Hierarchical tag structure | `ItemTag.MatchesTag(Framework.Item.Consumable)` returns true for all consumables |

**Why not multiple ItemTags?**
- A single unique ID prevents ambiguity: inventory lookups, save/load references, and crafting recipes all need one canonical name for each item.
- Hierarchical GameplayTags support partial matching: `Framework.Item.Consumable.MedKit` matches `Framework.Item.Consumable` for category-wide queries.
- Adding a `FGameplayTagContainer ItemTags` would create confusion — which tag is the "real" ID? Do you check all of them? Do you sort by the first one?
- The `ItemType` enum + boolean flags + `CombinesWith` array already cover every use case without tag collision risks.

**If you truly need multiple filtering tags**, the `CustomProperties` map can store them (e.g., `"FilterTags"` → `"Flammable,Magnetic,QuestItem"`), and your BP can parse the comma-separated string at runtime. But in practice, this is rarely needed because:
- `ItemType` already categorizes items
- `bIsKeyItem` / `bCanBeDropped` already handle behavioral flags
- `CombinesWith` already handles cross-item relationships
- Hierarchical tag matching handles category queries (e.g., `MatchesTag(Framework.Item.Weapon)`)

---

## Dependencies
- **Requires:** `GameplayTag` system (`DA_GameTagRegistry`), `UPrimaryDataAsset` (engine base)
- **Required By:** `BPC_InventorySystem`, `BPC_EquipmentSlotSystem`, `BPC_ConsumableSystem`, `BPC_AmmoComponent` (70), `BPC_ItemCombineSystem`, `BPC_KeyItemSystem`, `BPC_ActiveItemSystem`
- **Engine/Plugin Requirements:** `GameplayTags`, `AssetManager` (Primary Data Asset registration)
- **Parent Class:** `UPrimaryDataAsset`

## Class Info
| Property | Value |
|----------|-------|
| **Parent Class** | `UPrimaryDataAsset` |
| **C++ Class** | `UDA_ItemData` (in `Source/PG_Framework/Public/Inventory/DA_ItemData.h`) |
| **Class Type** | Primary Data Asset |
| **Asset Path** | `Content/Framework/DataAssets/Items/DA_Item_[Name]` |
| **Implements Interfaces** | None (passive data container) | |

---

## 1. Enums

### `E_ItemType`
| Value | Description |
|-------|-------------|
| `Weapon` | Equippable weapon (melee or ranged) |
| `Ammo` | Ammunition for weapons |
| `Consumable` | Single-use health/stamina/stress item |
| `KeyItem` | Story progression gating item (non-droppable) |
| `Document` | Readable document / note / file |
| `Collectible` | Optional hidden item for completion |
| `Tool` | Equipment item (flashlight, lockpick, etc.) |
| `Resource` | Crafting / repair material |
| `Misc` | Other (quest flags, no-function items) |

---

## 2. Structs

No custom structs defined in this Data Asset class. Consumed structs from other files:

- `S_EquipmentData` (from `BPC_EquipmentSlotSystem`) — optional, if item is equippable
- `S_ConsumableData` (from `BPC_ConsumableSystem`) — optional, if item is consumable
- `S_InspectData` (from `BPC_InspectItemSystem`) — optional, if item has 3D inspect model
- `S_AmmoData` (from `BPC_AmmoResourceSystem`) — optional, if item is ammo type

---

## 3. Variables

### Instance Editable (Category: "Item Definition")

| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `ItemTag` | `GameplayTag` | `None` | Unique identifier for this item (e.g. `Item.MedKit`) |
| `DisplayName` | `FText` | `""` | Player-visible item name |
| `Description` | `FText` | `""` | Item description text |
| `Icon` | `Texture2D (Soft)` | `None` | Inventory/UI icon |
| `WorldMesh` | `StaticMesh (Soft)` | `None` | 3D mesh when dropped in world |
| `Weight` | `Float` | `0.0` | Weight units (for carry limit) |
| `StackLimit` | `Integer` | `1` | Max stack count in a single inventory slot |
| `ItemType` | `E_ItemType` | `Misc` | Item classification |
| `bIsKeyItem` | `Bool` | `false` | Protected from drop/consume/clear |
| `CombinesWith` | `Array of GameplayTag` | `Empty` | Items this can combine with (item tags) |
| `CombineResult` | `GameplayTag` | `None` | Produced item tag on successful combine |
| `CustomProperties` | `Map (Name -> String)` | `Empty` | Per-project custom data (any key-value pairs) |

### Optional Sub-Data (EditCondition / Visible if applicable)

| Variable | Type | Default | EditCondition | Description |
|----------|------|---------|---------------|-------------|
| `EquipmentData` | `S_EquipmentData` | Default | `ItemType == Weapon || ItemType == Tool` | Weapon/tool equipment properties |
| `ConsumableData` | `S_ConsumableData` | Default | `ItemType == Consumable` | Health/stamina/stress restore values |
| `InspectData` | `S_InspectData` | Default | `bHasInspectMode` | 3D inspect rotation anchors and secrets |
| `AmmoData` | `S_AmmoData` | Default | `ItemType == Ammo` | Ammo type tag and per-pickup count |

### Metadata / Editor

| Variable | Type | Default | Description |
|----------|------|---------|-------------|
| `bHasInspectMode` | `Bool` | `false` | Whether item supports 3D inspection |
| `bCanBeDropped` | `Bool` | `true` | Allow dropping from inventory |
| `AssetSearchTags` | `Array of FName` | `Empty` | Editor search keywords |

---

## 4. Functions

`DA_ItemData` is a pure data container. All properties are read directly from Blueprints that hold a reference to the asset. The following functions exist in the C++ class (`Source/PG_Framework/Public/Inventory/DA_ItemData.h`):

### Runtime (All BlueprintCallable / BlueprintPure)

| Function | Returns | Description |
|----------|---------|-------------|
| `GetResistance(DamageType)` (on `DA_EquipmentConfig`) | `float` | Returns resistance value for a damage type (armor/equipment) |
| *(All UPROPERTY reads)* | — | `ItemTag`, `DisplayName`, `ItemType`, `Weight`, `StackLimit`, etc. are read directly — no function call needed |

### Editor-Only Functions (for content team validation)

#### `ValidateItemData` → `Bool` (BlueprintCallable, Editor only)
- **C++ Implementation:** Full — `Source/PG_Framework/Private/Inventory/DA_ItemData.cpp`
- **Description:** Runs editor validation checks (tag uniqueness, required fields filled).
- **Parameters:** `OutErrors` (FString, out) — human-readable error messages
- **Flow:**
  1. Check `ItemTag != None` — if None, append error
  2. Check `DisplayName != ""` — if empty, append error
  3. If `StackLimit < 1`, append error
  4. If `bIsKeyItem` then warn if `bCanBeDropped == true`
  5. If Consumable, check at least one effect value > 0
  6. Return true if all validations pass; false if any failed

---

## 5. Event Dispatchers

None. Data Assets are passive data containers; they do not fire events.

---

## 6. Overridden Events / Custom Events

No event overrides. Data Assets do not tick or have BeginPlay.

---

## 7. Content Creation Flow

`DA_ItemData` has **no blueprint graph**. It is created and edited in the Content Browser as a Data Asset instance.

```mermaid
flowchart LR
    A[Content Browser] --> B[Right-click > Miscellaneous > Data Asset]
    B --> C[Select Class: DA_ItemData]
    C --> D[Name: DA_Item_MedKit]
    D --> E[Open Asset > Fill Properties]
    E --> F[ItemTag: Framework.Item.Consumable.MedKit]
    F --> G[DisplayName: Med Kit]
    G --> H[Set Icon, WorldMesh]
    H --> I[ItemType: Consumable]
    I --> J[Fill ConsumableData: HealthRestore=25]
    J --> K[Save Asset]
    K --> L[Ready — referenced by BP_ItemPickup actors]
```

### How Systems Use the Data Asset (Read-Only)

```mermaid
flowchart TD
    DA[DA_Item_MedKit<br/>Data Asset] -->|referenced by| PICKUP[BP_ItemPickup<br/>Actor in world]
    PICKUP -->|OnInteract| INV[BPC_InventorySystem.AddItem(DA, 1)]
    INV -->|stores reference| SLOT[FInventorySlot.Item = DA]
    
    DA -->|reads EquipmentData| EQUIP[BPC_EquipmentSlotSystem]
    DA -->|reads ConsumableData| CONSUM[BPC_ConsumableSystem]
    DA -->|reads CombinesWith| COMBINE[BPC_ItemCombineSystem]
    DA -->|reads bIsKeyItem| KEY[BPC_KeyItemSystem]
    DA -->|reads ItemType| ACTIVE[BPC_ActiveItemSystem<br/>routes to correct handler]
    
    INV -->|dispatches OnItemAdded| UI[WBP_InventoryMenu<br/>reads DisplayName, Icon, Description]
```

---

## 8. Communication Matrix

| Who Talks | How | What Is Sent |
|-----------|-----|-------------|
| `BPC_InventorySystem` | Direct asset reference | Reads `ItemTag`, `DisplayName`, `Weight`, `StackLimit`, `bIsKeyItem`, `Icon` |
| `BPC_ConsumableSystem` | Direct asset reference | Reads `ConsumableData` (HealthRestore, StressReduce, etc.) |
| `BPC_EquipmentSlotSystem` | Direct asset reference | Reads `EquipmentData` (slot type, allowed types) |
| `BPC_AmmoResourceSystem` | Direct asset reference | Reads `AmmoData` (AmmoTypeTag, PerPickupCount) |
| `BPC_ItemCombineSystem` | Direct asset reference | Reads `CombinesWith`, `CombineResult` to validate combinations |
| `BPC_ActiveItemSystem` | Direct asset reference | Reads `ItemType` to route to correct use system |
| `BPC_InspectItemSystem` | Direct asset reference | Reads `InspectData`, `bHasInspectMode` |
| `WBP_InventoryMenu` | Via `BPC_InventorySystem` | Reads `DisplayName`, `Description`, `Icon`, `ItemType` for display |
| `WBP_InteractionPromptDisplay` | Via `I_Interactable` on world pickup | Reads `DisplayName` for "Pick up [ItemName]" prompt |

---

## 9. Validation / Testing Checklist

- [ ] Each `DA_ItemData` asset has a unique `ItemTag` (no two items share the same tag)
- [ ] `DisplayName` and `Description` are non-empty for all player-facing items
- [ ] `Icon` is assigned for all items that appear in inventory UI
- [ ] `WorldMesh` is assigned for items that have a world pickup representation
- [ ] `StackLimit` >= 1 for all items
- [ ] `bIsKeyItem` items have `bCanBeDropped = false`
- [ ] Consumable items have `ConsumableData` filled with at least one effect value > 0
- [ ] Weapon/Tool items have `EquipmentData` filled with correct slot tag
- [ ] Ammo items have `AmmoData` filled with `AmmoTypeTag` and `PerPickupCount > 0`
- [ ] Combine items: both sources reference the exact result tag in `CombineResult`
- [ ] `CustomProperties` map is empty for framework-defined items; used only for project-specific extensions
- [ ] Asset is registered with Primary Asset Manager (label: `Item`)
- [ ] Asset path follows convention: `Content/Data/Items/DA_Item_[Name]`

---

## 10. Reuse Notes

- **Create one `DA_ItemData` per item.** Naming convention: `DA_Item_[ShortName]` (e.g., `DA_Item_MedKit`, `DA_Item_Flashlight`, `DA_Item_KeyCard_Omega`).
- **Data Assets are not world actors.** They cannot be dragged into a level. To place an item in the world, create a `BP_ItemPickup` actor (spec #25) and assign the `DA_ItemData` to its `Config.ItemData` property.
- All `ItemTag` values must be registered in `DA_GameTagRegistry` before use. Use the hierarchical tag structure: `Framework.Item.[Type].[Name]`.
- The `CustomProperties` map future-proofs any per-project additions without modifying the base C++ class.
- For non-stackable items (weapons, key items, tools), set `StackLimit = 1`.
- For stacks, choose a sensible `StackLimit` (e.g., ammo = 999, consumables = 5, resources = 99).
- The `AssetManager` should be configured with `PrimaryAssetType = Item` and `PrimaryAssetLabel = Item` for async loading support.
- Document items (`E_ItemType.Document`) additionally populate `BPC_DocumentArchiveSystem` with their content; the `Description` field serves as document body text.
- To add a new item property across all items, add a new `UPROPERTY` to `DA_ItemData` in C++. Do not create a separate asset class per item type — use the `ItemType` enum + `EditCondition` metadata for branching display.
- The `ValidateItemData` editor function can be exposed as a Python command for batch validation on check-in.
- **C++ EditCondition metadata** auto-hides irrelevant panels based on `ItemType` (e.g., `ConsumableData` only shows when `ItemType == Consumable`). Designers never see irrelevant fields.
- **Inventory systems interact with `DA_ItemData` through C++ `TObjectPtr<UDA_ItemData>`** references — the Data Asset is never copied, only referenced by pointer. All inventory operations pass the `DA_ItemData*` pointer.

---

## Multiplayer Networking

**Replication: None needed.** `DA_ItemData` is a PrimaryDataAsset — read-only configuration loaded identically on all clients. No runtime state.

**Authority: N/A.** All clients load the same asset data from disk. Inventory operations that reference item data are server-authoritative (see `BPC_InventorySystem`).

---

*Blueprint Spec v1.0 — DA_ItemData for UE5.5-5.7*