Skip to content

Commit

Permalink
Adding an automatic reconnection process to RoomClient for recovery a… (
Browse files Browse the repository at this point in the history
#33)

* Adding an automatic reconnection process to RoomClient for recovery after the connection to Nexus is lost. On connection loss, the room client instructs the scene to drop all connections and periodically attempts at rejoining the room.

* Add scene reload, editor gui and user notification for reconnect functionality

---------

Co-authored-by: bnco <33021110+bnco-dev@users.noreply.github.com>
  • Loading branch information
FJThiel and bnco-dev authored Jul 25, 2023
1 parent 4f513ce commit 5a08065
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 16 deletions.
2 changes: 2 additions & 0 deletions Unity/Assets/Editor/Rooms/RoomClientEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
33 changes: 21 additions & 12 deletions Unity/Assets/Runtime/Messaging/NetworkScene.cs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,26 @@ public void AddConnection(INetworkConnection connection)
connections.Add(connection);
}

/// <summary>
/// Public method instructing the network scene to drop all current connections and dispose of them.
/// Used to recover from a connection loss to Nexus.
/// </summary>
public void ClearConnections()
{
foreach (var c in connections)
{
try
{
c.Dispose();
}
catch
{

}
}
connections.Clear();
}

private void Update()
{
OnUpdate.Invoke();
Expand Down Expand Up @@ -329,18 +349,7 @@ public void SendJson<T>(NetworkId objectid, T message)

private void OnDestroy()
{
foreach (var c in connections)
{
try
{
c.Dispose();
}
catch
{

}
}
connections.Clear();
ClearConnections();
}
}
}
91 changes: 87 additions & 4 deletions Unity/Assets/Runtime/Rooms/RoomClient.cs
Original file line number Diff line number Diff line change
@@ -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
{
Expand Down Expand Up @@ -240,6 +240,18 @@ public IEnumerable<IPeer> 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;
Expand All @@ -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)";
}
}
}
}
Expand Down Expand Up @@ -547,7 +567,7 @@ protected void ProcessMessage(ReferenceCountedSceneGraphMessage message)
case "Ping":
{
pingReceived = Time.realtimeSinceStartup;
PlayerNotifications.Delete(ref notification);

var response = JsonUtility.FromJson<PingResponseArgs>(container.args);
OnPingResponse(response);
}
Expand Down Expand Up @@ -635,6 +655,38 @@ public void Connect(ConnectionDefinition connection)
scene.AddConnection(Connections.Resolve(connection));
}

/// <summary>
/// Method to reset all current connections and reconnect to the ones defined by the user in the Unity UI.
/// </summary>
public void ResetAndReconnect()
{
ResetAndReconnect(servers);
}

/// <summary>
/// Method to reset all current connections and reconnect to the ones defined in the connection definition passed as argument.
/// </summary>
/// <param name="connectionDefinitions">The connection definition that will be connected after the reset.</param>
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());
Expand Down Expand Up @@ -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;
}
}
}

Expand Down Expand Up @@ -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;
Expand Down
7 changes: 7 additions & 0 deletions Unity/Assets/Samples/Start Here.unity
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions Unity/Assets/Samples/_Common/Prefabs/Network Scene.prefab
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}
Expand Down Expand Up @@ -160,6 +163,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
servers:
- {fileID: -7849211376014683480, guid: 1c91df7c43c1dbe4fb0fb303e71a2790, type: 2}
reconnectBehaviour: 2
--- !u!114 &7068762446378101731
MonoBehaviour:
m_ObjectHideFlags: 0
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 5a08065

Please sign in to comment.