1
0
mirror of https://github.com/xiaopeng12138/MaiDXR.git synced 2024-12-19 04:15:53 +01:00
MaiDXR/Assets/Oculus/VR/Scripts/OVRSceneManager.cs
2022-08-20 21:35:57 +02:00

700 lines
28 KiB
C#

/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using UnityEngine;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEngine.Serialization;
using Debug = UnityEngine.Debug;
/// <summary>
/// A manager for <see cref="OVRSceneAnchor"/>s created using the Guardian's Room Capture feature.
/// </summary>
public class OVRSceneManager : MonoBehaviour
{
/// <summary>
/// A prefab that will be used to instantiate any Plane found when querying the Scene model
/// </summary>
[FormerlySerializedAs("planePrefab")]
[Tooltip("A prefab that will be used to instantiate any Plane found when querying the Scene model")]
public OVRSceneAnchor PlanePrefab;
/// <summary>
/// A prefab that will be used to instantiate any Volume found when querying the Scene model
/// </summary>
[FormerlySerializedAs("volumePrefab")]
[Tooltip("A prefab that will be used to instantiate any Volume found when querying the Scene model")]
public OVRSceneAnchor VolumePrefab;
/// <summary>
/// Overrides the instantiation of the generic Plane and Volume prefabs with specialized ones
/// </summary>
[FormerlySerializedAs("prefabOverrides")]
[Tooltip("Overrides the instantiation of the generic Plane/Volume prefabs with specialized ones")]
public List<OVRScenePrefabOverride> PrefabOverrides = new List<OVRScenePrefabOverride>();
/// <summary>
/// When true, verbose debug logs will be emitted.
/// </summary>
[FormerlySerializedAs("verboseLogging")]
[Tooltip("When enabled, verbose debug logs will be emitted.")]
public bool VerboseLogging;
#region Events
/// <summary>
/// This event fires when the OVR Scene Manager has correctly loaded the scene definition and
/// instantiated the prefabs for the planes and volumes. Trap it to know that the logic of the
/// experience can now continue.
/// </summary>
public Action SceneModelLoadedSuccessfully;
/// <summary>
///This event fires when a query load the Scene Model returns no result. It can indicate that the,
/// user never used the Room Capture in the space they are in.
/// </summary>
public Action NoSceneModelToLoad;
/// <summary>
/// This event will fire after the Room Capture successfully returns. It can be trapped to load the
/// scene Model.
/// </summary>
public Action SceneCaptureReturnedWithoutError;
/// <summary>
/// This event will fire if an error occurred while trying to send the user to Room Capture.
/// </summary>
public Action UnexpectedErrorWithSceneCapture;
#endregion
/// <summary>
/// Represents the available classifications for each <see cref="OVRSceneAnchor"/>.
/// </summary>
public static class Classification
{
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as a floor.
/// </summary>
public const string Floor = "FLOOR";
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as a ceiling.
/// </summary>
public const string Ceiling = "CEILING";
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as a wall face.
/// </summary>
public const string WallFace = "WALL_FACE";
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as a desk.
/// </summary>
public const string Desk = "DESK";
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as a couch.
/// </summary>
public const string Couch = "COUCH";
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as a door frame.
/// </summary>
public const string DoorFrame = "DOOR_FRAME";
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as a window frame.
/// </summary>
public const string WindowFrame = "WINDOW_FRAME";
/// <summary>
/// Represents an <see cref="OVRSceneAnchor"/> that is classified as other.
/// </summary>
public const string Other = "OTHER";
/// <summary>
/// The list of possible semantic labels.
/// </summary>
public static IReadOnlyList<string> List { get; } = new[]
{
Floor,
Ceiling,
WallFace,
Desk,
Couch,
DoorFrame,
WindowFrame,
Other
};
}
/// <summary>
/// A container for the set of <see cref="OVRSceneAnchor"/>s representing a room.
/// </summary>
public class RoomLayoutInformation
{
/// <summary>
/// The <see cref="OVRScenePlane"/> representing the floor of the room.
/// </summary>
public OVRScenePlane Floor;
/// <summary>
/// The <see cref="OVRScenePlane"/> representing the ceiling of the room.
/// </summary>
public OVRScenePlane Ceiling;
/// <summary>
/// The set of <see cref="OVRScenePlane"/> representing the walls of the room.
/// </summary>
public List<OVRScenePlane> Walls = new List<OVRScenePlane>();
}
/// <summary>
/// Describes the room layout stored by the Guardian.
/// </summary>
public RoomLayoutInformation RoomLayout;
#region Private Vars
private enum QueryMode
{
QueryAllAnchors, // Get entire Scene
QueryByUuid, // Get a specific entity
QueryAllBounded2DEnabled, // Get all planar entities
QueryAllRoomLayoutEnabledForAllEntitiesInside, // Get Ceiling/Floor/Walls + other entities in Space Container.
QueryAllRoomLayoutEnabledForRoomBox, // Get Ceiling/Floor/Walls only.
}
private readonly Dictionary<Guid, int> _orderedRoomGuids = new Dictionary<Guid, int>();
private Comparison<OVRScenePlane> _wallOrderComparer;
// Maintain UUIDs to be used.
private List<Guid> _uuidsToQuery;
private QueryMode _currentQueryMode = QueryMode.QueryAllAnchors;
// We use this to store the request id when attempting to load the scene
private UInt64 _sceneCaptureRequestId = UInt64.MaxValue;
private HashSet<UInt64> _individualRequestIds = new HashSet<UInt64>();
// Spatial entities that we know about but are waiting for their "locatable" component to be enabled.
private readonly Dictionary<OVRSpace, OVRPlugin.SpaceQueryResult> _pendingLocatable =
new Dictionary<OVRSpace, OVRPlugin.SpaceQueryResult>();
#endregion
internal struct LogForwarder
{
public void Log(string context, string message) => Debug.Log($"[{context}] {message}");
public void LogWarning(string context, string message) => Debug.LogWarning($"[{context}] {message}");
public void LogError(string context, string message) => Debug.LogError($"[{context}] {message}");
}
internal LogForwarder? Verbose => VerboseLogging ? new LogForwarder() : (LogForwarder?)null;
internal static class Development
{
[Conditional("DEVELOPMENT_BUILD")]
[Conditional("UNITY_EDITOR")]
public static void Log(string context, string message) => Debug.Log($"[{context}] {message}");
[Conditional("DEVELOPMENT_BUILD")]
[Conditional("UNITY_EDITOR")]
public static void LogWarning(string context, string message) => Debug.LogWarning($"[{context}] {message}");
[Conditional("DEVELOPMENT_BUILD")]
[Conditional("UNITY_EDITOR")]
public static void LogError(string context, string message) => Debug.LogError($"[{context}] {message}");
}
void Awake()
{
_wallOrderComparer = (planeA, planeB) =>
{
bool TryGetUuid(OVRScenePlane plane, out int index)
{
var guid = plane.GetComponent<OVRSceneAnchor>().Uuid;
if (_orderedRoomGuids.TryGetValue(guid, out index)) return true;
Development.LogWarning(nameof(OVRSceneManager), $"{nameof(OVRScenePlane)} {guid} does not belong to the current room layout.");
return false;
}
if (!TryGetUuid(planeA, out var indexA)) return 0;
if (!TryGetUuid(planeB, out var indexB)) return 0;
return indexA.CompareTo(indexB);
};
// Only allow one instance at runtime.
if (FindObjectsOfType<OVRSceneManager>().Length > 1)
{
new LogForwarder().LogError(nameof(OVRSceneManager),
$"Found multiple {nameof(OVRSceneManager)}s. Destroying '{name}'.");
enabled = false;
DestroyImmediate(this);
}
}
/// <summary>
/// Loads the scene model from the Guardian.
/// </summary>
/// <remarks>
/// When running on Quest, Scene is queried to retrieve the entities describing the Scene Model. In the Editor,
/// the Scene Model is loaded over Link.
/// </remarks>
/// <returns>Returns true if the query was successfully registered</returns>
public bool LoadSceneModel()
{
_currentQueryMode = QueryMode.QueryAllRoomLayoutEnabledForAllEntitiesInside;
return LoadSpatialEntities();
}
/// <summary>
/// Requests scene capture from the Guardian.
/// </summary>
/// <returns>Returns true if scene capture succeeded, otherwise false.</returns>
public bool RequestSceneCapture()
{
#if !UNITY_EDITOR
var requestString = "";
return OVRPlugin.RequestSceneCapture(requestString, out _sceneCaptureRequestId);
#elif UNITY_EDITOR_WIN
Development.LogWarning(nameof(OVRSceneManager),
"Scene Capture does not work over Link. Please capture a scene with the HMD in standalone mode, then access the scene model over Link.");
return false;
#else
return false;
#endif
}
#region Private Methods
private void OnEnable()
{
// Bind events
OVRManager.SpaceQueryComplete += OVRManager_SpaceQueryComplete;
OVRManager.SceneCaptureComplete += OVRManager_SceneCaptureComplete;
OVRManager.SpaceSetComponentStatusComplete += OVRManager_SpaceSetComponentStatusComplete;
}
private void OnDisable()
{
// Unbind events
OVRManager.SpaceQueryComplete -= OVRManager_SpaceQueryComplete;
OVRManager.SceneCaptureComplete -= OVRManager_SceneCaptureComplete;
OVRManager.SpaceSetComponentStatusComplete -= OVRManager_SpaceSetComponentStatusComplete;
}
private bool LoadSpatialEntities()
{
// Remove all the scene entities in memory. Update with scene entities from new query.
var sceneAnchors = FindObjectsOfType<OVRSceneAnchor>();
foreach (var sceneAnchor in sceneAnchors)
{
Destroy(sceneAnchor.gameObject);
}
RoomLayout = new RoomLayoutInformation();
var queryInfo = new OVRPlugin.SpaceQueryInfo
{
QueryType = OVRPlugin.SpaceQueryType.Action,
MaxQuerySpaces = 100,
Timeout = 0,
Location = OVRPlugin.SpaceStorageLocation.Local,
ActionType = OVRPlugin.SpaceQueryActionType.Load,
FilterType = OVRPlugin.SpaceQueryFilterType.None
};
if (_currentQueryMode == QueryMode.QueryByUuid)
{
queryInfo.FilterType = OVRPlugin.SpaceQueryFilterType.Ids;
queryInfo.IdInfo = new OVRPlugin.SpaceFilterInfoIds
{
NumIds = Math.Min(OVRPlugin.SpaceFilterInfoIdsMaxSize, _uuidsToQuery.Count),
Ids = new Guid[OVRPlugin.SpaceFilterInfoIdsMaxSize]
};
for (int i = 0; i < queryInfo.IdInfo.NumIds; ++i)
{
queryInfo.IdInfo.Ids[i] = _uuidsToQuery[i];
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(LoadSpatialEntities)}() UUID to query [{_uuidsToQuery[i]}]");
}
}
else if (_currentQueryMode == QueryMode.QueryAllRoomLayoutEnabledForAllEntitiesInside || _currentQueryMode == QueryMode.QueryAllBounded2DEnabled || _currentQueryMode == QueryMode.QueryAllRoomLayoutEnabledForRoomBox)
{
queryInfo.FilterType = OVRPlugin.SpaceQueryFilterType.Components;
queryInfo.ComponentsInfo = new OVRPlugin.SpaceFilterInfoComponents
{
Components = new OVRPlugin.SpaceComponentType[OVRPlugin.SpaceFilterInfoComponentsMaxSize],
NumComponents = 1,
};
if (_currentQueryMode == QueryMode.QueryAllRoomLayoutEnabledForAllEntitiesInside || _currentQueryMode == QueryMode.QueryAllRoomLayoutEnabledForRoomBox)
{
queryInfo.ComponentsInfo.Components[0] = OVRPlugin.SpaceComponentType.RoomLayout;
}
else
{
queryInfo.ComponentsInfo.Components[0] = OVRPlugin.SpaceComponentType.Bounded2D;
}
}
if (OVRPlugin.QuerySpaces(queryInfo, out var requestId))
{
// We save this request id to ensure that when we trap a SpaceQueryResults event
// it's indeed one of our requests.
_individualRequestIds.Add(requestId);
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(LoadSpatialEntities)}() calling {nameof(OVRPlugin)}.{nameof(OVRPlugin.QuerySpaces)}(). Request id [{requestId}] added to the request list.");
return true;
}
Verbose?.LogWarning(nameof(OVRSceneManager),
$"{nameof(LoadSpatialEntities)}() {nameof(OVRPlugin)}.{nameof(OVRPlugin.QuerySpaces)}() failed.");
return false;
}
/// <summary>
/// Tests whether <paramref name="componentType"/> is enabled and, if not, requests that it be enabled.
/// </summary>
/// <returns>Returns the current state of the component.</returns>
private bool EnableComponentIfNecessary(OVRSpace space, Guid uuid, OVRPlugin.SpaceComponentType componentType)
{
OVRPlugin.GetSpaceComponentStatus(space, componentType, out bool componentEnabled, out _);
if (componentEnabled)
{
Verbose?.Log(nameof(OVRSceneManager),
$"[{uuid}] {nameof(EnableComponentIfNecessary)}() component [{componentType}] is already enabled.");
return true;
}
double dTimeout = 10 * 1000f;
OVRPlugin.SetSpaceComponentStatus(space, componentType, true, dTimeout, out var requestId);
Verbose?.Log(nameof(OVRSceneManager),
$"[{uuid}] {nameof(EnableComponentIfNecessary)}() component [{componentType}] requested with requestId [{requestId}].");
return false;
}
#endregion
#region ActionFunctions
private void OVRManager_SceneCaptureComplete(UInt64 requestId, bool result)
{
if (requestId != _sceneCaptureRequestId)
{
Verbose?.LogWarning(nameof(OVRSceneManager),
$"Scene Room Capture with requestId: [{requestId}] was ignored, as it was not issued by this Scene Load request.");
return;
}
Development.Log(nameof(OVRSceneManager),
$"{nameof(OVRManager_SceneCaptureComplete)}() requestId: [{requestId}] result: [{result}]");
if (result)
{
// Either the user created a room, or they confirmed that the existing room is up to date. We can now load it.
Development.Log(nameof(OVRSceneManager),
$"The Room Capture returned without errors. Invoking {nameof(SceneCaptureReturnedWithoutError)}.");
SceneCaptureReturnedWithoutError?.Invoke();
}
else
{
Development.LogError(nameof(OVRSceneManager),
$"An error occurred when sending the user to the Room Capture. Invoking {nameof(UnexpectedErrorWithSceneCapture)}.");
UnexpectedErrorWithSceneCapture?.Invoke();
}
}
private static bool IsComponentEnabled(OVRSpace space, OVRPlugin.SpaceComponentType componentType) =>
OVRPlugin.GetSpaceComponentStatus(space, componentType, out var enabled, out _) && enabled;
private OVRSceneAnchor InstantiateSceneAnchor(OVRSpace space, Guid uuid, OVRSceneAnchor prefab)
{
// Query for the semantic classification of the object
var hasSemanticLabels = OVRPlugin.GetSpaceSemanticLabels(space, out var labelString);
var labels = hasSemanticLabels
? labelString.Split(',')
: Array.Empty<string>();
// Search the prefab override for a matching label, and if found override the prefab
if (PrefabOverrides.Count > 0)
{
foreach (var label in labels)
{
// Skip empty labels
if (string.IsNullOrEmpty(label)) continue;
// Search the prefab override for an entry matching the label
foreach (var @override in PrefabOverrides)
{
if (@override.Prefab &&
@override.ClassificationLabel == label)
{
prefab = @override.Prefab;
break;
}
}
}
}
// This can occur if neither the prefab nor any matching override prefab is set in the inspector
if(prefab == null)
{
Verbose?.Log(nameof(OVRSceneManager),
$"No prefab was provided for space: [{space}]"
+ (labels.Length > 0 ? $" with semantic label {labels[0]}" : ""));
return null;
}
var sceneAnchor = Instantiate(prefab, Vector3.zero, Quaternion.identity);
sceneAnchor.Initialize(space, uuid);
var plane = sceneAnchor.GetComponent<OVRScenePlane>();
if (plane)
{
// Populate RoomLayoutInformation
foreach (var label in labels)
{
switch (label)
{
case Classification.Floor:
RoomLayout.Floor = plane;
break;
case Classification.Ceiling:
RoomLayout.Ceiling = plane;
break;
case Classification.WallFace:
RoomLayout.Walls.Add(plane);
break;
}
}
}
return sceneAnchor;
}
private void OVRManager_SpaceQueryComplete(UInt64 requestId, bool result)
{
// We should ignore any request that wasn't created by us
if (!_individualRequestIds.Contains(requestId))
{
Verbose?.LogWarning(nameof(OVRSceneManager),
$"requestId: [{requestId}] was ignored as it's not part of the Scene Load requests.");
return;
}
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(OVRManager_SpaceQueryComplete)}() requestId: [{requestId}] result: [{result}]");
_individualRequestIds.Remove(requestId);
if (!result) return;
if (!OVRPlugin.RetrieveSpaceQueryResults(requestId, out var results))
{
Development.LogError(nameof(OVRSceneManager),
$"{nameof(OVRPlugin.RetrieveSpaceQueryResults)}() Could not retrieve results.");
return;
}
if (results == null || results.Length == 0)
{
Development.LogWarning(nameof(OVRSceneManager),
"Loading the Scene definition yielded no result. "
+ "Typically, this means the user has not captured the room they are in yet. "
+ "Alternatively, an internal error may be preventing this app from accessing scene. "
+ $"Invoking {nameof(NoSceneModelToLoad)}.");
NoSceneModelToLoad?.Invoke();
return;
}
foreach (var queryResult in results)
{
ProcessQueryResult(queryResult);
}
CheckForCompletion();
}
private void CheckForCompletion()
{
// Requests can be nested, so we have to wait for the last one to be complete before applying
// any judgement on the final outcome.
if (_individualRequestIds.Count == 0 && _pendingLocatable.Count == 0)
{
Development.Log(nameof(OVRSceneManager),
$"Scene Model was loaded successfully. Invoking {nameof(SceneModelLoadedSuccessfully)}.");
RoomLayout?.Walls.Sort(_wallOrderComparer);
SceneModelLoadedSuccessfully?.Invoke();
}
}
private void OVRManager_SpaceSetComponentStatusComplete(UInt64 requestId, bool result, OVRSpace space, Guid uuid,
OVRPlugin.SpaceComponentType componentType, bool isEnabled)
{
if (!result)
{
#if DEVELOPMENT_BUILD
if (_pendingLocatable.ContainsKey(space))
{
Development.LogError(nameof(OVRSceneManager), $"[{uuid}] {nameof(OVRManager)}.{nameof(OVRManager.SpaceSetComponentStatusComplete)} failed for component {componentType}.");
}
#endif
return;
}
if (componentType == OVRPlugin.SpaceComponentType.Locatable &&
isEnabled &&
_pendingLocatable.TryGetValue(space, out var spaceQueryResult))
{
Development.Log(nameof(OVRSceneManager), $"[{uuid}] is now locatable.");
_pendingLocatable.Remove(space);
ProcessQueryResult(spaceQueryResult);
CheckForCompletion();
}
}
private void ProcessQueryResult(OVRPlugin.SpaceQueryResult queryResult)
{
var space = queryResult.space;
var uuid = queryResult.uuid;
OVRPlugin.GetSpaceComponentStatus(space, OVRPlugin.SpaceComponentType.Bounded3D, out bool bounded3dEnabled, out _);
OVRPlugin.GetSpaceComponentStatus(space, OVRPlugin.SpaceComponentType.Bounded2D, out bool bounded2dEnabled, out _);
OVRPlugin.GetSpaceComponentStatus(space, OVRPlugin.SpaceComponentType.RoomLayout, out bool roomLayoutEnabled, out _);
IEnumerable<string> EnabledComponents()
{
if (IsComponentEnabled(space, OVRPlugin.SpaceComponentType.Locatable))
yield return nameof(OVRPlugin.SpaceComponentType.Locatable);
if (bounded2dEnabled) yield return nameof(OVRPlugin.SpaceComponentType.Bounded2D);
if (bounded3dEnabled) yield return nameof(OVRPlugin.SpaceComponentType.Bounded3D);
if (IsComponentEnabled(space, OVRPlugin.SpaceComponentType.SemanticLabels))
{
if (OVRPlugin.GetSpaceSemanticLabels(space, out var labels))
{
yield return $"{nameof(OVRPlugin.SpaceComponentType.SemanticLabels)} ({labels})";
}
else
{
yield return $"{nameof(OVRPlugin.SpaceComponentType.SemanticLabels)} (none)";
}
}
if (roomLayoutEnabled) yield return nameof(OVRPlugin.SpaceComponentType.RoomLayout);
}
Verbose?.Log(nameof(OVRSceneManager),
$"[{uuid}] {nameof(OVRManager_SpaceQueryComplete)}() Enabled components: {string.Join(", ", EnabledComponents())}");
if (bounded2dEnabled || bounded3dEnabled)
{
// Validate only allowed components are set
if (roomLayoutEnabled)
{
Development.LogError(nameof(OVRSceneManager),
$"[{uuid}] {nameof(OVRManager_SpaceQueryComplete)}() Anchor has incompatible components. {nameof(OVRPlugin.SpaceComponentType.RoomLayout)} should not be enabled with {nameof(OVRPlugin.SpaceComponentType.Bounded2D)} or {nameof(OVRPlugin.SpaceComponentType.Bounded3D)}.");
return;
}
// Enable Locatable component, as it is not enabled when the space is loaded from storage for the first time.
var locatableEnabled = EnableComponentIfNecessary(space, uuid, OVRPlugin.SpaceComponentType.Locatable);
if (!locatableEnabled)
{
Development.Log(nameof(OVRSceneManager), $"[{uuid}] Waiting for spatial entity to become {nameof(OVRPlugin.SpaceComponentType.Locatable)}.");
_pendingLocatable[queryResult.space] = queryResult;
return;
}
InstantiateSceneAnchor(space, uuid, bounded2dEnabled ? PlanePrefab : VolumePrefab);
}
else if (roomLayoutEnabled)
{
bool roomLayoutSuccess = OVRPlugin.GetSpaceRoomLayout(space, out var roomLayout);
if (!roomLayoutSuccess)
{
Development.LogError(nameof(OVRSceneManager),
$"[{uuid}] has component {nameof(OVRPlugin.SpaceComponentType.RoomLayout)} but {nameof(OVRPlugin.GetSpaceRoomLayout)} failed. Ignoring room.");
return;
}
var uuidSet = new HashSet<Guid>();
if (!roomLayout.floorUuid.Equals(Guid.Empty))
{
uuidSet.Add(roomLayout.floorUuid);
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(OVRPlugin.GetSpaceRoomLayout)}: floor [{roomLayout.floorUuid}]");
}
if (!roomLayout.ceilingUuid.Equals(Guid.Empty))
{
uuidSet.Add(roomLayout.ceilingUuid);
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(OVRPlugin.GetSpaceRoomLayout)}: ceiling [{roomLayout.ceilingUuid}]");
}
_orderedRoomGuids.Clear();
int validWallsCount = 0;
foreach (var wallUuid in roomLayout.wallUuids)
{
if (!wallUuid.Equals(Guid.Empty))
{
uuidSet.Add(wallUuid);
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(OVRPlugin.GetSpaceRoomLayout)}: wall [{wallUuid}]");
_orderedRoomGuids[wallUuid] = validWallsCount++;
}
}
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(OVRPlugin.GetSpaceRoomLayout)}: wall count [{validWallsCount}]");
bool containerSuccess = OVRPlugin.GetSpaceContainer(space, out var containerUuids);
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(OVRPlugin.GetSpaceContainer)}: success [{containerSuccess}], count [{containerUuids.Length}]");
if (containerSuccess)
{
foreach (var containerUuid in containerUuids)
{
Verbose?.Log(nameof(OVRSceneManager),
$"{nameof(OVRPlugin.GetSpaceContainer)}: UUID [{containerUuid}]");
if (!containerUuid.Equals(Guid.Empty))
{
uuidSet.Add(containerUuid);
}
}
}
_uuidsToQuery = uuidSet.ToList();
_currentQueryMode = QueryMode.QueryByUuid;
LoadSpatialEntities();
}
}
#endregion
}