using System;
using UnityEngine;
using UnityEngine.Networking;
namespace Watermelon
{
///
/// Example cloud save handler implementation for custom backend.
/// Demonstrates how to implement ICloudSaveHandler for a REST API backend.
///
/// Usage:
/// 1. Extend SaveInitModule and override GetCloudHandler()
/// 2. Create instance of CustomBackendCloudHandler with your API URL
/// 3. Configure with user ID
/// 4. Return from GetCloudHandler()
///
public class CustomBackendCloudHandler : ICloudSaveHandler
{
private string apiBaseUrl;
private string userId;
private bool isAvailable = true;
public bool IsAvailable => isAvailable;
///
/// Create handler with custom backend configuration.
/// Example: new CustomBackendCloudHandler("https://api.example.com/saves", userId)
///
public CustomBackendCloudHandler(string baseUrl, string userIdentifier)
{
apiBaseUrl = baseUrl?.TrimEnd('/');
userId = userIdentifier;
if (string.IsNullOrEmpty(apiBaseUrl) || string.IsNullOrEmpty(userId))
{
Debug.LogError("[Cloud Save]: CustomBackendCloudHandler requires valid apiBaseUrl and userId");
isAvailable = false;
}
}
public void Init()
{
Debug.Log($"[Cloud Save]: CustomBackendCloudHandler initialized for user '{userId}' at {apiBaseUrl}");
}
///
/// Download save file from cloud.
/// GET /api/saves/{userId}/{fileName}
/// Response: { "json": "...", "metadata": { "timestampUnix": 0, "saveCount": 0 } }
///
public void Download(string fileName, Action onComplete)
{
if (!isAvailable)
{
onComplete?.Invoke(false, null, null);
return;
}
string url = $"{apiBaseUrl}/{userId}/{fileName}";
var request = UnityWebRequest.Get(url);
request.timeout = 10;
var asyncOp = request.SendWebRequest();
asyncOp.completed += _ => HandleDownloadResponse(request, fileName, onComplete);
}
private void HandleDownloadResponse(UnityWebRequest request, string fileName, Action onComplete)
{
try
{
if (request.result == UnityWebRequest.Result.Success)
{
string responseText = request.downloadHandler.text;
// Parse response JSON
// Expected format: { "json": "...", "metadata": { "timestampUnix": 0, "saveCount": 0 } }
try
{
var response = JsonUtility.FromJson(responseText);
if (response != null && !string.IsNullOrEmpty(response.json))
{
SaveFileMetadata metadata = response.metadata;
Debug.Log($"[Cloud Save]: Downloaded '{fileName}' from cloud - {metadata}");
onComplete?.Invoke(true, response.json, metadata);
return;
}
}
catch (Exception ex)
{
Debug.LogWarning($"[Cloud Save]: Failed to parse cloud response: {ex.Message}");
}
onComplete?.Invoke(false, null, null);
}
else if (request.responseCode == 404)
{
// File doesn't exist in cloud - this is not an error
Debug.Log($"[Cloud Save]: No cloud save found for '{fileName}'");
onComplete?.Invoke(false, null, null);
}
else
{
Debug.LogWarning($"[Cloud Save]: Download failed - HTTP {request.responseCode}: {request.error}");
onComplete?.Invoke(false, null, null);
}
}
finally
{
request?.Dispose();
}
}
///
/// Upload save file to cloud.
/// POST /api/saves/{userId}/{fileName}
/// Body: { "json": "...", "metadata": { "timestampUnix": 0, "saveCount": 0 } }
///
public void Upload(string fileName, string json, SaveFileMetadata metadata, Action onComplete)
{
if (!isAvailable)
{
onComplete?.Invoke(false);
return;
}
string url = $"{apiBaseUrl}/{userId}/{fileName}";
var payload = new CloudSavePayload { json = json, metadata = metadata };
string payloadJson = JsonUtility.ToJson(payload);
var request = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
request.uploadHandler = new UploadHandlerRaw(System.Text.Encoding.UTF8.GetBytes(payloadJson));
request.downloadHandler = new DownloadHandlerBuffer();
request.SetRequestHeader("Content-Type", "application/json");
request.timeout = 10;
var asyncOp = request.SendWebRequest();
asyncOp.completed += _ => HandleUploadResponse(request, fileName, onComplete);
}
private void HandleUploadResponse(UnityWebRequest request, string fileName, Action onComplete)
{
try
{
if (request.result == UnityWebRequest.Result.Success)
{
Debug.Log($"[Cloud Save]: Uploaded '{fileName}' to cloud successfully");
onComplete?.Invoke(true);
}
else
{
Debug.LogWarning($"[Cloud Save]: Upload failed - HTTP {request.responseCode}: {request.error}");
onComplete?.Invoke(false);
}
}
finally
{
request?.Dispose();
}
}
///
/// Delete save file from cloud.
/// DELETE /api/saves/{userId}/{fileName}
///
public void Delete(string fileName, Action onComplete)
{
if (!isAvailable)
{
onComplete?.Invoke(false);
return;
}
string url = $"{apiBaseUrl}/{userId}/{fileName}";
var request = UnityWebRequest.Delete(url);
request.timeout = 10;
var asyncOp = request.SendWebRequest();
asyncOp.completed += _ => HandleDeleteResponse(request, fileName, onComplete);
}
private void HandleDeleteResponse(UnityWebRequest request, string fileName, Action onComplete)
{
try
{
if (request.result == UnityWebRequest.Result.Success)
{
Debug.Log($"[Cloud Save]: Deleted '{fileName}' from cloud");
onComplete?.Invoke(true);
}
else
{
Debug.LogWarning($"[Cloud Save]: Delete failed - HTTP {request.responseCode}: {request.error}");
onComplete?.Invoke(false);
}
}
finally
{
request?.Dispose();
}
}
// Helper classes for JSON serialization
[System.Serializable]
private class CloudSavePayload
{
public string json;
public SaveFileMetadata metadata;
}
[System.Serializable]
private class CloudSaveResponse
{
public string json;
public SaveFileMetadata metadata;
}
}
}