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 file="ConnectionHandler.cs" company="Exit Games GmbH">
// Loadbalancing Framework for Photon - Copyright (C) 2018 Exit Games GmbH
// </copyright>
// <summary>
// If the game logic does not call Service() for whatever reason, this keeps the connection.
// </summary>
// <author>developer@photonengine.com</author>
// ----------------------------------------------------------------------------
#if UNITY_4_7 || UNITY_5 || UNITY_5_3_OR_NEWER
#define SUPPORTED_UNITY
#endif
namespace Photon.Realtime
{
using System;
using System.Diagnostics;
using SupportClass = ExitGames.Client.Photon.SupportClass;
#if SUPPORTED_UNITY
using UnityEngine;
#endif
#if SUPPORTED_UNITY
public class ConnectionHandler : MonoBehaviour
#else
public class ConnectionHandler
#endif
{
/// <summary>
/// Photon client to log information and statistics from.
/// </summary>
public LoadBalancingClient Client { get; set; }
/// <summary>Option to let the fallback thread call Disconnect after the KeepAliveInBackground time. Default: false.</summary>
/// <remarks>
/// If set to true, the thread will disconnect the client regularly, should the client not call SendOutgoingCommands / Service.
/// This may happen due to an app being in background (and not getting a lot of CPU time) or when loading assets.
///
/// If false, a regular timeout time will have to pass (on top) to time out the client.
/// </remarks>
public bool DisconnectAfterKeepAlive = false;
/// <summary>Defines for how long the Fallback Thread should keep the connection, before it may time out as usual.</summary>
/// <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>
public int KeepAliveInBackground = 60000;
/// <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>
public int CountSendAcksOnly { get; private set; }
/// <summary>True if a fallback thread is running. Will call the client's SendAcksOnly() method to keep the connection up.</summary>
public bool FallbackThreadRunning
{
get { return this.fallbackThreadId < 255; }
}
/// <summary>Keeps the ConnectionHandler, even if a new scene gets loaded.</summary>
public bool ApplyDontDestroyOnLoad = true;
/// <summary>Indicates that the app is closing. Set in OnApplicationQuit().</summary>
[NonSerialized]
public static bool AppQuits;
private byte fallbackThreadId = 255;
private bool didSendAcks;
private readonly Stopwatch backgroundStopwatch = new Stopwatch();
#if SUPPORTED_UNITY
#if UNITY_2019_4_OR_NEWER
/// <summary>
/// Resets statics for Domain Reload
/// </summary>
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void StaticReset()
{
AppQuits = false;
}
#endif
/// <summary>Called by Unity when the application gets closed. The UnityEngine will also call OnDisable, which disconnects.</summary>
protected void OnApplicationQuit()
{
AppQuits = true;
}
/// <summary></summary>
protected virtual void Awake()
{
if (this.ApplyDontDestroyOnLoad)
{
DontDestroyOnLoad(this.gameObject);
}
}
/// <summary>Called by Unity when the application gets closed. Disconnects if OnApplicationQuit() was called before.</summary>
protected virtual void OnDisable()
{
this.StopFallbackSendAckThread();
if (AppQuits)
{
if (this.Client != null && this.Client.IsConnected)
{
this.Client.Disconnect();
this.Client.LoadBalancingPeer.StopThread();
}
SupportClass.StopAllBackgroundCalls();
}
}
#endif
public void StartFallbackSendAckThread()
{
#if !UNITY_WEBGL
if (this.FallbackThreadRunning)
{
return;
}
#if UNITY_SWITCH
this.fallbackThreadId = SupportClass.StartBackgroundCalls(this.RealtimeFallbackThread, 50); // as workaround, we don't name the Thread.
#else
this.fallbackThreadId = SupportClass.StartBackgroundCalls(this.RealtimeFallbackThread, 50, "RealtimeFallbackThread");
#endif
#endif
}
public void StopFallbackSendAckThread()
{
#if !UNITY_WEBGL
if (!this.FallbackThreadRunning)
{
return;
}
SupportClass.StopBackgroundCalls(this.fallbackThreadId);
this.fallbackThreadId = 255;
#endif
}
/// <summary>A thread which runs independent from the Update() calls. Keeps connections online while loading or in background. See <see cref="KeepAliveInBackground"/>.</summary>
public bool RealtimeFallbackThread()
{
if (this.Client != null)
{
if (!this.Client.IsConnected)
{
this.didSendAcks = false;
return true;
}
if (this.Client.LoadBalancingPeer.ConnectionTime - this.Client.LoadBalancingPeer.LastSendOutgoingTime > 100)
{
if (!this.didSendAcks)
{
backgroundStopwatch.Reset();
backgroundStopwatch.Start();
}
// check if the client should disconnect after some seconds in background
if (backgroundStopwatch.ElapsedMilliseconds > this.KeepAliveInBackground)
{
if (this.DisconnectAfterKeepAlive)
{
this.Client.Disconnect();
}
return true;
}
this.didSendAcks = true;
this.CountSendAcksOnly++;
this.Client.LoadBalancingPeer.SendAcksOnly();
}
else
{
this.didSendAcks = false;
}
}
return true;
}
}
}
|