Supabase
Crystal Save includes built-in support for Supabase Storage as a cloud save backend. This allows you to store save files, metadata, and screenshots in a Supabase bucket with configurable authentication and folder strategies.
1. Prepare Your Supabase Project
Create a Supabase Project
Go to supabase.com and create a new project.
Create a Storage Bucket
Navigate to Storage → New Bucket.
Example name:
game-saves
.
Set Storage Policies
Go to Storage → Policies → Other policies (storage.objects).
Create policies for SELECT, INSERT, UPDATE, and DELETE according to your chosen folder strategy.
Example for a public/shared bucket:
CREATE POLICY "Anon read game-saves"
ON storage.objects
FOR SELECT TO anon
USING (bucket_id = 'game-saves');
Repeat for insert/update/delete with the appropriate clauses.
If you want per-user isolation:
Use RLS with
auth.uid()
in the policy.Example for Unity Authentication:
CREATE POLICY "Player read own saves"
ON storage.objects
FOR SELECT TO authenticated
USING (
bucket_id = 'game-saves'
AND name LIKE ('users/' || auth.uid() || '/%')
);
2. Configure Crystal Save
Create and Open Save Settings
Create → Crystal Save → Settings → Create Save Settings File
.
Enable Cloud Save and set:
Save Backend →
Supabase
Supabase URL → Found in your Supabase Project dashboard.
Supabase Anon Key → API key from Supabase Project settings.
Bucket Name → e.g.,
game-saves
.
Choose a User Folder Strategy (
userFolderStrategy
):Shared – All saves in one folder.
UnityAuthentication – Folders per Unity Auth user.
GuidPerDevice – Random GUID stored locally.
PublicPerBuild – Different public folder per build.
Custom – Fully controlled by your own resolver.
If using Custom strategy:
Assign a
CustomFolderAuthResolver
or your own implementation ofIUserAuthorizationResolver
.After login, call:
resolver.SetUserId(uid); resolver.SetToken(jwt); SupabaseAuthRelay.FireLoggedIn(uid);
3. Handle Authentication
Crystal Save does not force a specific login flow, but provides utilities:
Email/Password Signup:
StartCoroutine(SupabaseRestAuth.SignUpWithEmailPassword( supabaseUrl, supabaseAnonKey, email, password, (jwt, uid, needsConfirm) => { resolver.SetUserId(uid); resolver.SetToken(jwt); }, error => Debug.LogError(error)));
Email/Password Signin:
StartCoroutine(SupabaseRestAuth.SignInWithPassword( supabaseUrl, supabaseAnonKey, email, password, (jwt, uid) => { resolver.SetUserId(uid); resolver.SetToken(jwt); }, error => Debug.LogError(error)));
Use
SupabaseAuthRelay
events to react to login/logout.
4. Wait for Cloud Connection (Optional)
If your game must wait for a successful Supabase login before proceeding:
await SaveManager.Instance.WaitForSupabaseLoginAsync();
This waits until SupabaseAuthRelay
reports a login or times out.
5. Saving and Loading
Once logged in:
Call
SaveManager.SaveAsync(slotNumber)
to upload the save.Call
SaveManager.LoadAsync(slotNumber)
to download and load the save.Crystal Save:
Resolves the user folder based on strategy or resolver.
Uploads
.sav
or.json
file.Uploads
.meta.json
with slot details.Optionally uploads screenshots.
If
keepLocalMirror
is enabled, stores local copies for offline play.
6. Logging Out
SaveManager.Instance.LogoutFromSupabase();
Clears stored credentials from the resolver.
Resets cloud save state.
Mermaid Flow Diagram
Last updated