Skip to content

GlobalVault

The GlobalVault table provides a cross-server item storage system, allowing players to deposit items on one server and withdraw them on another. Each row represents a single vault slot containing serialized item data, enabling inventory persistence across the entire QS-Bridge cluster.


Scope

🌍 Global — Vault contents are accessible from any server in the cluster. A player can deposit items on server A and retrieve them on server B.


Schema

Column Type Constraints Description
vault_id u64 Primary Key, auto-increment Unique identifier for this vault entry
player_id String Indexed Platform-wide player identifier who owns the vault slot
item_data String Serialized item data (JSON format)
slot u32 Vault slot number for ordering and UI display
deposited_at Timestamp When the item was deposited into the vault
source_server_id String The server_id of the server where the item was deposited

Rust Definition

#[spacetimedb::table(public, name = global_vault)]
pub struct GlobalVault {
    #[primary_key]
    #[auto_inc]
    pub vault_id: u64,
    #[index(btree)]
    pub player_id: String,
    pub item_data: String,
    pub slot: u32,
    pub deposited_at: Timestamp,
    pub source_server_id: String,
}

Usage Patterns

Game-Agnostic Item Serialization

The item_data column stores item information as a JSON string. The platform layer does not parse, validate, or interpret this data — it is treated as an opaque payload. The game-specific sub-database and game hook are responsible for serialization and deserialization.

Example item_data payload (game-specific — format varies by game hook):

{
  "item_id": "iron_sword",
  "quantity": 1,
  "durability": 0.85,
  "enchantments": ["sharpness_3"],
  "custom_name": "Excalibur"
}

This design preserves the platform's game-agnostic architecture. The GlobalVault table can store items from any game without schema changes.

Deposit Flow

  1. Player opens the vault UI on server A.
  2. Game hook serializes the selected item to JSON.
  3. Item is removed from the player's in-game inventory.
  4. A new GlobalVault row is inserted with the serialized data.
  5. The insertion is confirmed via subscription callback.
// Pseudocode — vault deposit
fn deposit_item(player_id: &str, item: &GameItem, slot: u32, server_id: &str) {
    let item_data = serde_json::to_string(item).unwrap();
    GlobalVault::insert(GlobalVault {
        vault_id: 0, // auto-incremented
        player_id: player_id.to_string(),
        item_data,
        slot,
        deposited_at: Timestamp::now(),
        source_server_id: server_id.to_string(),
    });
}

Withdrawal Flow

  1. Player opens the vault UI on server B.
  2. Game hook queries the player's vault slots.
  3. Player selects an item to withdraw.
  4. Game hook deserializes the item_data JSON and creates the in-game item.
  5. The GlobalVault row is deleted.

Slot Management

The slot column provides a stable ordering for the vault UI. Slot numbers are managed by the game hook — the platform does not enforce slot uniqueness or maximum slot counts. Game hooks may impose their own limits (e.g., maximum 20 vault slots per player).

Provenance Tracking

The source_server_id column records where the item originated. This enables:

  • Audit trails: Administrators can see which server an item came from.
  • Transfer rules: Game hooks can enforce rules like "items from PvP servers cannot be withdrawn on PvE servers."
  • Duplication detection: Combined with timestamps, source tracking helps identify suspicious vault activity.

Security Considerations

Item Duplication Prevention

The vault system must coordinate with in-game inventory to prevent item duplication. The recommended pattern is:

  1. Remove from inventory first — Delete the item from the player's in-game inventory.
  2. Then insert into vault — Create the GlobalVault row.
  3. On withdrawal, reverse — Delete the GlobalVault row, then add to inventory.

Because SpacetimeDB reducers are transactional, the vault insertion (or deletion) is atomic. However, the in-game inventory operation happens outside the WASM module, so game hooks must handle edge cases (e.g., server crash between inventory removal and vault insertion).

Data Integrity

Since item_data is an opaque JSON string, the platform cannot validate its contents. Game hooks are responsible for ensuring that deposited items are valid and that the JSON schema matches what the withdrawal logic expects.


Vault operations are typically handled by game-specific reducers in the sub-database layer rather than platform-level reducers. The platform provides the table; the game hook provides the logic.


Subscriber Query Purpose
Game Hook SELECT * FROM global_vault WHERE player_id = '{player_id}' Player vault contents
Admin Panel SELECT * FROM global_vault Vault administration, item inspection

For full subscription architecture, see Subscriptions.