Loadlevel.async stops at ~90%?

Hi all, tried to use the loadlevelasync function, as I understand those are useable with the free version of unity 5? If they’re not, well, I guess that would explain it…

If they are, well, here is my relevant code:

AsyncOperation loadLevel;

IEnumerator LoadNextLevel(){
	loadLevel = Application.LoadLevelAsync(scene);
	loadLevel.allowSceneActivation = false;
	yield return loadLevel;
	Debug.Log("loading complete");

}
void Update(){

	if(loadLevel != null){
		loadBar.fillAmount = loadLevel.progress;
		if(loadLevel.isDone){
			beginButton.interactable = true;
		}else{
			beginButton.interactable = false;
			//backButton.interactable = false;
		}
	}
}

void Start () {

	StartCoroutine(LoadNextLevel());
}

I don’t get any errors or anything, the loadbar fills to about 90% and then just…stops,
and I never see my ‘loading complete’ debug statement. So…am I doing something wrong or do I have to get the pro version in order for this to work?

AsyncOperation.isDone will never be true if AsyncOperation.allowSceneActivation is false.
Progress will stop at around 0.9f. You can work around this to do whatever needs to be done before the final load takes place by waiting until progress has reached 0.9f, and end with allowing the scene activation again after you’ve done what you need to prior to that.
Example:

using UnityEngine;
using System.Collections;

public class LoadLevel : MonoBehaviour {
	public string level;
	private string progress = "";	// Name of scene to load.
	private bool isLoading = false;
	private bool doneLoading = false;
	private bool allowLoading = false;
	private void OnGUI() {
		GUILayout.BeginVertical("box");
		if (!isLoading) {
			if (GUILayout.Button ("Begin Load")) {
				isLoading = true;
				StartCoroutine(LoadRoutine());
			}
		} else {
			if (doneLoading) {
				if (GUILayout.Button ("Actually Load")) {
					allowLoading = true;
					StartCoroutine(LoadRoutine());
				}
			}
			GUILayout.Label(progress);
		}

		GUILayout.EndVertical();
	}
	private IEnumerator LoadRoutine() {
		AsyncOperation op = Application.LoadLevelAsync(level);
		op.allowSceneActivation = false;
		while (op.progress < 0.9f) {
			// Report progress etc.
			progress = "Progress: " + op.progress.ToString();
			yield return null;
		}
		// Show the UI button to actually start loaded level
		doneLoading = true;
		while(!allowLoading) {
			// Wait for allow button to be pushed.
			progress = "Progress: " + op.progress.ToString();
			yield return null;
		}
		// Allow the activation of the scene again.
		op.allowSceneActivation = true;
	}
}

One important thing to note is that anything that happens in Start or Awake on any of the MonoBehaviours in the new scene will not be performed asynchronously. It will only load the things that are in the scene before any code in it is actually run.
Another example of an Awake/Start script in the loaded level that takes a long time to process shows that this is the case:

using UnityEngine;
using System.Collections;

public class WorkAtStart : MonoBehaviour {
	public int calculations = 10000;
	public int iterations = 10000;
	public bool inAwake = true;
	public bool inStart = true;
	void Start () {
		if (inStart == true) {
			Calculate("Start");
		}
	}
	void Awake() {
		if (inAwake == true) {
			Calculate("Awake");
		}
	}

	string debugText = "Calculating...";
	private void Calculate(string funcName) {
		System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
		stopwatch.Start();
		Vector3 calc = Vector3.zero;
		// Do some random calculations:
		for (int i = 0; i < iterations; i++) {
			calc = Vector3.zero;
			for (int c = 0; c < calculations; c++) {
				calc = calc + Random.onUnitSphere;
			}
		}
		stopwatch.Stop();
		Debug.Log (stopwatch.Elapsed);
		debugText += "

" + funcName + ": " + stopwatch.Elapsed.ToString();
}

	private void OnGUI() {
		GUILayout.BeginVertical("box");
		GUILayout.Label(debugText);
		GUILayout.EndVertical();
	}
}

So if you need to do asynchronous things in Start/Awake you will need to fire up some Coroutines or do some threading inside the new scene.

It’s worth noting, for anyone else who finds this issue, that you cannot finish the LoadLevelAsync() operator if you don’t yield from a MonoBehaviour context.

public IEnumerator Open(string sceneId) {
  AsyncOperation op = Application.CanStreamedLevelBeLoaded(sceneId) ? Application.LoadLevelAsync(sceneId) : null;
  if (op != null) {
    op.allowSceneActivation = true;  // Do not defer loading
    while (!op.isDone) {
      yield return new WaitForSeconds(0.1f);
    }
  }
}

This above function will never complete beyond 0.9 loaded if it is not yielded into a monobehaviour context, like this:

public void LoadScene(MonoBehaviour context, string sceneId) {
  context.StartCoroutine(Open(sceneId));
}

This is a bug in Unity; without the MonoBehaviour to track, the AsyncOperation will never complete; waiting for 0.9 does NOT fix this issue and under no circumstances should you ever use the hack:

while (op.progress < 0.9) { ... }

As a workaround; this code above is incorrect; the new level will not have loaded when the function returns; specifically components and objects in the scene will not have spawned.

If you “yield return loadLevel”, then that’s it for that method; nothing beyond that point will ever get executed. That’s why you don’t see your debug log. Use “yield return null” if you want to continue execution (asynchronously).

As for the progress, I too see the progress reports stop around 90%, but then isDone becomes true shortly after that. So it doesn’t seem like a big deal to me. But note that it may be considerably smoother in a built app than when running within the editor, so be sure to test it there.

For lazy guys adding 11 to the progress value should do it.