# Saving the Inventory

> Save the inventory in your game's own Save Game. The plugin saves nothing itself: Export Snapshot hands over each stack with its place, state and belt slot, and Import Snapshot puts it all back.

Markdown version of https://rigbak.com/docs/universal-player-combat/inventory-saving, a page of the Universal Player Combat documentation. Link that page when citing it.

## Set it up (5 minutes)

1. **Make a Save Game**

   Create `BP_MySaveGame`, a Blueprint child of **Save Game**, with a variable `Inventory` of type **UPC Inventory Snapshot**.
2. **Save and load in the player controller**

   In `BP_UPC_PlayerController` (or your own), save on K and load on L:

   Blueprint graph, nodes in reading order:

   - **Comment box: Player controller Blueprint · K saves the inventory**

     - **K** (event); outputs: Pressed, Released, Key
     - **Get Controlled Pawn** (pure function); inputs: Target = self; outputs: Return Value
     - **Get Component by Class** (pure function); inputs: Target, Component Class = UPC Inventory; outputs: Return Value
     - **Export Snapshot** (function; Target is UPC Inventory); inputs: Target; outputs: Return Value
     - **Create Save Game Object** (function); inputs: Save Game Class = BP_MySaveGame; outputs: Return Value
     - **SET** (function; Target is BP My Save Game); inputs: Target, Inventory
     - **Save Game to Slot** (function); inputs: Save Game Object, Slot Name = Slot0, User Index = 0; outputs: Return Value

   Blueprint graph, nodes in reading order:

   - **Comment box: Player controller Blueprint · L loads it**

     - **L** (event); outputs: Pressed, Released, Key
     - **Load Game from Slot** (function); inputs: Slot Name = Slot0, User Index = 0; outputs: Return Value
     - **Cast To BP_MySaveGame** (function); inputs: Object; outputs: Cast Failed, As BP My Save Game
     - **Get Controlled Pawn** (pure function); inputs: Target = self; outputs: Return Value
     - **Get Component by Class** (pure function); inputs: Target, Component Class = UPC Inventory; outputs: Return Value
     - **Inventory** (pure function); inputs: Target; outputs: Inventory
     - **Import Snapshot** (function; Target is UPC Inventory); inputs: Target, Snapshot
3. **Press Play, save, and load**

   In `LVL_UPC_Demo`, press F at the hallway loot chest, draw a weapon and press K. Stop, press Play again and press L: the same items return in the same places, belt slots and hand. The chest is full again, since only the player's inventory was saved.

---

## Which stash a snapshot holds

The demo's **Stash** is a container of the player's inventory, so the player's snapshot saves it with everything else. A stash on a [loot chest](https://rigbak.com/docs/universal-player-combat/loot-chests) or any actor with a **UPC World Inventory** is different: it keeps its items in its own inventory, which exports and imports with its own snapshot (no belt slots, nothing in hand). A level save keeps one snapshot per such chest; the quick start's player snapshot leaves them out.

---

## When to save and load

Both nodes run on the server (your one machine in single player).

- **Save** while the controller still possesses the character, so the snapshot holds belt slots; on death, save before it unpossesses.
- **Load** from the player controller's **On Possess** or later (a load menu). The character's **Event Possessed** is too early: it runs before the belt binds, so no belt slots restore.
- **A load replaces** everything the inventory holds, and the inventory then skips its **Starting Items**, even when the load runs before Begin Play (an On Possess load at map start does).

---

## Keep old saves working

When you move or rename an item asset, keep its redirector or add a CoreRedirect, so older saves still find it. The import leaves out an item that fails to load, and one warning names every such path. A changed config or a lower **Max Stack Size** needs nothing from you: an item whose saved place is gone or taken goes to the first free place in its container, or past its end with a warning. A stack saved larger than its item's Max Stack Size comes back as several (20 arrows saved, then a Max Stack Size of 10, load as two stacks of 10). A saved container the config no longer lists sends its rows to the first carried container that takes new items.

---

## Debug it

`LogUPCInventory` warns when an import finds no belt for its slots (call from On Possess or later), when saved items fail to load (each path named), and when a row sits past a container's end.

<details>
<summary>What an import does (Advanced)</summary>

1. The belt empties and every stack leaves (a bag's items before the bag, so nothing spills); anything drawn is put away except the unarmed fallback.
2. Each row returns with exactly its saved stat tags, in its saved place when that still exists, is allowed and is free; a bag returns before its rows.
3. The belt takes its saved slots in one change, within each slot's Filter and copy limit; with **Auto Populate from Inventory** each item takes its saved slot, not the first free one.
4. Each drawn row is drawn at once, without animation, into its saved places, the moveset carrier first.

- Rules and Access Tags never turn a saved item away; status tags such as Encumbered follow from the result.
- The snapshot holds the inventory's own items only: it leaves out an item a belt slot or the hand held from outside the inventory, which an import puts away, and a belt slot's wish to bring an item back once its place frees.
- A bag's rows return in the bag's container under its current Container Tag; if the bag is gone or lost its Container fragment, they go to the first carried container taking new items.

</details>

<details>
<summary>What a snapshot holds (Advanced)</summary>

A **UPC Inventory Snapshot** holds one row per stack:

| Field | Holds |
| --- | --- |
| **Item** | The item, saved by asset path and loaded again on import. |
| **Count** | Units in the stack. |
| **Stat Tags** | The stack's own state, such as durability or charges. |
| **Placement** | Container, place and turn; place -1 for an item the belt or hand held outside its container. |
| **Bag Row** | For a stack in a bag, the bag's row; else -1. |
| **Belt Slot** | Its belt slot, or -1. |
| **Drawn**, **Places**, **Combat Driver** | In hand or worn, the body places taken (right ring, not left), and whether it carried the moveset. |

</details>

<details>
<summary>What runs where (Multiplayer)</summary>

Export and import run on the server; the owning player's belt, hand and inventory screen follow about a round trip later. A client asking to save sends its own server call to whatever runs the save on the server.

</details>

<details>
<summary>C++</summary>

```cpp
SaveGame->Inventory = Inventory->ExportSnapshot();          // UPROPERTY(SaveGame) FUPCInventorySnapshot Inventory;
UGameplayStatics::SaveGameToSlot(SaveGame, TEXT("Slot0"), 0);

UMySaveGame* Loaded = Cast<UMySaveGame>(UGameplayStatics::LoadGameFromSlot(TEXT("Slot0"), 0));
Inventory->ImportSnapshot(Loaded->Inventory);
```

- `FUPCInventorySnapshot` holds `TArray<FUPCInventorySnapshotEntry> Entries`; every field carries the `SaveGame` flag. In an `OnPossess` override, call `ImportSnapshot` after `Super::OnPossess`, which binds the belt.

</details>

---

Previous page: [Inventory Screens](https://rigbak.com/docs/universal-player-combat/inventory-screens). Next page: [Inventory Rules and Combines in Blueprint](https://rigbak.com/docs/universal-player-combat/inventory-blueprint)
