using System; using UnityEditor; using UnityEngine; using UnityEngine.Networking; namespace Chameleon.Editor.WebAssets { /// /// Non-blocking UnityWebRequest transport for editor tools. All requests poll on /// EditorApplication.update — never blocks the editor. Shared by the Poly Haven /// and ambientCG importers. /// public static class EditorWebRequest { public const string UserAgent = "Chameleon-Unity-AssetImporter/1.0"; /// GET a URL and return the response body as text. public static void GetText(string url, Action onDone, Action onError) { var req = UnityWebRequest.Get(url); req.SetRequestHeader("User-Agent", UserAgent); Send(req, () => onDone?.Invoke(req.downloadHandler.text), onError); } /// Fetches an image as a Texture2D (browser thumbnails, previews). public static void GetTexture(string url, Action onDone, Action onError) { var req = UnityWebRequestTexture.GetTexture(url); req.SetRequestHeader("User-Agent", UserAgent); Send(req, () => { var tex = DownloadHandlerTexture.GetContent(req); // Survive play-mode enter/exit cleanup — otherwise Unity destroys these // loose runtime textures and browser previews go blank. if (tex) tex.hideFlags = HideFlags.HideAndDontSave; onDone?.Invoke(tex); }, onError); } /// Streams a file straight to disk (no RAM peak on big downloads). public static void DownloadFile(string url, string destPath, Action onDone, Action onError, Action onProgress = null) { var req = new UnityWebRequest(url, UnityWebRequest.kHttpVerbGET); req.downloadHandler = new DownloadHandlerFile(destPath) { removeFileOnAbort = true }; req.SetRequestHeader("User-Agent", UserAgent); Send(req, () => onDone?.Invoke(), onError, onProgress); } public static void Send(UnityWebRequest req, Action onSuccess, Action onError, Action onProgress = null) { var op = req.SendWebRequest(); void Tick() { if (onProgress != null && !op.isDone) onProgress(req.downloadProgress); if (!op.isDone) return; EditorApplication.update -= Tick; try { if (req.result != UnityWebRequest.Result.Success) { onError?.Invoke($"{req.error} ({req.url})"); } else { onProgress?.Invoke(1f); onSuccess?.Invoke(); } } finally { req.Dispose(); } } EditorApplication.update += Tick; } } }