# How the SavedPlayers Module in YimMenuV2 Persists and Restores Player Data

> Discover how YimMenuV2's SavedPlayers module persists and restores player data using nlohmann::json serialization and an unordered map. Learn to manage player information efficiently.

- Repository: [YimMenu/YimMenuV2](https://github.com/YimMenu/YimMenuV2)
- Tags: how-to-guide
- Published: 2026-07-17

---

**The SavedPlayers module in YimMenuV2 persists player data to a JSON file using nlohmann::json serialization, storing Rockstar IDs, names, and flags in an unordered map that loads on initialization and saves automatically on modifications.**

The SavedPlayers subsystem in YimMenuV2 maintains a persistent record of player information across menu sessions. It tracks Rockstar IDs, usernames, modder flags, and tracking preferences in a local JSON file, ensuring user-defined player data survives between launches while keeping runtime-fetched social club data volatile.

## Data Structure and Storage Model

The persistence layer relies on two primary C++ structures defined in the backend headers.

**SavedPlayers** maintains the container and filesystem logic. In [`src/game/backend/SavedPlayers.hpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/backend/SavedPlayers.hpp) (lines 12-13), the class declares an `std::unordered_map<std::uint64_t, SavedPlayerData> m_SavedPlayers` where the Rockstar ID serves as the unique key. This unordered map provides O(1) lookup performance for player entries.

**SavedPlayerData** defines the actual payload. Located in [`src/game/backend/SavedPlayerData.hpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/backend/SavedPlayerData.hpp) (lines 45-55), this struct contains three persisted fields—`m_Name`, `m_IsModder`, and `m_TrackPlayer`—alongside the transient `m_FetchedData` member. The `m_FetchedData` field holds live social club information retrieved during gameplay and is explicitly excluded from disk storage.

Serialization is handled automatically via the **nlohmann::json** library. The `NLOHMANN_DEFINE_TYPE_INTRUSIVE` macro registers the three stored members for JSON conversion, enabling single-line serialization and deserialization without manual field mapping.

## Initialization and Loading Process

When YimMenuV2 launches, the SavedPlayers constructor establishes the storage path and immediately hydrates the internal map from disk.

In [`src/game/backend/SavedPlayers.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/backend/SavedPlayers.cpp) (lines 50-54), the constructor sets the file path to [`saved_players.json`](https://github.com/YimMenu/YimMenuV2/blob/main/saved_players.json) using `FileMgr::GetProjectFile("./saved_players.json")` and invokes `LoadImpl()`. This ensures the player database is available before any gameplay logic executes.

The `LoadImpl()` function (lines 306-325) performs the actual disk read. It checks for file existence, parses the JSON content using **nlohmann::json**, and iterates over each key-value pair. Each JSON key is converted from string to `uint64_t` Rockstar ID, with the corresponding value deserialized into a `SavedPlayerData` object inserted into `m_SavedPlayers`. Parsing exceptions are caught and logged to prevent startup crashes from corrupt JSON.

## Persistence Workflow

Modifications to player data trigger atomic writes to the JSON file through the `SaveImpl()` method.

Located in [`src/game/backend/SavedPlayers.cpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/backend/SavedPlayers.cpp) (lines 332-445), `SaveImpl()` serializes the entire `m_SavedPlayers` map back to JSON format. It opens [`saved_players.json`](https://github.com/YimMenu/YimMenuV2/blob/main/saved_players.json) with `std::ofstream` in truncation mode (`std::ios::trunc`), writes the formatted data, and ensures atomic replacement of the previous file contents. Like loading, exceptions during write operations are caught and logged rather than propagated.

**Automatic save triggers** include:
- Adding a new player via `AddPlayerDataImpl()` (lines 77-88)
- Updating a Rockstar ID or username
- Modifying player flags during `OnPlayerJoinImpl()` (lines 52-63)

## Runtime Operations and Script Integration

The module integrates with YimMenuV2's script system to maintain synchronization between stored data and live session states.

**Adding Players:** The `AddPlayerDataImpl()` method creates new `SavedPlayerData` entries and immediately calls `SaveImpl()` to persist the change. This ensures player records survive unexpected menu crashes.

**Session Join Handling:** When a player joins the current session, `OnPlayerJoinImpl()` queries the stored map using their Rockstar ID. If found, it copies the `m_IsModder` flag to the live player object and updates the stored name if it differs from the current session username, triggering a subsequent save.

**Background Fetching:** The `RunScriptImpl` loop (lines 28-39) periodically executes `FetchPlayerInfoImpl()` to retrieve fresh social club data for all saved players. This updates the runtime-only `m_FetchedData` fields without invoking `SaveImpl()`, preventing unnecessary disk writes for volatile information.

## Code Examples

### Adding a New Saved Player

```cpp
std::uint64_t rockstarId = 123456789;
std::string_view username = "BadBoyBob";

// Inserts entry and persists to saved_players.json
YimMenu::SavedPlayers::AddPlayerData(rockstarId, username);

```

### Updating Stored Player Information

```cpp
if (auto* data = YimMenu::SavedPlayers::GetPlayerData(rockstarId))
{
    data->m_Name = "NewName";
    data->m_IsModder = true;
    YimMenu::SavedPlayers::Save(); // Explicit persistence call
}

```

### Removing a Player Entry

```cpp
YimMenu::SavedPlayers::RemovePlayerData(rockstarId);
// Removal persists on next automatic save cycle

```

## Summary

- **Storage Format:** Player data persists to [`saved_players.json`](https://github.com/YimMenu/YimMenuV2/blob/main/saved_players.json) using nlohmann::json serialization via the `NLOHMANN_DEFINE_TYPE_INTRUSIVE` macro.
- **Core Container:** An `std::unordered_map<std::uint64_t, SavedPlayerData>` indexed by Rockstar ID provides fast lookups in [`src/game/backend/SavedPlayers.hpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/backend/SavedPlayers.hpp).
- **Lifecycle:** The constructor in `SavedPlayers::SavedPlayers()` triggers `LoadImpl()` to hydrate data at startup, while `SaveImpl()` atomically writes changes to disk.
- **Data Segregation:** Only `m_Name`, `m_IsModder`, and `m_TrackPlayer` persist; `m_FetchedData` remains runtime-only.
- **Integration:** Background scripts update live player info without triggering saves, while session join events automatically synchronize flags and names.

## Frequently Asked Questions

### What player data does YimMenuV2 actually save to disk?

YimMenuV2 persists the player's Rockstar ID (as the map key), display name, modder flag status, and tracking preference. According to the source in [`src/game/backend/SavedPlayerData.hpp`](https://github.com/YimMenu/YimMenuV2/blob/main/src/game/backend/SavedPlayerData.hpp), these correspond to `m_Name`, `m_IsModder`, and `m_TrackPlayer`. Live social club data stored in `m_FetchedData` is intentionally excluded from the JSON serialization.

### How does the SavedPlayers module handle corrupt JSON files?

During initialization, `LoadImpl()` wraps the JSON parsing logic in exception handling. If [`saved_players.json`](https://github.com/YimMenu/YimMenuV2/blob/main/saved_players.json) is malformed or unreadable, the catch block logs the error and continues execution with an empty player map. The module does not crash on corrupt data; it simply starts fresh and overwrites the file on the next save operation.

### When exactly does the module write to saved_players.json?

The module writes to disk immediately when `SaveImpl()` is invoked by `AddPlayerDataImpl()`, during Rockstar ID changes, or when player metadata updates in `OnPlayerJoinImpl()`. The write uses `std::ios::trunc` mode to replace the entire file atomically, ensuring data integrity even if the process terminates during the operation.

### Why does the module use Rockstar ID as the primary key?

The Rockstar ID (`uint64_t`) provides a immutable, unique identifier that persists across username changes and session switches. Using this as the unordered_map key in `m_SavedPlayers` ensures that player records remain linked to the correct account even if the player changes their display name, which is stored only as secondary metadata.