// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System; using System.Collections; using HoloToolkit.Unity; using UnityEngine; namespace HoloToolkit.Sharing.Utilities { /// <summary> /// Utility class for automatically joining shared sessions without needing to go through a lobby. /// </summary> public class AutoJoinSessionAndRoom : Singleton<AutoJoinSessionAndRoom> { /// <summary> /// Some room ID for indicating which room we are in. /// </summary> private long roomID = 1; /// <summary> /// Time to wait before attempting to reconnect. /// </summary> public float Timeout = 1f; private static bool ShouldLocalUserCreateRoom { get { if (!SharingStage.IsInitialized || SharingStage.Instance.SessionUsersTracker == null) { return false; } long localUserId; using (User localUser = SharingStage.Instance.Manager.GetLocalUser()) { localUserId = localUser.GetID(); } for (int i = 0; i < SharingStage.Instance.SessionUsersTracker.CurrentUsers.Count; i++) { if (SharingStage.Instance.SessionUsersTracker.CurrentUsers[i].GetID() < localUserId) { return false; } } return true; } } private void Start() { // SharingStage should be valid at this point, but we may not be connected. if (SharingStage.Instance.IsConnected) { SharingManagerConnected(); } else { SessionTrackerDisconnected(); } } protected override void OnDestroy() { if (SharingStage.Instance != null) { SharingStage.Instance.SharingManagerConnected -= SharingManagerConnected; SharingStage.Instance.SessionsTracker.ServerDisconnected -= SessionTrackerDisconnected; } StopCoroutine(AutoConnect()); base.OnDestroy(); } /// <summary> /// Called when the sharing stage connects to a server. /// </summary> /// <param name="sender">Sender.</param> /// <param name="e">Events Arguments.</param> private void SharingManagerConnected(object sender = null, EventArgs e = null) { SharingStage.Instance.SharingManagerConnected -= SharingManagerConnected; SharingStage.Instance.SessionsTracker.ServerDisconnected += SessionTrackerDisconnected; } /// <summary> /// Called when the Session Tracker connects to a server. /// </summary> private void SessionTrackerDisconnected() { SharingStage.Instance.SharingManagerConnected += SharingManagerConnected; SharingStage.Instance.SessionsTracker.ServerDisconnected -= SessionTrackerDisconnected; if (SharingStage.Instance.ClientRole == ClientRole.Primary) { StartCoroutine(AutoConnect()); } } private IEnumerator AutoConnect() { if (SharingStage.Instance.ShowDetailedLogs) { Debug.Log("[AutoJoinSessionAndRoom] Attempting to connect..."); } yield return new WaitForSeconds(Timeout); if (!SharingStage.Instance.SessionsTracker.IsServerConnected) { if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogWarning("[AutoJoinSessionAndRoom] Disconnected from server. Waiting for a connection... "); } while (!SharingStage.Instance.SessionsTracker.IsServerConnected) { yield return null; } if (SharingStage.Instance.ShowDetailedLogs) { Debug.Log("[AutoJoinSessionAndRoom] Connected!"); } } if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogFormat("[AutoJoinSessionAndRoom] Looking for {0}...", SharingStage.Instance.SessionName); Debug.LogFormat("[AutoJoinSessionAndRoom] Successfully connected to server with {0} Sessions.", SharingStage.Instance.SessionsTracker.Sessions.Count.ToString()); } yield return new WaitForEndOfFrame(); bool sessionExists = false; for (int i = 0; i < SharingStage.Instance.SessionsTracker.Sessions.Count; ++i) { if (SharingStage.Instance.SessionsTracker.Sessions[i].GetName().GetString() == SharingStage.Instance.SessionName) { sessionExists = true; if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogFormat("[AutoJoinSessionAndRoom] Joining session {0}...", SharingStage.Instance.SessionName); } yield return SharingStage.Instance.SessionsTracker.JoinSession(SharingStage.Instance.SessionsTracker.Sessions[i]); yield return new WaitForEndOfFrame(); break; } } if (!sessionExists) { if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogFormat("[AutoJoinSessionAndRoom] Didn't find session {0}, making a new one...", SharingStage.Instance.SessionName); } if (!SharingStage.Instance.SessionsTracker.CreateSession(SharingStage.Instance.SessionName)) { yield break; } yield return new WaitForEndOfFrame(); while (SharingStage.Instance.SessionsTracker.GetCurrentSession() == null) { yield return null; } } while (SharingStage.Instance.SessionsTracker.GetCurrentSession().GetMachineSessionState() != MachineSessionState.JOINED) { yield return null; } if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogFormat("[AutoJoinSessionAndRoom] Joined session {0} successfully!", SharingStage.Instance.SessionName); } yield return new WaitForEndOfFrame(); if (SharingStage.Instance.CurrentRoomManager.GetRoomCount() == 0) { // If we are the user with the lowest user ID, we will create the room. if (ShouldLocalUserCreateRoom) { if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogFormat("[AutoJoinSessionAndRoom] Creating room {0}...", SharingStage.Instance.RoomName); } // To keep anchors alive even if all users have left the session... // Pass in true instead of false in CreateRoom. SharingStage.Instance.CurrentRoomManager.CreateRoom( new XString(SharingStage.Instance.RoomName), roomID, SharingStage.Instance.KeepRoomAlive); } } else if (SharingStage.Instance.CurrentRoomManager.GetRoomCount() > 0) { if (SharingStage.Instance.CurrentRoom != null) { SharingStage.Instance.CurrentRoomManager.LeaveRoom(); } yield return new WaitForEndOfFrame(); // Look through the existing rooms and join the one that matches the room name provided. for (int i = 0; i < SharingStage.Instance.CurrentRoomManager.GetRoomCount(); i++) { if (SharingStage.Instance.CurrentRoomManager.GetRoom(i).GetName().GetString().Equals(SharingStage.Instance.RoomName, StringComparison.OrdinalIgnoreCase)) { SharingStage.Instance.CurrentRoomManager.JoinRoom(SharingStage.Instance.CurrentRoomManager.GetRoom(i)); if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogFormat("[AutoJoinSessionAndRoom] Joining room {0}...", SharingStage.Instance.CurrentRoomManager.GetRoom(i).GetName().GetString()); } break; } } } while (SharingStage.Instance.CurrentRoom == null) { yield return null; } if (SharingStage.Instance.ShowDetailedLogs) { Debug.LogFormat("[AutoJoinSessionAndRoom] Joined room {0} successfully!", SharingStage.Instance.CurrentRoom.GetName().GetString()); } yield return new WaitForEndOfFrame(); SharingWorldAnchorManager.Instance.AttachAnchor(gameObject); } } }