#Data & Persistence
#Where data is saved
One DataStore record per player: store RidePet_Player_v1, key u_<UserId>. It holds the player's profile (below). The server saves:
- every 120 seconds for every player,
- when the player leaves,
- when the server shuts down (
BindToClose).
A session lock stops two servers from overwriting each other: a record that another server wrote less than 5 minutes ago is not taken over. If the data cannot be loaded after three tries, a live server kicks the player with "Could not load your data. Please try again." instead of giving them an empty profile. In Studio you get a temporary profile that is not saved.
#Profile
| Field | Meaning |
|---|---|
cash | Money (capped at 1e20) |
luck | Hatch Luck, 1 … 1024 |
rebirths | 0 … 7 |
pets | List of pets: id, kind, level, xp, placed, weather, mutation, kg, kgRatio |
basket | Eggs in the inventory |
nests | Placed eggs with their ready time and position |
food | { foodName = count } |
radars | { radarName = count } (old saves with true count as one) |
index, indexEggs | Discovered pets and eggs |
claimed | Index rewards already paid |
lastSeen | Time of the last save, used for offline income |
Loaded data passes through a sanitizer: numbers are clamped, unknown pets are dropped, and invalid weather or mutation names are removed. The player's pets are limited to 300.
#Offline income
When a player joins, the server adds their income for the time they were away: up to Catalog.OfflineHoursCap (24 hours) at Catalog.OfflineIncomeFraction (50 %).
#Rate limit
Every Action request is limited to one per 0.12 seconds per player (except reads), and all input is validated on the server.
#Changing the schema
Add the new field to newProfile with a safe default and, if it must be a number, to the list in sanitize. Old saves then load without a migration because unknown or missing fields fall back to the default.