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