using System; using System.Collections; using System.Text; using UnityEngine; using UnityEngine.Networking; namespace BlockSpace.Voxels { public sealed class InventoryBackendClient { [Serializable] public sealed class ListResponse { public bool ok; public string[] ids; public string equippedId; public string error; } [Serializable] public sealed class PutResponse { public bool ok; public bool saved; public string id; public string error; } [Serializable] public sealed class EquipResponse { public bool ok; public string equippedId; public string error; } [Serializable] private sealed class EquipRequest { public string playerId; public string avatarId; } private readonly string baseUrl; public InventoryBackendClient(string baseUrl) { this.baseUrl = (baseUrl ?? string.Empty).Trim().TrimEnd('/'); } public IEnumerator ListAvatars(string playerId, Action onDone) { yield return GetJson("/api/inventory/avatars?playerId=" + UnityWebRequest.EscapeURL(playerId ?? ""), onDone); } public IEnumerator ListCreations(string playerId, Action onDone) { yield return GetJson("/api/inventory/creations?playerId=" + UnityWebRequest.EscapeURL(playerId ?? ""), onDone); } public IEnumerator DownloadAvatar(string playerId, string avatarId, Action onDone) { string uri = baseUrl + "/api/inventory/avatars/" + UnityWebRequest.EscapeURL(avatarId ?? "") + "?playerId=" + UnityWebRequest.EscapeURL(playerId ?? ""); using UnityWebRequest request = UnityWebRequest.Get(uri); request.downloadHandler = new DownloadHandlerBuffer(); yield return request.SendWebRequest(); if (request.result != UnityWebRequest.Result.Success) { Debug.LogWarning($"DownloadAvatar failed: {request.result} {request.responseCode} {request.error}"); onDone?.Invoke(string.Empty); yield break; } string text = request.downloadHandler.text ?? string.Empty; Debug.Log($"DownloadAvatar ok: code={request.responseCode} bytes={((text != null) ? Encoding.UTF8.GetByteCount(text) : 0)}"); onDone?.Invoke(text); } public IEnumerator UploadAvatar(string playerId, string avatarId, string payloadJson, Action onDone) { string url = baseUrl + "/api/inventory/avatars/" + UnityWebRequest.EscapeURL(avatarId ?? "") + "?playerId=" + UnityWebRequest.EscapeURL(playerId ?? ""); byte[] body = Encoding.UTF8.GetBytes(payloadJson ?? "{}"); using UnityWebRequest request = new UnityWebRequest(url, "PUT"); request.uploadHandler = new UploadHandlerRaw(body); request.downloadHandler = new DownloadHandlerBuffer(); request.chunkedTransfer = false; request.uploadHandler.contentType = "application/json; charset=utf-8"; request.SetRequestHeader("Content-Type", "application/json; charset=utf-8"); yield return request.SendWebRequest(); PutResponse putResponse = null; if (request.result == UnityWebRequest.Result.Success) { try { putResponse = JsonUtility.FromJson(request.downloadHandler.text); } catch { } Debug.Log($"UploadAvatar ok: code={request.responseCode} bytes={body.Length} respLen={((request.downloadHandler.text != null) ? request.downloadHandler.text.Length : 0)}"); } else { Debug.LogWarning($"UploadAvatar failed: {request.result} {request.responseCode} {request.error} bytes={body.Length}"); } if (putResponse == null) { putResponse = new PutResponse { ok = false, saved = false, id = (avatarId ?? ""), error = request.error }; } onDone?.Invoke(putResponse); } public IEnumerator EquipAvatar(string playerId, string avatarId, Action onDone) { string url = baseUrl + "/api/inventory/avatars/equip"; string s = JsonUtility.ToJson(new EquipRequest { playerId = (playerId ?? ""), avatarId = (avatarId ?? "") }); byte[] bytes = Encoding.UTF8.GetBytes(s); using UnityWebRequest request = new UnityWebRequest(url, "POST"); request.uploadHandler = new UploadHandlerRaw(bytes); request.downloadHandler = new DownloadHandlerBuffer(); request.SetRequestHeader("Content-Type", "application/json; charset=utf-8"); yield return request.SendWebRequest(); EquipResponse equipResponse = null; if (request.result == UnityWebRequest.Result.Success) { try { equipResponse = JsonUtility.FromJson(request.downloadHandler.text); } catch { } } if (equipResponse == null) { equipResponse = new EquipResponse { ok = false, equippedId = "", error = request.error }; } onDone?.Invoke(equipResponse); } public IEnumerator DownloadCreation(string playerId, string creationId, Action onDone) { string uri = baseUrl + "/api/inventory/creations/" + UnityWebRequest.EscapeURL(creationId ?? "") + "?playerId=" + UnityWebRequest.EscapeURL(playerId ?? ""); using UnityWebRequest request = UnityWebRequest.Get(uri); request.downloadHandler = new DownloadHandlerBuffer(); yield return request.SendWebRequest(); if (request.result != UnityWebRequest.Result.Success) { onDone?.Invoke(Array.Empty()); yield break; } onDone?.Invoke(request.downloadHandler.data ?? Array.Empty()); } public IEnumerator UploadCreation(string playerId, string creationId, byte[] gzipBytes, Action onDone) { string url = baseUrl + "/api/inventory/creations/" + UnityWebRequest.EscapeURL(creationId ?? "") + "?playerId=" + UnityWebRequest.EscapeURL(playerId ?? ""); byte[] body = gzipBytes ?? Array.Empty(); using UnityWebRequest request = new UnityWebRequest(url, "PUT"); request.uploadHandler = new UploadHandlerRaw(body); request.downloadHandler = new DownloadHandlerBuffer(); request.chunkedTransfer = false; request.uploadHandler.contentType = "application/octet-stream"; request.SetRequestHeader("Content-Type", "application/octet-stream"); yield return request.SendWebRequest(); PutResponse putResponse = null; if (request.result == UnityWebRequest.Result.Success) { try { putResponse = JsonUtility.FromJson(request.downloadHandler.text); } catch { } Debug.Log($"UploadCreation ok: code={request.responseCode} bytes={body.Length}"); } else { Debug.LogWarning($"UploadCreation failed: {request.result} {request.responseCode} {request.error}"); } if (putResponse == null) { putResponse = new PutResponse { ok = false, saved = false, id = (creationId ?? ""), error = request.error }; } onDone?.Invoke(putResponse); } private IEnumerator GetJson(string pathAndQuery, Action onDone) where T : class { if (string.IsNullOrEmpty(baseUrl)) { onDone?.Invoke(null); yield break; } string url = baseUrl + pathAndQuery; using UnityWebRequest request = UnityWebRequest.Get(url); request.downloadHandler = new DownloadHandlerBuffer(); yield return request.SendWebRequest(); if (request.result != UnityWebRequest.Result.Success) { Debug.LogWarning($"InventoryBackendClient GET failed: {url} {request.result} {request.responseCode} {request.error}"); onDone?.Invoke(null); yield break; } T obj = null; try { obj = JsonUtility.FromJson(request.downloadHandler.text); } catch { } onDone?.Invoke(obj); } } }