ConnectionHandler.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. // ----------------------------------------------------------------------------
  2. // <copyright file="ConnectionHandler.cs" company="Exit Games GmbH">
  3. // Loadbalancing Framework for Photon - Copyright (C) 2018 Exit Games GmbH
  4. // </copyright>
  5. // <summary>
  6. // If the game logic does not call Service() for whatever reason, this keeps the connection.
  7. // </summary>
  8. // <author>developer@photonengine.com</author>
  9. // ----------------------------------------------------------------------------
  10. #if UNITY_4_7 || UNITY_5 || UNITY_5_3_OR_NEWER
  11. #define SUPPORTED_UNITY
  12. #endif
  13. namespace Photon.Realtime
  14. {
  15. using System;
  16. using System.Diagnostics;
  17. using SupportClass = ExitGames.Client.Photon.SupportClass;
  18. #if SUPPORTED_UNITY
  19. using UnityEngine;
  20. #endif
  21. #if SUPPORTED_UNITY
  22. public class ConnectionHandler : MonoBehaviour
  23. #else
  24. public class ConnectionHandler
  25. #endif
  26. {
  27. /// <summary>
  28. /// Photon client to log information and statistics from.
  29. /// </summary>
  30. public LoadBalancingClient Client { get; set; }
  31. /// <summary>Option to let the fallback thread call Disconnect after the KeepAliveInBackground time. Default: false.</summary>
  32. /// <remarks>
  33. /// If set to true, the thread will disconnect the client regularly, should the client not call SendOutgoingCommands / Service.
  34. /// This may happen due to an app being in background (and not getting a lot of CPU time) or when loading assets.
  35. ///
  36. /// If false, a regular timeout time will have to pass (on top) to time out the client.
  37. /// </remarks>
  38. public bool DisconnectAfterKeepAlive = false;
  39. /// <summary>Defines for how long the Fallback Thread should keep the connection, before it may time out as usual.</summary>
  40. /// <remarks>We want to the Client to keep it's connection when an app is in the background (and doesn't call Update / Service Clients should not keep their connection indefinitely in the background, so after some milliseconds, the Fallback Thread should stop keeping it up.</remarks>
  41. public int KeepAliveInBackground = 60000;
  42. /// <summary>Counts how often the Fallback Thread called SendAcksOnly, which is purely of interest to monitor if the game logic called SendOutgoingCommands as intended.</summary>
  43. public int CountSendAcksOnly { get; private set; }
  44. /// <summary>True if a fallback thread is running. Will call the client's SendAcksOnly() method to keep the connection up.</summary>
  45. public bool FallbackThreadRunning
  46. {
  47. get { return this.fallbackThreadId < 255; }
  48. }
  49. /// <summary>Keeps the ConnectionHandler, even if a new scene gets loaded.</summary>
  50. public bool ApplyDontDestroyOnLoad = true;
  51. /// <summary>Indicates that the app is closing. Set in OnApplicationQuit().</summary>
  52. [NonSerialized]
  53. public static bool AppQuits;
  54. private byte fallbackThreadId = 255;
  55. private bool didSendAcks;
  56. private readonly Stopwatch backgroundStopwatch = new Stopwatch();
  57. #if SUPPORTED_UNITY
  58. #if UNITY_2019_4_OR_NEWER
  59. /// <summary>
  60. /// Resets statics for Domain Reload
  61. /// </summary>
  62. [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
  63. static void StaticReset()
  64. {
  65. AppQuits = false;
  66. }
  67. #endif
  68. /// <summary>Called by Unity when the application gets closed. The UnityEngine will also call OnDisable, which disconnects.</summary>
  69. protected void OnApplicationQuit()
  70. {
  71. AppQuits = true;
  72. }
  73. /// <summary></summary>
  74. protected virtual void Awake()
  75. {
  76. if (this.ApplyDontDestroyOnLoad)
  77. {
  78. DontDestroyOnLoad(this.gameObject);
  79. }
  80. }
  81. /// <summary>Called by Unity when the application gets closed. Disconnects if OnApplicationQuit() was called before.</summary>
  82. protected virtual void OnDisable()
  83. {
  84. this.StopFallbackSendAckThread();
  85. if (AppQuits)
  86. {
  87. if (this.Client != null && this.Client.IsConnected)
  88. {
  89. this.Client.Disconnect();
  90. this.Client.LoadBalancingPeer.StopThread();
  91. }
  92. SupportClass.StopAllBackgroundCalls();
  93. }
  94. }
  95. #endif
  96. public void StartFallbackSendAckThread()
  97. {
  98. #if !UNITY_WEBGL
  99. if (this.FallbackThreadRunning)
  100. {
  101. return;
  102. }
  103. #if UNITY_SWITCH
  104. this.fallbackThreadId = SupportClass.StartBackgroundCalls(this.RealtimeFallbackThread, 50); // as workaround, we don't name the Thread.
  105. #else
  106. this.fallbackThreadId = SupportClass.StartBackgroundCalls(this.RealtimeFallbackThread, 50, "RealtimeFallbackThread");
  107. #endif
  108. #endif
  109. }
  110. public void StopFallbackSendAckThread()
  111. {
  112. #if !UNITY_WEBGL
  113. if (!this.FallbackThreadRunning)
  114. {
  115. return;
  116. }
  117. SupportClass.StopBackgroundCalls(this.fallbackThreadId);
  118. this.fallbackThreadId = 255;
  119. #endif
  120. }
  121. /// <summary>A thread which runs independent from the Update() calls. Keeps connections online while loading or in background. See <see cref="KeepAliveInBackground"/>.</summary>
  122. public bool RealtimeFallbackThread()
  123. {
  124. if (this.Client != null)
  125. {
  126. if (!this.Client.IsConnected)
  127. {
  128. this.didSendAcks = false;
  129. return true;
  130. }
  131. if (this.Client.LoadBalancingPeer.ConnectionTime - this.Client.LoadBalancingPeer.LastSendOutgoingTime > 100)
  132. {
  133. if (!this.didSendAcks)
  134. {
  135. backgroundStopwatch.Reset();
  136. backgroundStopwatch.Start();
  137. }
  138. // check if the client should disconnect after some seconds in background
  139. if (backgroundStopwatch.ElapsedMilliseconds > this.KeepAliveInBackground)
  140. {
  141. if (this.DisconnectAfterKeepAlive)
  142. {
  143. this.Client.Disconnect();
  144. }
  145. return true;
  146. }
  147. this.didSendAcks = true;
  148. this.CountSendAcksOnly++;
  149. this.Client.LoadBalancingPeer.SendAcksOnly();
  150. }
  151. else
  152. {
  153. this.didSendAcks = false;
  154. }
  155. }
  156. return true;
  157. }
  158. }
  159. }