forked from cgvr/DeltaVR
		
	
		
			
				
	
	
		
			266 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			266 lines
		
	
	
		
			7.1 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.IO;
 | 
						|
 | 
						|
using UnityEngine;
 | 
						|
using UnityEngine.SceneManagement;
 | 
						|
using UnityEngine.UI;
 | 
						|
 | 
						|
public class OVRSceneLoader : MonoBehaviour
 | 
						|
{
 | 
						|
	public const string externalStoragePath = "/sdcard/Android/data";
 | 
						|
	public const string sceneLoadDataName = "SceneLoadData.txt";
 | 
						|
	public const string resourceBundleName = "asset_resources";
 | 
						|
 | 
						|
	public float sceneCheckIntervalSeconds = 1f;
 | 
						|
	public float logCloseTime = 5.0f;
 | 
						|
 | 
						|
	public Canvas mainCanvas;
 | 
						|
	public Text logTextBox;
 | 
						|
 | 
						|
	private AsyncOperation loadSceneOperation;
 | 
						|
	private string formattedLogText;
 | 
						|
 | 
						|
	private float closeLogTimer;
 | 
						|
	private bool closeLogDialogue;
 | 
						|
 | 
						|
	private bool canvasPosUpdated;
 | 
						|
 | 
						|
	private struct SceneInfo
 | 
						|
	{
 | 
						|
		public List<string> scenes;
 | 
						|
		public long version;
 | 
						|
 | 
						|
		public SceneInfo(List<string> sceneList, long currentSceneEpochVersion)
 | 
						|
		{
 | 
						|
			scenes = sceneList;
 | 
						|
			version = currentSceneEpochVersion;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	private string scenePath = "";
 | 
						|
	private string sceneLoadDataPath = "";
 | 
						|
	private List<AssetBundle> loadedAssetBundles = new List<AssetBundle>();
 | 
						|
	private SceneInfo currentSceneInfo;
 | 
						|
 | 
						|
	private void Awake()
 | 
						|
	{
 | 
						|
		// Make it presist across scene to continue checking for changes
 | 
						|
		DontDestroyOnLoad(this.gameObject);
 | 
						|
	}
 | 
						|
 | 
						|
	void Start()
 | 
						|
	{
 | 
						|
		string applicationPath = Path.Combine(externalStoragePath, Application.identifier);
 | 
						|
		scenePath = Path.Combine(applicationPath, "cache/scenes");
 | 
						|
		sceneLoadDataPath = Path.Combine(scenePath, sceneLoadDataName);
 | 
						|
 | 
						|
		closeLogDialogue = false;
 | 
						|
		StartCoroutine(DelayCanvasPosUpdate());
 | 
						|
 | 
						|
		currentSceneInfo = GetSceneInfo();
 | 
						|
		// Check valid scene info has been fetched, and load the scenes
 | 
						|
		if (currentSceneInfo.version != 0 && !string.IsNullOrEmpty(currentSceneInfo.scenes[0]))
 | 
						|
		{
 | 
						|
			LoadScene(currentSceneInfo);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	private void LoadScene(SceneInfo sceneInfo)
 | 
						|
	{
 | 
						|
		AssetBundle mainSceneBundle = null;
 | 
						|
		Debug.Log("[OVRSceneLoader] Loading main scene: " + sceneInfo.scenes[0] + " with version " + sceneInfo.version.ToString());
 | 
						|
 | 
						|
		logTextBox.text += "Target Scene: " + sceneInfo.scenes[0] + "\n";
 | 
						|
		logTextBox.text += "Version: " + sceneInfo.version.ToString() + "\n";
 | 
						|
 | 
						|
		// Load main scene and dependent additive scenes (if any)
 | 
						|
		Debug.Log("[OVRSceneLoader] Loading scene bundle files.");
 | 
						|
		// Fetch all files under scene cache path, excluding unnecessary files such as scene metadata file
 | 
						|
		string[] bundles = Directory.GetFiles(scenePath, "*_*");
 | 
						|
		logTextBox.text += "Loading " + bundles.Length + " bundle(s) . . . ";
 | 
						|
		string mainSceneBundleFileName = "scene_" + sceneInfo.scenes[0].ToLower();
 | 
						|
		try
 | 
						|
		{
 | 
						|
			foreach (string b in bundles)
 | 
						|
			{
 | 
						|
				var assetBundle = AssetBundle.LoadFromFile(b);
 | 
						|
				if (assetBundle != null)
 | 
						|
				{
 | 
						|
					Debug.Log("[OVRSceneLoader] Loading file bundle: " + assetBundle.name == null ? "null" : assetBundle.name);
 | 
						|
					loadedAssetBundles.Add(assetBundle);
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					Debug.LogError("[OVRSceneLoader] Loading file bundle failed");
 | 
						|
				}
 | 
						|
 | 
						|
				if (assetBundle.name == mainSceneBundleFileName)
 | 
						|
				{
 | 
						|
					mainSceneBundle = assetBundle;
 | 
						|
				}
 | 
						|
 | 
						|
				if (assetBundle.name == resourceBundleName)
 | 
						|
				{
 | 
						|
					OVRResources.SetResourceBundle(assetBundle);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		catch(Exception e)
 | 
						|
		{
 | 
						|
			logTextBox.text += "<color=red>" + e.Message + "</color>";
 | 
						|
			return;
 | 
						|
		}
 | 
						|
		logTextBox.text += "<color=green>DONE\n</color>";
 | 
						|
 | 
						|
		if (mainSceneBundle != null)
 | 
						|
		{
 | 
						|
			logTextBox.text += "Loading Scene: {0:P0}\n";
 | 
						|
			formattedLogText = logTextBox.text;
 | 
						|
			string[] scenePaths = mainSceneBundle.GetAllScenePaths();
 | 
						|
			string sceneName = Path.GetFileNameWithoutExtension(scenePaths[0]);
 | 
						|
			
 | 
						|
			loadSceneOperation = SceneManager.LoadSceneAsync(sceneName);
 | 
						|
			loadSceneOperation.completed += LoadSceneOperation_completed;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			logTextBox.text += "<color=red>Failed to get main scene bundle.\n</color>";
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	private void LoadSceneOperation_completed(AsyncOperation obj)
 | 
						|
	{
 | 
						|
		StartCoroutine(onCheckSceneCoroutine());
 | 
						|
		StartCoroutine(DelayCanvasPosUpdate());
 | 
						|
 | 
						|
		closeLogTimer = 0;
 | 
						|
		closeLogDialogue = true;
 | 
						|
 | 
						|
		logTextBox.text += "Log closing in {0} seconds.\n";
 | 
						|
		formattedLogText = logTextBox.text;
 | 
						|
	}
 | 
						|
 | 
						|
	public void Update()
 | 
						|
	{
 | 
						|
		// Display scene load percentage
 | 
						|
		if (loadSceneOperation != null)
 | 
						|
		{
 | 
						|
			if (!loadSceneOperation.isDone)
 | 
						|
			{
 | 
						|
				logTextBox.text = string.Format(formattedLogText, loadSceneOperation.progress + 0.1f);
 | 
						|
				if (loadSceneOperation.progress >= 0.9f)
 | 
						|
				{
 | 
						|
					logTextBox.text = formattedLogText.Replace("{0:P0}", "<color=green>DONE</color>");
 | 
						|
					logTextBox.text += "Transitioning to new scene.\nLoad times will vary depending on scene complexity.\n";
 | 
						|
					
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		UpdateCanvasPosition();
 | 
						|
 | 
						|
		// Wait a certain time before closing the log dialogue after the scene has transitioned
 | 
						|
		if (closeLogDialogue)
 | 
						|
		{
 | 
						|
			if (closeLogTimer < logCloseTime)
 | 
						|
			{
 | 
						|
				closeLogTimer += Time.deltaTime;
 | 
						|
				logTextBox.text = string.Format(formattedLogText, (int)(logCloseTime - closeLogTimer));
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				mainCanvas.gameObject.SetActive(false);
 | 
						|
				closeLogDialogue = false;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	private void UpdateCanvasPosition()
 | 
						|
	{
 | 
						|
		// Update canvas camera reference and position if the main camera has changed
 | 
						|
		if (mainCanvas.worldCamera != Camera.main)
 | 
						|
		{
 | 
						|
			mainCanvas.worldCamera = Camera.main;
 | 
						|
			if (Camera.main != null)
 | 
						|
			{
 | 
						|
				Vector3 newPosition = Camera.main.transform.position + Camera.main.transform.forward * 0.3f;
 | 
						|
				gameObject.transform.position = newPosition;
 | 
						|
				gameObject.transform.rotation = Camera.main.transform.rotation;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	private SceneInfo GetSceneInfo()
 | 
						|
	{
 | 
						|
		SceneInfo sceneInfo = new SceneInfo();
 | 
						|
		try
 | 
						|
		{
 | 
						|
			StreamReader reader = new StreamReader(sceneLoadDataPath);
 | 
						|
			sceneInfo.version = System.Convert.ToInt64(reader.ReadLine());
 | 
						|
			List<string> sceneList = new List<string>();
 | 
						|
			while (!reader.EndOfStream)
 | 
						|
			{
 | 
						|
				sceneList.Add(reader.ReadLine());
 | 
						|
			}
 | 
						|
			sceneInfo.scenes = sceneList;
 | 
						|
		}
 | 
						|
		catch
 | 
						|
		{
 | 
						|
			logTextBox.text += "<color=red>Failed to get scene info data.\n</color>";
 | 
						|
		}
 | 
						|
		return sceneInfo;
 | 
						|
	}
 | 
						|
 | 
						|
	// Update canvas position after a slight delay to get accurate headset position after scene transitions
 | 
						|
	IEnumerator DelayCanvasPosUpdate()
 | 
						|
	{
 | 
						|
		yield return new WaitForSeconds(0.1f);
 | 
						|
		UpdateCanvasPosition();
 | 
						|
	}
 | 
						|
 | 
						|
	IEnumerator onCheckSceneCoroutine()
 | 
						|
	{
 | 
						|
		SceneInfo newSceneInfo;
 | 
						|
		while (true)
 | 
						|
		{
 | 
						|
			newSceneInfo = GetSceneInfo();
 | 
						|
			if (newSceneInfo.version != currentSceneInfo.version)
 | 
						|
			{
 | 
						|
				Debug.Log("[OVRSceneLoader] Scene change detected.");
 | 
						|
 | 
						|
				// Unload all asset bundles
 | 
						|
				foreach (var b in loadedAssetBundles)
 | 
						|
				{
 | 
						|
					if (b != null)
 | 
						|
					{
 | 
						|
						b.Unload(true);
 | 
						|
					}
 | 
						|
				}
 | 
						|
				loadedAssetBundles.Clear();
 | 
						|
 | 
						|
				// Unload all scenes in the hierarchy including main scene and 
 | 
						|
				// its dependent additive scenes.
 | 
						|
				int activeScenes = SceneManager.sceneCount;
 | 
						|
				for (int i = 0; i < activeScenes; i++)
 | 
						|
				{
 | 
						|
					SceneManager.UnloadSceneAsync(SceneManager.GetSceneAt(i));
 | 
						|
				}
 | 
						|
				DestroyAllGameObjects();
 | 
						|
				SceneManager.LoadSceneAsync("OVRTransitionScene");
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			yield return new WaitForSeconds(sceneCheckIntervalSeconds);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	void DestroyAllGameObjects()
 | 
						|
	{
 | 
						|
		foreach (GameObject go in Resources.FindObjectsOfTypeAll(typeof(GameObject)) as GameObject[])
 | 
						|
		{
 | 
						|
			Destroy(go);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 |