-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathColocationDriverNetObj.cs
199 lines (165 loc) · 6.91 KB
/
ColocationDriverNetObj.cs
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
191
192
193
194
195
196
197
198
199
// Copyright (c) Meta Platforms, Inc. and affiliates.
using System;
using System.Collections;
using com.meta.xr.colocation;
using CrypticCabinet.GameManagement;
using CrypticCabinet.Photon;
using CrypticCabinet.Photon.Colocation;
using CrypticCabinet.UI;
using CrypticCabinet.Utils;
using Cysharp.Threading.Tasks;
using Fusion;
using Oculus.Platform.Models;
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>
public class ColocationDriverNetObj : NetworkBehaviour
{
/// <summary>
/// Callback for when the colocation process completes.
/// If succeeded, the callback will be passed a true, otherwise a false.
/// </summary>
public static Action<bool> OnColocationCompletedCallback;
/// <summary>
/// If set to true, the colocation process will be skipped. False otherwise.
/// </summary>
public static bool SkipColocation;
/// <summary>
/// Callback for when the colocation process is skipped.
/// </summary>
public static Action OnColocationSkippedCallback;
[SerializeField] private PhotonNetworkData m_networkData;
[SerializeField] private PhotonNetworkMessenger m_networkMessenger;
[SerializeField] private GameObject m_anchorPrefab;
private SharedAnchorManager m_sharedAnchorManager;
private AutomaticColocationLauncher m_colocationLauncher;
private ulong m_playerDeviceUid;
private User m_oculusUser;
private Transform m_ovrCameraRigTransform;
public static ColocationDriverNetObj Instance { get; private set; }
private const int RETRY_ATTEMPTS_ALLOWED = 3;
private int m_currentRetryAttempts;
private bool m_colocationSuccessful;
private void Awake()
{
Debug.Assert(Instance == null, $"{nameof(ColocationDriverNetObj)} instance already exists");
Instance = this;
}
private void OnDestroy()
{
if (Instance == this)
{
Instance = null;
}
}
public override void Spawned()
{
Init();
}
private async void Init()
{
// Initialize colocation regardless on single or multiplayer session.
UISystem.Instance.ShowMessage("Waiting for colocation to be ready, please wait...", null, -1);
m_ovrCameraRigTransform = FindObjectOfType<OVRCameraRig>().transform;
#if !UNITY_EDITOR
if (PhotonConnector.Instance.IsMultiplayerSession)
{
// Only get the logged in user if we are not in editor, and we are in multiplayer.
m_oculusUser = await OculusPlatformUtils.GetLoggedInUser();
}
#else
await UniTask.Yield();
#endif
OnColocationCompletedCallback += delegate (bool b)
{
m_colocationSuccessful = b;
};
m_playerDeviceUid = OculusPlatformUtils.GetUserDeviceGeneratedUid();
SetupForColocation();
}
private void SetupForColocation()
{
Debug.Log("SetupForColocation: Initializing network messenger");
m_networkMessenger.RegisterLocalPlayer(m_playerDeviceUid);
// Instantiates the manager for the Oculus shared anchors, specifying the desired anchor prefab.
Debug.Log("SetupForColocation: Instantiating shared anchor manager");
m_sharedAnchorManager = new SharedAnchorManager { AnchorPrefab = m_anchorPrefab };
NetworkAdapter.SetConfig(m_networkData, m_networkMessenger);
Debug.Log("SetupForColocation: Initializing Colocation for the player");
// Starts the colocation alignment process
m_colocationLauncher = new AutomaticColocationLauncher();
m_colocationLauncher.Init(
NetworkAdapter.NetworkData,
NetworkAdapter.NetworkMessenger,
m_sharedAnchorManager,
m_ovrCameraRigTransform.gameObject,
m_playerDeviceUid,
m_oculusUser?.ID ?? default
);
// Hooks the event to react to the colocation ready state
m_colocationLauncher.ColocationReady += OnColocationReady;
m_colocationLauncher.ColocationFailed += OnColocationFailed;
if (HasStateAuthority || !PhotonConnector.Instance.IsMultiplayerSession)
{
// Being the state authority for the network or a single player, this user will
// create from scratch a new alignment anchor, which will be used by
// all other users to colocate in multiplayer, or by the single player.
m_colocationLauncher.CreateColocatedSpace();
}
else
{
// Don't try to colocate if we want to skip colocation
if (SkipColocation)
{
OnColocationSkippedCallback?.Invoke();
}
else
{
m_colocationLauncher.ColocateAutomatically();
}
}
}
private static void OnColocationReady()
{
Debug.Log("Colocation is Ready!");
// The AlignCameraToAnchor scripts updates on every frame which messes up Physics and create frame spikes.
// We need to disable it and add our own align manager that is applied only on recenter
var alignCamBehaviour = FindObjectOfType<AlignCameraToAnchor>();
alignCamBehaviour.enabled = false;
var alignmentGameObject = alignCamBehaviour.gameObject;
var alignManager = alignmentGameObject.AddComponent<AlignCameraToAnchorManager>();
alignManager.CameraAlignmentBehaviour = alignCamBehaviour;
alignManager.RealignToAnchor();
OnColocationCompletedCallback?.Invoke(true);
}
private static void OnColocationFailed(ColocationFailedReason reason)
{
Debug.Log($"Colocation failed! {reason}");
OnColocationCompletedCallback?.Invoke(false);
}
private static void OnColocationSkipped()
{
Debug.Log("Colocation skipped");
OnColocationSkippedCallback?.Invoke();
}
public IEnumerator RetryColocation()
{
yield return new WaitForSeconds(5f);
if (m_colocationSuccessful)
{
yield break;
}
if (m_currentRetryAttempts >= RETRY_ATTEMPTS_ALLOWED)
{
GameManager.Instance.RestartGameplay();
yield break;
}
m_currentRetryAttempts++;
m_colocationLauncher.ColocateAutomatically();
}
}
}