diff --git a/Unity/Assets/Editor/Rooms/RoomClientEditor.cs b/Unity/Assets/Editor/Rooms/RoomClientEditor.cs
index d9bfdeb4d..6866f15fa 100644
--- a/Unity/Assets/Editor/Rooms/RoomClientEditor.cs
+++ b/Unity/Assets/Editor/Rooms/RoomClientEditor.cs
@@ -92,6 +92,8 @@ public override void OnInspectorGUI()
EditorGUILayout.HelpBox("Joined Room " + component.Room.UUID, MessageType.Info);
}
+ EditorGUILayout.PropertyField(serializedObject.FindProperty("reconnectBehaviour"));
+
foldoutRooms = EditorGUILayout.BeginFoldoutHeaderGroup(foldoutRooms, "Available Rooms");
if (foldoutRooms)
diff --git a/Unity/Assets/Runtime/Messaging/NetworkScene.cs b/Unity/Assets/Runtime/Messaging/NetworkScene.cs
index 8ba7f3d75..d2dd47aa4 100644
--- a/Unity/Assets/Runtime/Messaging/NetworkScene.cs
+++ b/Unity/Assets/Runtime/Messaging/NetworkScene.cs
@@ -246,6 +246,26 @@ public void AddConnection(INetworkConnection connection)
connections.Add(connection);
}
+ ///
+ /// Public method instructing the network scene to drop all current connections and dispose of them.
+ /// Used to recover from a connection loss to Nexus.
+ ///
+ public void ClearConnections()
+ {
+ foreach (var c in connections)
+ {
+ try
+ {
+ c.Dispose();
+ }
+ catch
+ {
+
+ }
+ }
+ connections.Clear();
+ }
+
private void Update()
{
OnUpdate.Invoke();
@@ -329,18 +349,7 @@ public void SendJson(NetworkId objectid, T message)
private void OnDestroy()
{
- foreach (var c in connections)
- {
- try
- {
- c.Dispose();
- }
- catch
- {
-
- }
- }
- connections.Clear();
+ ClearConnections();
}
}
}
\ No newline at end of file
diff --git a/Unity/Assets/Runtime/Rooms/RoomClient.cs b/Unity/Assets/Runtime/Rooms/RoomClient.cs
index 6fde83595..99b6ab84b 100644
--- a/Unity/Assets/Runtime/Rooms/RoomClient.cs
+++ b/Unity/Assets/Runtime/Rooms/RoomClient.cs
@@ -1,12 +1,12 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using Ubiq.Dictionaries;
using Ubiq.Messaging;
using Ubiq.Networking;
using Ubiq.Rooms.Messages;
using Ubiq.XR.Notifications;
using UnityEngine;
+using UnityEngine.SceneManagement;
namespace Ubiq.Rooms
{
@@ -240,6 +240,18 @@ public IEnumerable Peers
private float heartbeatSent => Time.realtimeSinceStartup - pingSent;
public static float HeartbeatTimeout = 5f;
public static float HeartbeatInterval = 1f;
+
+ public enum ReconnectBehaviour
+ {
+ None,
+ Reconnect,
+ ReconnectAndReloadScenes
+ }
+
+ public ReconnectBehaviour reconnectBehaviour = ReconnectBehaviour.None;
+ public static float reconnectTimeout = 10.0f;
+ private float nextReconnectTimeout = reconnectTimeout;
+
private PeerInterfaceFriend me = new PeerInterfaceFriend(Guid.NewGuid().ToString());
private RoomInterfaceFriend room = new RoomInterfaceFriend();
private NetworkScene scene;
@@ -262,7 +274,15 @@ public override string Message
{
get
{
- return $"No Connection ({ client.heartbeatReceived.ToString("0") } seconds ago)";
+ if (client.reconnectBehaviour == ReconnectBehaviour.None)
+ {
+ return $"Connection lost ({ client.heartbeatReceived.ToString("0") } seconds ago)";
+ }
+ else
+ {
+ var timeToReconnect = Mathf.Max(0,client.nextReconnectTimeout - client.heartbeatReceived);
+ return $"Connection lost (Next reconnect attempt in { timeToReconnect.ToString("0") } seconds)";
+ }
}
}
}
@@ -547,7 +567,7 @@ protected void ProcessMessage(ReferenceCountedSceneGraphMessage message)
case "Ping":
{
pingReceived = Time.realtimeSinceStartup;
- PlayerNotifications.Delete(ref notification);
+
var response = JsonUtility.FromJson(container.args);
OnPingResponse(response);
}
@@ -635,6 +655,38 @@ public void Connect(ConnectionDefinition connection)
scene.AddConnection(Connections.Resolve(connection));
}
+ ///
+ /// Method to reset all current connections and reconnect to the ones defined by the user in the Unity UI.
+ ///
+ public void ResetAndReconnect()
+ {
+ ResetAndReconnect(servers);
+ }
+
+ ///
+ /// Method to reset all current connections and reconnect to the ones defined in the connection definition passed as argument.
+ ///
+ /// The connection definition that will be connected after the reset.
+ public void ResetAndReconnect(ConnectionDefinition[] connectionDefinitions)
+ {
+ // Drop all connections
+ scene.ClearConnections();
+
+ // Reconnect all connections
+ foreach (var item in connectionDefinitions)
+ {
+ try
+ {
+ Connect(item);
+ }
+ catch(Exception e)
+ {
+ Debug.LogError(e.ToString());
+ }
+ }
+ }
+
+
private void Update()
{
actions.ForEach(a => a());
@@ -674,10 +726,20 @@ private void Update()
if (heartbeatReceived > HeartbeatTimeout)
{
+ // There's been a long interval between server responses
+ // We may be disconnected, or there may be network issues
+
if (notification == null)
{
notification = PlayerNotifications.Show(new TimeoutNotification(this));
}
+
+ if (heartbeatReceived > nextReconnectTimeout
+ && reconnectBehaviour != ReconnectBehaviour.None)
+ {
+ ResetAndReconnect();
+ nextReconnectTimeout += reconnectTimeout;
+ }
}
}
@@ -758,9 +820,30 @@ public void Ping()
private void OnPingResponse(PingResponseArgs args)
{
+ PlayerNotifications.Delete(ref notification);
+ nextReconnectTimeout = reconnectTimeout;
+
if(SessionId != args.sessionId && SessionId != null)
{
- Join(name:"",publish:false); // The RoomClient has re-established connectivity with the RoomServer, but under a different state. So, leave the room and let the user code re-establish any state.
+ // The RoomClient has re-established connectivity with
+ // the RoomServer, but under a different state.
+ if (reconnectBehaviour == ReconnectBehaviour.ReconnectAndReloadScenes)
+ {
+ var scenes = new Scene[SceneManager.sceneCount];
+ for (int i = 0; i < SceneManager.sceneCount; i++)
+ {
+ scenes[i] = SceneManager.GetSceneAt(i);
+ }
+
+ var first = true;
+ for (int i = 0; i < scenes.Length; i++)
+ {
+ SceneManager.LoadScene(scenes[i].buildIndex,mode: first
+ ? LoadSceneMode.Single
+ : LoadSceneMode.Additive);
+ first = false;
+ }
+ }
}
SessionId = args.sessionId;
diff --git a/Unity/Assets/Samples/Start Here.unity b/Unity/Assets/Samples/Start Here.unity
index dfd101542..32feff72b 100644
--- a/Unity/Assets/Samples/Start Here.unity
+++ b/Unity/Assets/Samples/Start Here.unity
@@ -413,6 +413,7 @@ MeshRenderer:
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
+ m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
@@ -461,6 +462,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -1.214, y: 0.634, z: -0.99}
m_LocalScale: {x: 0.25361246, y: 0.25361246, z: 0.25361246}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 4
@@ -707,6 +709,11 @@ PrefabInstance:
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
+ - target: {fileID: 2642065778884258271, guid: 46c1f5d5a11cf5042886aabd56e7b9d7,
+ type: 3}
+ propertyPath: m_Enabled
+ value: 1
+ objectReference: {fileID: 0}
- target: {fileID: 2642065778884258271, guid: 46c1f5d5a11cf5042886aabd56e7b9d7,
type: 3}
propertyPath: servers.Array.size
diff --git a/Unity/Assets/Samples/_Common/Prefabs/Network Scene.prefab b/Unity/Assets/Samples/_Common/Prefabs/Network Scene.prefab
index c9ad23e8a..b690f6abe 100644
--- a/Unity/Assets/Samples/_Common/Prefabs/Network Scene.prefab
+++ b/Unity/Assets/Samples/_Common/Prefabs/Network Scene.prefab
@@ -27,6 +27,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7068762446378101729}
m_RootOrder: 4
@@ -72,6 +73,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7068762446378101729}
m_RootOrder: 0
@@ -118,6 +120,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7068762446051028576}
- {fileID: 7068762446560339092}
@@ -160,6 +163,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
servers:
- {fileID: -7849211376014683480, guid: 1c91df7c43c1dbe4fb0fb303e71a2790, type: 2}
+ reconnectBehaviour: 2
--- !u!114 &7068762446378101731
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -217,6 +221,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7068762446378101729}
m_RootOrder: 1
@@ -260,6 +265,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7068762446378101729}
m_RootOrder: 2
@@ -309,6 +315,7 @@ Transform:
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
+ m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 7068762446378101729}
m_RootOrder: 3