Back up your database
Backups run on their own. You need access to the server's storyforce_server.cfg and server files.
The backup cvars are read when a backup is due, so a change applies without a restart.
There is no in-game screen for this. You set it in storyforce_server.cfg.
Find your database
Every account, every character and everything attached to them lives in one SQLite file:
<fs_homepath>/<fs_game>/db/storyforce.db
With the shipped launcher that is GameData/StoryForce/db/storyforce.db.
The server prints the resolved path at boot, before the open is attempted, so a failure names the path it tried:
SF_DB_Open: failed to open 'GameData/StoryForce/db/storyforce.db': unable to open database file
After that line nobody can log in, register or load a character.
It is likely a permissions problem on the directory.
Set the backup up
Three cvars, all set by the shipped config to the values the mod already compiles in:
set sf_dbbackup "1"
set sf_dbbackupinterval "24"
set sf_dbbackupretention "7"
sf_dbbackupturns automatic backups on.0turns them off.sf_dbbackupintervalis hours between snapshots.0also disables them.sf_dbbackupretentionis days to keep. Older snapshots are deleted after each successful new backup.
Run sf_dbbackup at the server console for an immediate snapshot, even when automatic backups are off.
Restore a backup
Restoring returns accounts, characters and XP to the snapshot's date. It replaces the whole database; it does not merge old records with newer ones. There is no restore command in the game.
- Stop the server cleanly, and close any database editor. Keep the server stopped throughout the file changes.
- Move the current
storyforce.dbinto a dated folder outside the livedb/directory. Move any remainingstoryforce.db-walandstoryforce.db-shmfiles with it, keeping them together as your rollback copy. - Copy a completed
.dbsnapshot fromdb/backups/into the livedb/directory and name the copystoryforce.db. Keep the original snapshot. Do not use a.tmpfile. - Make sure the server can write the replacement file and its directory, then restart it with the same launcher and paths.
- Check the database path in the boot output, then log in and load a character to check the restored records.
What the backup does not cover
The backup copies the database and nothing else.
| Not backed up | Where it lives |
|---|---|
| Every saved scene: placed props, lights, cameras, triggers, NPCs and spawns, on every map | <fs_homepath>/<fs_game>/scenes/ |
| What your AI-driven NPCs remember about people | <fs_homepath>/<fs_game>/llm/<persona>/ |
| Engine IP bans and exceptions | <fs_homepath>/<fs_game>/serverbans.dat |
StoryForce /sfban records | <fs_homepath>/<fs_game>/bannedips.cfg |
| The shared prop library | <fs_homepath>/<fs_game>/props/ |
Your own storyforce_server.cfg and anything you exec from it | wherever you put it |
Back those up yourself. They are all plain files, so any ordinary file-level backup of the mod folder covers them.
Mirror to Cloudflare D1
StoryForce can push accounts, characters, the item catalogue, item ownership and the XP award log to a Cloudflare D1 database so a website can read them. Containers and the private pending-XP draft queue stay local.
The whole block is commented out in the shipped config, so the mirror is off until you uncomment it.
set sf_d1sync "1"
set sf_d1syncinterval "0"
set sf_d1syncpassword "0"
set sf_d1account "<your Cloudflare account ID>"
set sf_d1database "<your D1 database UUID>"
set sf_d1token "<your scoped API token>"
The mirror is one-way and the game never reads back from it.
It pushes at map start, at a map change and at quit, and sf_d1syncinterval adds an optional push every so many seconds.
Only changed rows are sent.
Check sf_sync_meta before treating the mirror as updated. A finished cycle has in_progress = 0 and matching completed_cycle and cycle_id values.
An interrupted cycle can leave partial data.
sf_d1resync at the server console forces a full re-push. When it is enabled, the console replies:
SF_D1Sync: full reload queued
sf_d1syncpassword is a decision, not a default to copy. At 0 your players' password hashes never leave the server. At 1 the salted hash is mirrored too, which is what lets a website offer a login against the same account.
You will need to take appropriate steps to secure it.