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

  1. Create a Supabase Project

    • Go to supabase.com and create a new project.

  2. Create a Storage Bucket

    • Navigate to Storage → New Bucket.

    • Example name: game-saves.

  3. 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.

  1. 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

  1. Create and Open Save Settings

    • Create → Crystal Save → Settings → Create Save Settings File.

  2. 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.

  3. 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.

  4. If using Custom strategy:

    • Assign a CustomFolderAuthResolver or your own implementation of IUserAuthorizationResolver.

    • 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