/// <summary> /// Tries to restore the binding from persistent storage and PCF system /// </summary> IEnumerator RestoreBinding(string objId) { _state = State.RestoreBinding; if (MLPersistentStore.Contains(objId)) { MLContentBinding binding; MLResult result = MLPersistentStore.Load(objId, out binding); if (!result.IsOk) { SetError(result); _state = State.BindingComplete; } else { Binding = binding; Debug.Log("binding result : " + Binding.PCF.CurrentResult); Binding.GameObject = this.gameObject; MLContentBinder.Restore(Binding, HandleBindingRestore); } } else { BindToAllPCFs(); } while (_state != State.BindingComplete) { yield return(null); } yield break; }
/// <summary> /// Creates a binding to the closest PCF /// </summary> /// <returns>Must be executed as a Coroutine</returns> IEnumerator TryBindingToClosestPCF() { _done = false; MLResult returnResult = MLPersistentCoordinateFrames.FindClosestPCF(gameObject.transform.position, (result, returnPCF) => { if (result.IsOk && returnPCF.CurrentResult == MLResultCode.Ok) { Debug.Log("Binding to closest found PCF: " + returnPCF.CFUID); Binding = MLContentBinder.BindToPCF(gameObject.name, gameObject, returnPCF); MLPersistentStore.Save(Binding); SetComplete(true); _done = true; } else { Debug.LogErrorFormat("Error: MLPersistentPoint failed to find closest PCF. Reason: {0}", result); SetComplete(false); _done = true; } }); if (!returnResult.IsOk) { // Technically, if we reach this point, the system had a problem Debug.LogErrorFormat("Error: MLPersistentPoint failed to attempt to find closest PCF. Reason: {0}", returnResult); SetComplete(false); _done = true; } while (!_done) { yield return(null); } }
/// <summary> /// Tries to restore the binding or find closest PCF. /// </summary> void RestoreBinding(string objId) { if (MLPersistentStore.Contains(objId)) { MLContentBinding binding; MLResult result = MLPersistentStore.Load(objId, out binding); if (!result.IsOk) { SetError(new MLResult(result.Code, string.Format("Error: MLPersistentPoint failed to load binding. Reason: {0}", result))); SetComplete(false); } else { Binding = binding; Binding.GameObject = this.gameObject; MLContentBinder.Restore(Binding, HandleBindingRestore); } } else { StartCoroutine(BindToClosestPCF()); } }
/// <summary> /// Creates a binding to the closest PCF /// </summary> /// <returns>Must be executed as a Coroutine</returns> IEnumerator TryBindingToClosestPCF() { _done = false; MLResult returnResult = MLPersistentCoordinateFrames.FindClosestPCF(gameObject.transform.position, (pcfPositionResult, pcfWithPosition) => { if (pcfPositionResult.IsOk && pcfWithPosition != null && pcfWithPosition.CurrentResult == MLResultCode.Ok) { Debug.Log("Binding to closest found PCF: " + pcfWithPosition.CFUID); Binding = MLContentBinder.BindToPCF(UniqueId, gameObject, pcfWithPosition); MLPersistentStore.Save(Binding); NotifyChangeOfStatus(Status.BINDING_CREATED, MLResult.ResultOk); RegisterPCFEventHandlers(); _done = true; } else { Debug.LogErrorFormat("Error: MLPersistentBehavior failed to get PCF position. Reason: {0}", pcfPositionResult); NotifyChangeOfStatus(Status.BINDING_CREATE_FAILED, pcfPositionResult); _done = true; } }); if (!returnResult.IsOk) { Debug.LogErrorFormat("Error: MLPersistentBehavior failed to attempt to find closest PCF. Reason: {0}", returnResult); NotifyChangeOfStatus(Status.BINDING_CREATE_FAILED, returnResult); _done = true; } while (!_done) { yield return(null); } }
/// <summary> /// Destroys the given binding /// </summary> /// <param name="binding">Binding</param> void DestroyBindingInternal(MLContentBinding binding) { if (binding != null) { MLPersistentStore.DeleteBinding(binding); } }
///<summary> /// Starts the restoration process. /// </summary> void StartRestore() { MLResult result = MLPersistentStore.Start(); if (!result.IsOk) { SetError(result); enabled = false; return; } result = MLPersistentCoordinateFrames.Start(); if (!result.IsOk) { MLPersistentStore.Stop(); SetError(result); enabled = false; return; } result = MLPersistentCoordinateFrames.GetAllPCFs(out _allPCFs, MaxPCFsToBindTo); if (!result.IsOk) { MLPersistentStore.Stop(); MLPersistentCoordinateFrames.Stop(); SetError(result); enabled = false; return; } StartCoroutine(TryRestoreBinding()); }
/// <summary> /// Handler when PCF bound to is lost. It tries to look for reliable PCF to bind to. If no PCF /// is available, try again later. /// </summary> void HandlePCFLost() { _searchForPCF = null; MLResult result = MLPersistentCoordinateFrames.FindClosestPCF(transform.position, (findResult, returnPCF) => { if (findResult.IsOk && returnPCF != null && returnPCF.CurrentResult == MLResultCode.Ok) { UnregisterPCFEventHandlers(); Debug.LogFormat("Rebinding to closest found PCF: {0}", returnPCF.CFUID); Binding.PCF = returnPCF; MLResult bindingUpdateResult = Binding.Update(); if (!bindingUpdateResult.IsOk) { MLPersistentStore.Save(Binding); } RegisterPCFEventHandlers(); } else { Debug.LogFormat("MLPersistentBehavior failed to rebind to closest PCF. Reason: {0}. Retrying in {1} seconds", findResult, RetryDelayInSeconds); _searchForPCF = StartCoroutine(RetryFindPCFToRebind()); } }); if (!result.IsOk) { Debug.LogWarningFormat("Error: MLPersistentBehavior failed to attempt to find another closest PCF. Reason: {0}", result); } }
/// <summary> /// Destroys the given binding /// </summary> /// <param name="binding">Binding</param> void DestroyBindingInternal(MLContentBinding binding) { if (binding != null) { NotifyChangeOfStatus(Status.BINDING_DESTROYED, MLResult.ResultOk); MLPersistentStore.DeleteBinding(binding); } }
public void UpdateBinding() { if (transform.hasChanged) { Binding.Update(); MLPersistentStore.Save(Binding); } }
/// <summary> /// Bind this gameObject to a pcf /// </summary> /// <param name="pcf">The pcf to bind to</param> void BindToPCF(MLPCF pcf) { UnregisterPCFEventHandlers(); DestroyBinding(); Binding = MLContentBinder.BindToPCF(UniqueId, gameObject, pcf); MLPersistentStore.Save(Binding); NotifyChangeOfStatus(Status.BINDING_CREATED, MLResult.ResultOk); RegisterPCFEventHandlers(); _pcfLost = false; }
/// <summary> /// Saves the binding if transform has changed /// </summary> public void UpdateBinding() { if (transform.hasChanged) { // Note: this does not change the PCF bound to Binding.Update(); MLPersistentStore.Save(Binding); transform.hasChanged = false; } }
/// <summary> /// Handler for binding restore /// </summary> /// <param name="contentBinding">Content binding.</param> /// <param name="resultCode">Result code.</param> void HandleBindingRestore(MLContentBinding contentBinding, MLResult result) { _state = State.BindingComplete; Debug.Log("binding result : " + contentBinding.PCF.CurrentResult); if (!result.IsOk) { MLPersistentStore.DeleteBinding(contentBinding); Debug.LogFormat("Failed to restore : {0} - {1}. Result code:", gameObject.name, contentBinding.PCF.CFUID, result.Code); } }
/// <summary> /// Called externally to save its binding /// </summary> public void UpdateBinding() { if (transform.hasChanged) { // Note: this does not change the PCF bound to Binding.Update(); MLPersistentStore.Save(Binding); transform.hasChanged = false; NotifyChangeOfStatus(Status.BINDING_UPDATED, MLResult.ResultOk); } }
/// <summary> /// Determine and perform the appropriate action /// </summary> void CreateOrRestoreBinding() { if (MLPersistentStore.Contains(UniqueId)) { RestoreBinding(); } else { // Find closest PCF and create binding to it StartCoroutine(BindToClosestPCF()); } }
/// <summary> /// Clean Up /// </summary> private void OnDestroy() { if (MLPersistentStore.IsStarted) { MLPersistentStore.Stop(); } if (MLPersistentCoordinateFrames.IsStarted) { MLPersistentCoordinateFrames.Stop(); MLPersistentCoordinateFrames.OnReady -= HandleReady; } }
/// <summary> /// Handler when MLPersistentCoordinateFrames becomes ready /// </summary> private void HandleReady() { MLPersistentCoordinateFrames.OnReady -= HandleReady; if (MLPersistentStore.Contains(UniqueId)) { RestoreBinding(); } else { // Find closest PCF and create binding to that StartCoroutine(BindToClosestPCF()); } }
/// <summary> /// Shuts down the systems started in Start /// </summary> void OnDestroy() { if (MLPersistentCoordinateFrames.IsStarted) { MLPersistentCoordinateFrames.Stop(); } if (MLPersistentStore.IsStarted) { MLPersistentStore.Stop(); } PrivilegeRequester.OnPrivilegesDone -= HandlePrivilegesDone; }
/// <summary> /// Clean Up /// </summary> void OnDestroy() { if (MLPersistentStore.IsStarted) { MLPersistentStore.Stop(); } if (MLPersistentCoordinateFrames.IsStarted) { MLPersistentCoordinateFrames.Stop(); } UnregisterPCFEventHandlers(); StopAllCoroutines(); }
/// <summary> /// Clean up /// </summary> void OnDestroy() { if (MLPersistentStore.IsStarted) { MLPersistentStore.Stop(); } if (MLPersistentCoordinateFrames.IsStarted) { MLPersistentCoordinateFrames.Stop(); } foreach (GameObject go in _pcfObjs) { Destroy(go); } }
/// <summary> /// Handler when MLPersistentCoordinateFrames becomes ready /// </summary> void HandleInitialized(MLResult status) { MLPersistentCoordinateFrames.OnInitialized -= HandleInitialized; if (status.IsOk) { CreateOrRestoreBinding(); } else { Debug.LogErrorFormat("Error: MLPersistentCoordinateFrames failed to initialize, disabling script. Reason: {0}", status); MLPersistentStore.Stop(); MLPersistentCoordinateFrames.Stop(); Invoke("StartAPIs", 3); } }
/// <summary> /// Start up /// Note: This requires the privilege to be granted prior to Start() /// </summary> void Start() { MLResult result = MLPersistentStore.Start(); if (!result.IsOk) { Debug.LogErrorFormat("MLPersistentPoint failed starting MLPersistentStore, disabling script. Reason: {0}", result); enabled = false; return; } result = MLPersistentCoordinateFrames.Start(); if (!result.IsOk) { MLPersistentStore.Stop(); Debug.LogErrorFormat("MLPersistentPoint failed starting MLPersistentCoordinateFrames, disabling script. Reason: {0}", result); enabled = false; return; } if (string.IsNullOrEmpty(UniqueId)) { Debug.LogWarning("Unique Id is empty will try to use game object's name. It's good to provide a unique id for virtual objects to avoid weird behavior."); if (string.IsNullOrEmpty(gameObject.name)) { SetError(new MLResult(MLResultCode.UnspecifiedFailure, "Either UniqueId or name should be non empty. Disabling component")); enabled = false; return; } UniqueId = gameObject.name; } else { gameObject.name = UniqueId; } if (MLPersistentCoordinateFrames.IsReady) { RestoreBinding(gameObject.name); } else { MLPersistentCoordinateFrames.OnReady += HandleReady; } }
/// <summary> /// Tries to restore the binding /// </summary> void RestoreBinding() { MLContentBinding binding; MLResult result = MLPersistentStore.Load(UniqueId, out binding); if (!result.IsOk) { Debug.LogErrorFormat("Error: MLPersistentBehavior failed to load binding. Reason: {0}", result); NotifyChangeOfStatus(Status.RESTORE_FAILED, result); } else { Binding = binding; Binding.GameObject = this.gameObject; MLContentBinder.Restore(Binding, HandleBindingRestore); } }
/// <summary> /// Attempts to start the MLPersistentStore and MLPersistentCoordinateFrames APIs /// </summary> void StartAPIs() { MLResult result = MLPersistentStore.Start(); if (!result.IsOk) { Debug.LogErrorFormat("MLPersistentBehavior failed starting MLPersistentStore, disabling script. Reason: {0}", result); enabled = false; return; } result = MLPersistentCoordinateFrames.Start(); if (!result.IsOk) { MLPersistentStore.Stop(); Debug.LogErrorFormat("MLPersistentBehavior failed starting MLPersistentCoordinateFrames, disabling script. Reason: {0}", result); enabled = false; return; } if (string.IsNullOrEmpty(UniqueId)) { Debug.LogWarning("Unique Id is empty will try to use game object's name. It's good to provide a unique id for virtual objects to avoid weird behavior."); if (string.IsNullOrEmpty(gameObject.name)) { Debug.LogError("Either UniqueId or name should be non empty. Disabling component"); enabled = false; return; } UniqueId = gameObject.name; } if (MLPersistentCoordinateFrames.IsReady) { CreateOrRestoreBinding(); } else { MLPersistentCoordinateFrames.OnInitialized += HandleInitialized; } }
/// <summary> /// Start this instance. /// </summary> void Start() { MLResult result = MLPersistentStore.Start(); if (!result.IsOk) { SetError("Failed to start persistent store. Disabling component"); enabled = false; return; } result = MLPersistentCoordinateFrames.Start(); if (!result.IsOk) { MLPersistentStore.Stop(); SetError("Failed to start coordinate frames system. disabling component"); enabled = false; return; } if (_representativePrefab == null) { SetError("Error: _representativePrefab must be set"); enabled = false; return; } List <MLPCF> pcfList; result = MLPersistentCoordinateFrames.GetAllPCFs(out pcfList, int.MaxValue); if (!result.IsOk) { MLPersistentStore.Stop(); MLPersistentCoordinateFrames.Stop(); SetError(result.ToString()); enabled = false; return; } TryShowingAllPCFs(pcfList); }
/// <summary> /// Finds the closest pcf for this persistent point. /// </summary> void BindToAllPCFs() { _state = State.BindToAllPCFs; string suffix = ""; int count = 0; // In the loop below we try to associate the persitent point with not only // the closest but all pcfs in the surrounding. This will increase the probablilty // of restoration on reboots. It's costly in terms of disk space so we will limit it to // a max foreach (MLPCF pcf in _allPCFs) { string objectName = gameObject.name + suffix; var returnResult = MLPersistentCoordinateFrames.GetPCFPosition(pcf, (result, returnPCF) => { if (result.IsOk && pcf.CurrentResult == MLResultCode.Ok) { Debug.Log("binding to PCF: " + pcf.CFUID); Binding = MLContentBinder.BindToPCF(objectName, gameObject, pcf); MLPersistentStore.Save(Binding); } else { Debug.LogWarningFormat("Failed to find the position for PCF {0}", returnPCF.CFUID); } }); if (!returnResult.IsOk) { Debug.LogError("Failed to GetPCF"); break; } suffix = "-" + count; count++; } _state = State.BindingComplete; }
/// <summary> /// Handler for binding restore /// </summary> /// <param name="contentBinding">Content binding.</param> /// <param name="resultCode">Result code.</param> void HandleBindingRestore(MLContentBinding contentBinding, MLResult result) { if (!result.IsOk) { if (NumRetriesForRestore > 0) { NumRetriesForRestore--; Debug.LogWarningFormat("Failed to restore: {0} - {1}. Retries left: {2}. Result Code: {3}", gameObject.name, contentBinding.PCF.CFUID, NumRetriesForRestore, result); StartCoroutine(TryRestore()); } else { Debug.LogErrorFormat("Failed to restore : {0} - {1}. Deleting Binding. Result code: {2}", gameObject.name, contentBinding.PCF.CFUID, result); MLPersistentStore.DeleteBinding(contentBinding); SetComplete(false); } } else { SetComplete(true); } }
/// <summary> /// Called externally to save its binding /// </summary> public void UpdateBinding() { Binding.Update(); MLPersistentStore.Save(Binding); NotifyChangeOfStatus(Status.BINDING_UPDATED, MLResult.ResultOk); }
/// <summary> /// Destroys the binding /// Note: Game Object is still alive. It is the responsibility /// of the caller to deal with the Game Object /// </summary> public void DestroyBinding() { MLPersistentStore.DeleteBinding(Binding); }