DCDC/Assets/Scripts/SpatialAnchorManager.cs

210 lines
7.0 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SpatialAnchorManager : MonoBehaviour
{
private ApplicationManager _applicationManager;
// This reusable buffer helps reduce pressure on the garbage collector
private readonly List<OVRSpatialAnchor.UnboundAnchor> _unboundAnchors = new();
private const string NumUuidsPlayerPref = "NumUuids";
private void Awake()
{
_applicationManager = GetComponent<ApplicationManager>();
if (_applicationManager == null)
{
Debug.LogError("[DCDC] ApplicationManager component not found on the GameObject.");
}
}
private void Start()
{
_applicationManager.SetInProgress(true);
LoadSavedAnchors();
}
private void Update()
{
// spatial anchor options are only available to the host
if (_applicationManager.InProgress || _applicationManager.IsHost == false) return;
if (OVRInput.GetDown(OVRInput.Button.PrimaryIndexTrigger, OVRInput.Controller.RTouch))
{
CreateSpatialAnchor();
}
if (OVRInput.GetDown(OVRInput.Button.PrimaryThumbstick, OVRInput.Controller.RTouch))
{
UnsaveAllAnchors();
}
}
private async void LoadSavedAnchors()
{
try
{
if (!PlayerPrefs.HasKey(NumUuidsPlayerPref)) PlayerPrefs.SetInt(NumUuidsPlayerPref, 0);
var playerUuidCount = PlayerPrefs.GetInt(NumUuidsPlayerPref);
if (playerUuidCount == 0)
{
_applicationManager.SetInProgress(false);
return;
}
Debug.Log($"[DCDC] Loading {playerUuidCount} anchors from PlayerPrefs.");
var uuids = new Guid[playerUuidCount];
for (var i = 0; i < playerUuidCount; i++)
{
var uuidKey = "uuid" + i;
var currentUuid = PlayerPrefs.GetString(uuidKey);
uuids[i] = new Guid(currentUuid);
}
// Load
var result = await OVRSpatialAnchor.LoadUnboundAnchorsAsync(uuids, _unboundAnchors);
if (result.Success)
{
Debug.Log("[DCDC] Anchors loaded successfully.");
// Note result.Value is the same as _unboundAnchors
foreach (var unboundAnchor in result.Value)
{
unboundAnchor.LocalizeAsync().ContinueWith((success, _) =>
{
if (success)
{
unboundAnchor.TryGetPose(out var pose);
var spatialAnchor = Instantiate(_applicationManager.hostPlaceholderMarker, pose.position,
pose.rotation);
var button = spatialAnchor.gameObject.GetComponentInChildren<Button>();
if (button != null) button.onClick.AddListener(_applicationManager.AnchorSubmitted);
else Debug.LogError("[DCDC] Submit button not found on host placeholder marker.");
unboundAnchor.BindTo(spatialAnchor);
_applicationManager.SetAnchor(spatialAnchor);
}
else
{
Debug.LogError($"[DCDC] Localization failed for anchor {unboundAnchor.Uuid}");
}
}, unboundAnchor);
}
}
else
{
Debug.LogError($"[DCDC] Load failed with error {result.Status}.");
}
_applicationManager.SetInProgress(false);
}
catch (Exception e)
{
Debug.LogError($"[DCDC] Exception while loading anchors: {e}");
_applicationManager.SetInProgress(false);
}
}
private void CreateSpatialAnchor()
{
// one anchor only
if (_applicationManager.PlacedAnchor != null) return;
var workingAnchor = Instantiate(
_applicationManager.hostPlaceholderMarker,
// place the anchor .5 meters in z axis from the right controller's current position and rotation
OVRInput.GetLocalControllerPosition(OVRInput.Controller.RTouch) +
OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch) * Vector3.forward * 0.5f,
OVRInput.GetLocalControllerRotation(OVRInput.Controller.RTouch)
);
var button = workingAnchor.gameObject.GetComponentInChildren<Button>();
if (button != null) button.onClick.AddListener(_applicationManager.AnchorSubmitted);
else Debug.LogError("[DCDC] Submit button not found on host placeholder marker.");
_applicationManager.SetAnchor(workingAnchor);
StartCoroutine(AnchorCreated(workingAnchor));
}
private static IEnumerator AnchorCreated(OVRSpatialAnchor anchor)
{
while (!anchor.Created && !anchor.Localized)
{
yield return new WaitForEndOfFrame();
}
SaveLastCreatedAnchor(anchor);
}
private static async void SaveLastCreatedAnchor(OVRSpatialAnchor anchor)
{
try
{
var saved = await anchor.SaveAnchorAsync();
if (!saved.Success)
{
Debug.LogError($"[DCDC] Anchor Save failed with error: {saved.Status}");
return;
}
SaveUuidToPlayerPrefs(anchor.Uuid);
}
catch (Exception e)
{
Debug.LogError($"[DCDC] Exception while saving anchor: {e}");
}
}
private static void SaveUuidToPlayerPrefs(Guid uuid)
{
if (!PlayerPrefs.HasKey(NumUuidsPlayerPref))
{
PlayerPrefs.SetInt(NumUuidsPlayerPref, 0);
}
var numUuids = PlayerPrefs.GetInt(NumUuidsPlayerPref);
var strId = $"uuid{numUuids}";
PlayerPrefs.SetString(strId, uuid.ToString());
PlayerPrefs.SetInt(NumUuidsPlayerPref, ++numUuids);
Debug.Log($"[DCDC] PlayerPrefs saved: {strId} : {uuid}");
}
private void UnsaveAllAnchors()
{
var unsaved = _applicationManager.PlacedAnchor.EraseAnchorAsync();
if (unsaved.IsFaulted)
{
Debug.LogError($"[DCDC] Anchor Unsave failed with error: {unsaved.GetException()}");
return;
}
// remove the UI game object
Destroy(_applicationManager.PlacedAnchor.gameObject);
_applicationManager.SetAnchor(null);
ClearAllUuidsFromPlayerPrefs();
}
private static void ClearAllUuidsFromPlayerPrefs()
{
if (!PlayerPrefs.HasKey(NumUuidsPlayerPref)) return;
var numUuids = PlayerPrefs.GetInt(NumUuidsPlayerPref);
for (var i = 0; i < numUuids; i++)
{
PlayerPrefs.DeleteKey($"AnchorUuid_{i}");
}
PlayerPrefs.DeleteKey(NumUuidsPlayerPref);
PlayerPrefs.Save();
Debug.Log("[DCDC] All anchor UUIDs cleared from PlayerPrefs.");
}
}