using System; using System.Collections.Generic; using UnityEngine; #if UNITY_5_4_OR_NEWER using UnityEngine.Networking; using UnityEngine.Rendering; #endif namespace Cryville.Common.Unity { /// /// A worker that performs network tasks in the background. /// /// /// It is required to call every tick to keep the worker working. /// public class NetworkTaskWorker { bool suspended; NetworkTask currentNetworkTask; readonly Queue networkTasks = new Queue(); /// /// Current queued task count. /// public int TaskCount { get { return networkTasks.Count; } } /// /// Submits a new network task. /// /// The task. public void SubmitNetworkTask(NetworkTask task) { networkTasks.Enqueue(task); } /// /// Ticks the worker. /// /// The status of the worker. public WorkerStatus TickBackgroundTasks() { if (suspended) return WorkerStatus.Suspended; if (currentNetworkTask != null) { if (currentNetworkTask.Cancelled) currentNetworkTask = null; else if (currentNetworkTask.Done()) currentNetworkTask = null; } while (networkTasks.Count > 0 && currentNetworkTask == null) { var task = networkTasks.Dequeue(); if (task.Cancelled) continue; currentNetworkTask = task; currentNetworkTask.Start(); } return currentNetworkTask == null ? WorkerStatus.Idle : WorkerStatus.Working; } /// /// Cancels the current working task (if present) and suspends all background tasks. /// public void SuspendBackgroundTasks() { suspended = true; if (currentNetworkTask != null) { currentNetworkTask.Cancel(); currentNetworkTask = null; } } /// /// Resumes background tasks. /// public void ResumeBackgroundTasks() { suspended = false; } } /// /// Status of a . /// public enum WorkerStatus { /// /// The worker is not working nor suspended. /// Idle, /// /// The worker is working on a task. /// Working, /// /// The worker is suspended. /// Suspended, } /// /// A network task. /// public abstract class NetworkTask { protected NetworkTask(string uri) { Uri = uri; } /// /// The URI of the resource. /// public string Uri { get; private set; } /// /// Whether the task is cancelled. /// public bool Cancelled { get; private set; } /// /// Cancels the task. /// public virtual void Cancel() { Cancelled = true; } #if UNITY_5_4_OR_NEWER protected UnityWebRequest www; /// /// Starts the task. /// public virtual void Start() { www = new UnityWebRequest(Uri); www.SendWebRequest(); } /// /// Gets whether the task is done. /// /// Whether the task is done. public virtual bool Done() { if (!www.isDone) return false; return true; } #else protected WWW www; /// /// Starts the task. /// public virtual void Start() { www = new WWW(Uri); } /// /// Gets whether the task is done. /// /// Whether the task is done. public virtual bool Done() { if (!www.isDone) return false; return true; } #endif } /// /// A that loads a texture. /// public class LoadTextureTask : NetworkTask { /// /// Creates an instance of the class. /// /// The URI of the resource. /// The callback function upon load complete. public LoadTextureTask(string uri, Action callback) : base(uri) { Callback = callback; } /// /// The callback function upon load complete. /// public Action Callback { get; private set; } #if UNITY_5_4_OR_NEWER DownloadHandlerTexture handler; /// public override void Start() { handler = new DownloadHandlerTexture(); www = new UnityWebRequest(Uri, "GET", handler, null); www.SendWebRequest(); } /// public override bool Done() { if (!www.isDone) return false; if (handler.isDone && handler.texture != null) { var buffer = handler.texture; var result = new Texture2D(buffer.width, buffer.height, buffer.format, true); if (SystemInfo.copyTextureSupport.HasFlag(CopyTextureSupport.Basic)) { Graphics.CopyTexture(buffer, 0, 0, result, 0, 0); } else { result.LoadImage(handler.data); } result.Apply(true, true); Texture2D.Destroy(buffer); Callback(true, result); // Callback(true, buffer); } else { Callback(false, null); } www.Dispose(); handler.Dispose(); return true; } #else /// public override bool Done() { if (!www.isDone) return false; bool succeeded = string.IsNullOrEmpty(www.error); if (succeeded) { var buffer = www.texture; /*var result = new Texture2D(buffer.width, buffer.height, buffer.format, true); result.SetPixels(buffer.GetPixels()); result.Apply(true, true); Texture2D.Destroy(buffer); Callback(true, result);*/ Callback(true, buffer); } else Callback(false, null); return true; } #endif } }