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
}
}