-
Notifications
You must be signed in to change notification settings - Fork 54
Expand file tree
/
Copy pathColocationDriverNetObj.cs
More file actions
190 lines (160 loc) · 7.2 KB
/
ColocationDriverNetObj.cs
File metadata and controls
190 lines (160 loc) · 7.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using CrypticCabinet.GameManagement;
using CrypticCabinet.UI;
using CrypticCabinet.Utils;
using Fusion;
using Meta.XR.Samples;
using Oculus.Platform.Models;
using Meta.Utilities;
using Meta.XR.MRUtilityKit;
using UnityEngine;
namespace CrypticCabinet.Colocation
{
/// <summary>
/// Manages the complete workflow to ensure that all existing and new users will be colocated correctly
/// into the room.
/// </summary>
[MetaCodeSample("CrypticCabinet")]
public class ColocationDriverNetObj : NetworkSingleton<ColocationDriverNetObj>
{
/// <summary>
/// Callback for when the colocation process completes.
/// If succeeded, the callback will be passed a true, otherwise a false.
/// </summary>
public Action<bool> OnColocationCompletedCallback;
[SerializeField] private GameObject m_clientMRUK;
private const int RETRY_ATTEMPTS_ALLOWED = 3;
private int m_currentRetryAttempts;
private bool m_colocationSuccessful;
private readonly Guid m_groupUuid = Guid.NewGuid();
public override void Spawned()
{
// Initialize colocation regardless on single or multiplayer session.
UISystem.Instance.ShowMessage("Waiting for colocation to be ready, please wait...", null, -1);
SetupForColocation();
}
private async void SetupForColocation()
{
Debug.Log("SetupForColocation: Initializing Colocation for the player");
if (HasStateAuthority)
{
Debug.Log($"[{nameof(ColocationDriverNetObj)}] hosting colocation", this);
OnColocationCompleted(MRUK.LoadDeviceResult.Success);
}
else
{
var user = await OculusPlatformUtils.GetLoggedInUser();
Debug.Log($"[{nameof(ColocationDriverNetObj)}] requesting colocation for user '{user.ID}'", this);
ShareSceneServerRpc(user.ID);
}
}
[Rpc(sources: RpcSources.All, targets: RpcTargets.StateAuthority)]
private async void ShareSceneServerRpc(ulong oculusUserId, RpcInfo info = default)
{
foreach (var r in MRUK.Instance.Rooms)
{
if (!r.Anchor.TryGetComponent<OVRSharable>(out var sharableComponent)) {
Debug.LogError("Anchor does not support sharing.");
return;
}
if (await sharableComponent.SetEnabledAsync(true)) {
Debug.Log("Anchor is now sharable.");
} else {
Debug.LogError("Unable to enable the sharable component.");
}
}
Debug.Log($"Sharing current room with {oculusUserId}", this);
if (!OVRSpaceUser.TryCreate(oculusUserId, out var spaceUser))
{
Debug.LogError($"Failed to create space user for oculus id {oculusUserId}", this);
return;
}
var result = await MRUK.Instance.ShareRoomsAsync(MRUK.Instance.Rooms, m_groupUuid);
if (!result.Success)
{
Debug.LogError($"Failed to share {MRUK.Instance.Rooms.Count} rooms with user '{oculusUserId}', result = {result}", this);
return;
}
var roomGuids = MRUK.Instance.Rooms.Select(room => room.Anchor.Uuid.ToString()).ToArray();
var floorAnchor = MRUK.Instance.GetCurrentRoom().FloorAnchor;
Debug.Log($"Sending shared scene guids = {roomGuids.ListToString()}", this);
ReceiveSharedSceneClientRpc(info.Source, roomGuids, m_groupUuid.ToString(), floorAnchor.transform.position.ToString(), floorAnchor.transform.rotation.ToString());
}
[Rpc(sources: RpcSources.StateAuthority, targets: RpcTargets.All)]
private async void ReceiveSharedSceneClientRpc([RpcTarget] PlayerRef player, string[] roomStrings, string groupString, string floorPositionString, string floorRotationString)
{
var roomGuids = roomStrings.Select(str => new Guid(str)).ToArray();
var roomGuidsString = roomGuids.ListToString();
var groupUuid = new Guid(groupString);
Debug.Log($"Received shared room guids = {roomGuidsString}; loading...", this);
Debug.Assert(MRUK.Instance == null, "There is an MRUK Instance already");
m_clientMRUK.SetActive(true);
var floorAnchorPose = new PoseSerializable
{
position = new Vector4Serializable(floorPositionString),
rotation = new Vector4Serializable(floorRotationString)
};
var result = await MRUK.Instance.LoadSceneFromSharedRooms(roomGuids, groupUuid, (alignmentRoomUuid: roomGuids[0], floorWorldPoseOnHost: floorAnchorPose.ToPose()));
OnColocationCompleted(result);
}
private void OnColocationCompleted(MRUK.LoadDeviceResult result)
{
if (result is MRUK.LoadDeviceResult.Success)
{
Debug.Log("Colocation is Ready!", this);
m_colocationSuccessful = true;
OnColocationCompletedCallback?.Invoke(true);
}
else
{
Debug.Log($"Colocation failed! {result}", this);
OnColocationCompletedCallback?.Invoke(false);
}
}
public IEnumerator RetryColocation()
{
Debug.Log($"Retrying colocation (retry #{m_currentRetryAttempts})", this);
yield return new WaitForSeconds(5f);
if (m_colocationSuccessful)
{
yield break;
}
if (m_currentRetryAttempts >= RETRY_ATTEMPTS_ALLOWED)
{
GameManager.Instance.RestartGameplay();
yield break;
}
m_currentRetryAttempts++;
SetupForColocation();
}
[Serializable]
private struct Vector4Serializable
{
public float x, y, z, w;
public Vector4Serializable(Vector4 v) { x = v.x; y = v.y; z = v.z; w = v.w; }
public Vector4Serializable(Quaternion q) { x = q.x; y = q.y; z = q.z; w = q.w; }
public Vector4 ToVector4() => new Vector4(x, y, z, w);
public Vector3 ToVector3() => new Vector3(x, y, z);
public Quaternion ToQuaternion() => new Quaternion(x, y, z, w);
public Vector4Serializable(string str)
{
var components = str.Trim('(', ')').Split(',');
x = float.Parse(components[0].Trim());
y = float.Parse(components[1].Trim());
z = float.Parse(components[2].Trim());
w = components.Length == 4 ? float.Parse(components[3].Trim()) : 0;
}
}
[Serializable]
private struct PoseSerializable
{
public Vector4Serializable position;
public Vector4Serializable rotation;
public Pose ToPose() => new Pose(position.ToVector3(), rotation.ToQuaternion());
}
}
}