-
-
Save cloned/fe255b4f7d6feacee319 to your computer and use it in GitHub Desktop.
using UnityEngine; | |
using System.Collections; | |
using System.Collections.Generic; | |
namespace WWWKit | |
{ | |
/// <summary> | |
/// A handy class to use WWW class and WWWForm class. | |
/// | |
/// Features: | |
/// | |
/// * Use callback (delegate) instead of coroutine. Of course this class uses | |
/// coroutine internally not to stop other processes. | |
/// * Can use timeout. | |
/// * Handle complex constructor of WWW class. | |
/// | |
/// Requirements: | |
/// | |
/// * Unity 4.5 | |
/// | |
/// Example usage: | |
/// | |
/// using WWWKit; | |
/// public class WWWClientExample : MonoBehaviour | |
/// { | |
/// void Start() | |
/// { | |
/// // GET request | |
/// WWWClient client = new WWWClient(this, "http://example.com/"); | |
/// client.OnDone = (WWW www) => { | |
/// Debug.Log(www.text); | |
/// }; | |
/// client.Request(); | |
/// | |
/// // POST request | |
/// WWWClient http = new WWWClient(this, "http://example.com/"); | |
/// client.AddData("foo", "bar"); | |
/// client.OnDone = (WWW www) => { | |
/// Debug.Log(www.text); | |
/// }; | |
/// client.Request(); | |
/// | |
/// // POST request with binary data (file attachment) | |
/// byte[] binary = System.Text.Encoding.Unicode.GetBytes("bar"); | |
/// WWWClient http = new WWWClient(this, "http://example.com/"); | |
/// client.AddBinaryData("foo", binary, "test.txt", "application/octet-stream"); | |
/// client.OnDone = (WWW www) => { | |
/// Debug.Log(www.text); | |
/// }; | |
/// client.Request(); | |
/// | |
/// // Handle error | |
/// client.OnFail = (WWW www) => { | |
/// Debug.Log(www.error); | |
/// }; | |
/// | |
/// // Handle timed out | |
/// client.OnDisposed = () => { | |
/// Debug.Log("Timed out"); | |
/// }; | |
/// | |
/// // Set timeout time (default is infinity) | |
/// client.Timeout = 10f; | |
/// | |
/// // Add header | |
/// client.AddHeader("Cookie", "cookiename=cookievalue"); | |
/// } | |
/// } | |
/// </summary> | |
public class WWWClient | |
{ | |
public delegate void FinishedDelegate(WWW www); | |
public delegate void DisposedDelegate(); | |
private MonoBehaviour mMonoBehaviour; | |
private string mUrl; | |
private WWW mWww; | |
private WWWForm mForm; | |
private Dictionary<string, string> mHeaders; | |
private float mTimeout; | |
private FinishedDelegate mOnDone; | |
private FinishedDelegate mOnFail; | |
private DisposedDelegate mOnDisposed; | |
private bool mDisposed; | |
public Dictionary<string, string> Headers | |
{ | |
set { mHeaders = value; } | |
get { return mHeaders; } | |
} | |
public float Timeout | |
{ | |
set { mTimeout = value; } | |
get { return mTimeout; } | |
} | |
public FinishedDelegate OnDone | |
{ | |
set { mOnDone = value; } | |
} | |
public FinishedDelegate OnFail | |
{ | |
set { mOnFail = value; } | |
} | |
public DisposedDelegate OnDisposed | |
{ | |
set { mOnDisposed = value; } | |
} | |
public WWWClient(MonoBehaviour monoBehaviour, string url) | |
{ | |
mMonoBehaviour = monoBehaviour; | |
mUrl = url; | |
mHeaders = new Dictionary<string, string>(); | |
mForm = new WWWForm(); | |
mTimeout = -1; | |
mDisposed = false; | |
} | |
public void AddHeader(string headerName, string value) | |
{ | |
mHeaders.Add(headerName, value); | |
} | |
public void AddData(string fieldName, string value) | |
{ | |
mForm.AddField(fieldName, value); | |
} | |
public void AddBinaryData(string fieldName, byte[] contents) | |
{ | |
mForm.AddBinaryData(fieldName, contents); | |
} | |
public void AddBinaryData(string fieldName, byte[] contents, string fileName) | |
{ | |
mForm.AddBinaryData(fieldName, contents, fileName); | |
} | |
public void AddBinaryData(string fieldName, byte[] contents, string fileName, string mimeType) | |
{ | |
mForm.AddBinaryData(fieldName, contents, fileName, mimeType); | |
} | |
public void Request() | |
{ | |
mMonoBehaviour.StartCoroutine(RequestCoroutine()); | |
} | |
public void Dispose() | |
{ | |
if (mWww != null && !mDisposed) | |
{ | |
mWww.Dispose(); | |
mDisposed = true; | |
} | |
} | |
private IEnumerator RequestCoroutine() | |
{ | |
if (mForm.data.Length > 0) | |
{ | |
// Overwrite added headers with WWWForm.headers because WWWForm.headers may have required | |
// headers to request. For example, WWWForm.headers has Content-Type like | |
// 'multipart/form-data; boundary="xxxx"' if WWWForm.AddBinaryData() is called. | |
foreach (DictionaryEntry entry in mForm.headers) | |
{ | |
mHeaders[System.Convert.ToString(entry.Key)] = System.Convert.ToString(entry.Value); | |
} | |
// POST request | |
mWww = new WWW(mUrl, mForm.data, mHeaders); | |
} | |
else | |
{ | |
// GET request | |
mWww = new WWW(mUrl, null, mHeaders); | |
} | |
yield return mMonoBehaviour.StartCoroutine(CheckTimeout()); | |
if (mDisposed) | |
{ | |
if (mOnDisposed != null) | |
{ | |
mOnDisposed(); | |
} | |
} | |
else if (System.String.IsNullOrEmpty(mWww.error)) | |
{ | |
if (mOnDone != null) | |
{ | |
mOnDone(mWww); | |
} | |
} | |
else | |
{ | |
if (mOnFail != null) | |
{ | |
mOnFail(mWww); | |
} | |
} | |
} | |
private IEnumerator CheckTimeout() | |
{ | |
float startTime = Time.time; | |
while (!mDisposed && !mWww.isDone) | |
{ | |
if (mTimeout > 0 && (Time.time - startTime) >= mTimeout) | |
{ | |
Dispose(); | |
break; | |
} | |
else | |
{ | |
yield return null; | |
} | |
} | |
yield return null; | |
} | |
} | |
} |
WWWClient can request a url one time only which means that you can not reuse the same instance for some requests. It's not great design but WWWClient can keep simplicity.
About the returning inside a onDone block, it's works for me (Unity 4.6.3f1).
Here is a sample code.
using UnityEngine;
using WWWKit;
public class Test : MonoBehaviour {
void Start () {
// Chained Requests
WWWClient c1 = new WWWClient(this, "http://www.google.com/");
c1.OnDone = (WWW www1) => {
Debug.Log(www1.text);
WWWClient c2 = new WWWClient(this, "http://www.yahoo.com/");
c2.OnDone = (WWW www2) => {
Debug.Log(www2.text);
};
c2.Request();
};
c1.Request();
// "return" inside a onDone block
WWWClient c3 = new WWWClient(this, "http://www.google.com/");
c3.OnDone = (WWW www) => {
return;
Debug.Log("Will never reach here");
};
}
}
yes, thats what I thought. So I created a second class that uses WWWkit internally. The problem is that, the moment this class tries to make the second request, it fails.
client.OnDone = (WWW www) => {
string processedResponse = this.hostController.analyze(www.text); //This object is an instance of a different class, and that method will execute a second http request.
...
I'm getting this error.
NullReferenceException
UnityEngine.MonoBehaviour.StartCoroutine (IEnumerator routine)
WWWKit.WWWClient.Request () (at Assets/Scripts/Artifical Intelligence/WWWClient.cs:161)
There is nothing wrong with the way Im implementing the WWWkit because I've copied that code and ran in independently and it worked fine. So there most be a problem with something else.
It seems like this.
http://answers.unity3d.com/questions/501082/running-a-monobehavior-script-a-with-a-coroutine-i.html
Test class in my sample code is safe as long as it's instantiated as a Component.
Test test = new Test();
test.Start();
This code occurs the error because Test which extends MonoBehaviour is not instantiated as a Component.
Oh thank you very much. That was the problem, I needed to instantiate the Monobehaviour class a different way. But....
I still noticed that "returns" dont work inside the onDone and onFail blocks.
for example when Im returning a string:
HostRemoteController.cs(112,57): error CS0029: Cannot implicitly convert type
string' to void' HostRemoteController.cs(112,57): error CS1662: Cannot convert
lambda expression' to delegate type WWWKit.WWWClient.FinishedDelegate' because some of the return types in the block are not implicitly convertible to the delegate return type
Sorry for the delay.
Following code is not compatible with WWWKit.WWWClient.FinishedDelegate.
client.OnDone = (WWW www) => {
return "something";
};
Because the returning type of WWWKit.WWWClient.FinishedDelegate is defined as void.
public delegate void FinishedDelegate(WWW www);
WWWClient.cs, Line 73
Is it okay to call another method like this?
client.OnDone = (WWW www) => {
String foo = "want to use this outside";
SomeAnotherMethod(foo);
};
Is there a way to make a client.Request() inside a onDone method ? Im having troubles making chained requests. Also, I have methods where I need to make a "return" inside a onDone block, but the library doesn't allow that.