Hi Unity folks,
I’m trying to implement some basic WWW operations to get asset bundles from remote server while displaying download progress and I can’t make it working. Build target: WebGL, Editor mode.
As per the doc the usual way to go is to yield return unityWebRequest.Send() (let’s say unityWebRequest is UnityWebRequest instance) method however it’s useless if you need to do something while Unity is working on HTTP request.
If we need to hang on in a loop we have to fire Send() and then check some condition that could tell us whether request is finished or it’s not to break the loop. However it’s not so easy to figure out such condition. UnityWebRequest attributes responsible for that are becoming lunatic and completely useless.
So what do we have here:
- unityWebRequest.isDone
- unityWebRequest.Send().isDone (AsyncOperation returned from Send)
- DownloadHandlerAssetBundle.isDone
- unityWebRequest.progress != 1.0f (using approximate equality algo)
- unityWebRequest.Send().downloadProgress != 1.0f
It appeared that all of them are unreliable and cannot be used for polling loop:
- unityWebRequest.isDone
Debug.Log(">>>> WWWIsDone started");
this.www = UnityWebRequest.GetAssetBundle(URL);
Debug.Log("Before sending ...");
this.www.Send();
Debug.Log("Done");
// while (www.downloadProgress < 1.0f)
while (!www.isDone)
{
Debug.Log("Inside waiting loop, updating progress");
Debug.Log(www.downloadProgress);
Debug.Log(www.isDone);
this.sliderProgressWWW.value = www.downloadProgress;
yield return new WaitForEndOfFrame();
}
DownloadHandlerAssetBundle assetHandler = (DownloadHandlerAssetBundle)this.www.downloadHandler;
if (assetHandler.assetBundle == null)
{
Debug.LogError("assetBundle is null!");
}
else
{
Debug.Log(string.Join("\n", assetHandler.assetBundle.GetAllAssetNames()));
assetHandler.assetBundle.Unload(true);
}
Debug.Log("<<<< WWWIsDone finished");
It logs 0, False, then some small value like 0.04161367, False then boom! Loop’s done (isDone is true) but asset bundle is null. Not quite sure what’s happening.
If I add 2-3 seconds delay asset bundle becomes valid and fully loaded so isDone isn’t reflecting actual readiness here.
Ok keep moving.
- unityWebRequest.Send().isDone (AsyncOperation returned from Send)
Debug.Log(">>>> AsyncOpIsDone started");
this.www = UnityWebRequest.GetAssetBundle(URL);
Debug.Log("Before sending ...");
AsyncOperation ao = this.www.Send();
Debug.Log("Done");
while (!ao.isDone)
{
Debug.Log("Inside waiting loop, updating progress");
this.sliderProgressWWW.value = www.downloadProgress;
this.sliderProgressAsyncOp.value = ao.progress;
Debug.Log(www.downloadProgress);
Debug.Log(www.isDone);
Debug.Log(ao.progress);
Debug.Log(ao.isDone);
yield return new WaitForEndOfFrame();
}
DownloadHandlerAssetBundle assetHandler = (DownloadHandlerAssetBundle)this.www.downloadHandler;
if (assetHandler.assetBundle == null)
{
Debug.LogError("assetBundle is null!");
}
else
{
Debug.Log(string.Join("\n", assetHandler.assetBundle.GetAllAssetNames()));
assetHandler.assetBundle.Unload(true);
}
Debug.Log("<<<< AsyncOpIsDone finished");
Exactly the same like in case 1, AsyncOperation.isDone is working in the same weird way as UnityWebRequest.isDone does, couple of frames with progress going up and finally isDone = true, asset bundle is null…
Nvm more to go.
- DownloadHandlerAssetBundle.isDone
Debug.Log(">>>> HandlerIsDone started");
this.www = UnityWebRequest.GetAssetBundle(URL);
DownloadHandlerAssetBundle assetHandler = (DownloadHandlerAssetBundle)this.www.downloadHandler;
Debug.Log("Before sending ...");
this.www.Send();
Debug.Log("Done");
while (!assetHandler.isDone)
{
Debug.Log("Inside waiting loop, updating progress");
this.sliderProgressWWW.value = www.downloadProgress;
Debug.Log(www.downloadProgress);
Debug.Log(www.isDone);
yield return new WaitForEndOfFrame();
}
if (assetHandler.assetBundle == null)
{
Debug.LogError("assetBundle is null!");
}
else
{
Debug.Log(string.Join("\n", assetHandler.assetBundle.GetAllAssetNames()));
assetHandler.assetBundle.Unload(true);
}
Debug.Log("<<<< HandlerIsDone finished");
The weirdest one, just infinite loop. Download handler never reaches isDone being true (which is out of sync with actual bundle being available with 2-3 sec delay).
4+5. progress != 1.0f
Case 2 but with the following condition:
while (www.downloadProgress < 1.0f)
Output is curious:
Frame 1: UWR.downloadProgress: 0, UWR.isDone: false, AO.progress: 0, AO.isDone: false
Frame 2: UWR.downloadProgress: 0.06242051, UWR.isDone: false, AO.progress: 0.08322734, AO.isDone: false
Frame 3: UWR.downloadProgress: 0.4993641, UWR.isDone: true, AO.progress: 1, AO.isDone: true
Frame 4: UWR.downloadProgress: 0.8530803, UWR.isDone: true, AO.progress: 1, AO.isDone: true
Frame 5: UWR.downloadProgress: 0 (!!!), UWR.isDone: true, AO.progress: 1, AO.isDone: true
What… 0 then 0.5 then isDone is true, then back to 0.
As a conclusion the only viable solution would be checking UWR.downloadProgress whether it got up from 0 to some value and then back to 0, this is enough to say asset bundle is ready and isn’t null!
Attaching project.
Shall I submit this as a bug?
Such behavior basically contradicts documentation here.
Thanks.
2623759–184291–UnityWebRequestDemo.zip (36.9 KB)