Save & load
One call each way, JSON on disk, and enough engineering underneath that a crash mid-write can't eat a save.
The one-liners
inventory.SaveInventory(); // default file for this inventory type inventory.LoadInventory(); inventory.SaveInventory("checkpoint_3"); // or name the file yourself inventory.LoadInventory("checkpoint_3");
The same pair exists on grid, slot, hotbar, and equipment controllers. Each inventory type writes into its own subfolder:
{Application.persistentDataPath}/InventorySaves/
├── Player/
│ ├── inventory_player.json ← grid default
│ ├── slotinventory_player.json ← slot/hotbar default
│ ├── equipment_player.json ← equipment default
│ └── autosave_player.json ← written by Auto Save
├── Shop/…
└── Stash/…
# Windows: %userprofile%/AppData/LocalLow/<Company>/<Product>/InventorySavesWhat gets saved
Per item: the ItemID, grid position (or slot index), rotation, stack count, condition, and custom name — plus the grid dimensions and a format version for the file itself. Item definitions are not serialized; they're re-resolved from the ID on load.
Resources.LoadAll<ItemData>(""), so ItemData assets belong under a Resources/ folder and need unique IDs — a duplicate ID means "first found wins." An item whose ID can't be resolved is skipped silently.using InventorySystem; // Replace the Resources scan with your own lookup (per controller family): SlotInventoryController.ItemDataResolver = id => MyItemCatalog.Find(id); EquipmentController.ItemDataResolver = id => MyItemCatalog.Find(id); // Created ItemData at runtime? Invalidate the session cache: ItemDataCache.Clear();
Crash-safe by construction
Every write is atomic, and every load self-heals:
| Guarantee | Description |
|---|---|
| Atomic writes | Data goes to a .tmp file first, the previous save is demoted to .bak, then the temp is promoted. A crash mid-write leaves the old save intact. |
| Backup recovery | If the live .json is missing, empty, or corrupted, loading falls back to the .bak automatically (with a console warning). |
| Version migration | v1-format saves from the original release load transparently; files from a newer asset version log a warning and load best-effort. |
| Hostile-data sanitizing | Corrupted fields are clamped on load (stack counts below 1 become 1, negative positions reset); items that no longer fit the current grid are relocated to free cells or skipped with a log. |
Auto-save & timestamped saves
Tick Auto Save on any controller and it writes autosave_<type>.json every Auto Save Interval seconds (default 30) while playing. For manual checkpoints, the controller's context menu (⋮) offers Save (Timestamped) — files like player_20260716_143012.json — and Load Most Recent.
Managing save files from code
using InventorySystem; var saves = new SaveSystem(); // default directory string[] files = saves.GetSaveFiles(); // names, no extension bool ok = saves.SaveFileExists("checkpoint_3"); var info = saves.GetSaveFileInfo("checkpoint_3"); // times + size saves.CreateBackup("checkpoint_3"); // → checkpoint_3_backup.json saves.DeleteSave("checkpoint_3"); // also removes .bak/.tmp companions