mirror of
https://github.com/FriendshipIsEpic/FiE-Game.git
synced 2024-12-01 01:18:00 +01:00
335 lines
11 KiB
C#
335 lines
11 KiB
C#
// --------------------------------------------------------------------------------------------------------------------
|
|
// <copyright file="PhotonHandler.cs" company="Exit Games GmbH">
|
|
// Part of: Photon Unity Networking
|
|
// </copyright>
|
|
// --------------------------------------------------------------------------------------------------------------------
|
|
|
|
#if UNITY_5 && (!UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && !UNITY_5_3) || UNITY_6
|
|
#define UNITY_MIN_5_4
|
|
#endif
|
|
|
|
using System;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using ExitGames.Client.Photon;
|
|
using UnityEngine;
|
|
using UnityEngine.Profiling;
|
|
using Debug = UnityEngine.Debug;
|
|
using Hashtable = ExitGames.Client.Photon.Hashtable;
|
|
using SupportClassPun = ExitGames.Client.Photon.SupportClass;
|
|
|
|
#if UNITY_5_5_OR_NEWER
|
|
using UnityEngine.Profiling;
|
|
#endif
|
|
|
|
/// <summary>
|
|
/// Internal Monobehaviour that allows Photon to run an Update loop.
|
|
/// </summary>
|
|
internal class PhotonHandler : MonoBehaviour
|
|
{
|
|
public static PhotonHandler SP;
|
|
|
|
public int updateInterval; // time [ms] between consecutive SendOutgoingCommands calls
|
|
|
|
public int updateIntervalOnSerialize; // time [ms] between consecutive RunViewUpdate calls (sending syncs, etc)
|
|
|
|
private int nextSendTickCount = 0;
|
|
|
|
private int nextSendTickCountOnSerialize = 0;
|
|
|
|
private static bool sendThreadShouldRun;
|
|
|
|
private static Stopwatch timerToStopConnectionInBackground;
|
|
|
|
protected internal static bool AppQuits;
|
|
|
|
protected internal static Type PingImplementation = null;
|
|
|
|
protected void Awake()
|
|
{
|
|
if (SP != null && SP != this && SP.gameObject != null)
|
|
{
|
|
GameObject.DestroyImmediate(SP.gameObject);
|
|
}
|
|
|
|
SP = this;
|
|
DontDestroyOnLoad(this.gameObject);
|
|
|
|
this.updateInterval = 1000 / PhotonNetwork.sendRate;
|
|
this.updateIntervalOnSerialize = 1000 / PhotonNetwork.sendRateOnSerialize;
|
|
|
|
PhotonHandler.StartFallbackSendAckThread();
|
|
}
|
|
|
|
|
|
#if UNITY_MIN_5_4
|
|
|
|
protected void Start()
|
|
{
|
|
UnityEngine.SceneManagement.SceneManager.sceneLoaded += (scene, loadingMode) =>
|
|
{
|
|
PhotonNetwork.networkingPeer.NewSceneLoaded();
|
|
PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(SceneManagerHelper.ActiveSceneName);
|
|
};
|
|
}
|
|
|
|
#else
|
|
|
|
/// <summary>Called by Unity after a new level was loaded.</summary>
|
|
protected void OnLevelWasLoaded(int level)
|
|
{
|
|
PhotonNetwork.networkingPeer.NewSceneLoaded();
|
|
PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(SceneManagerHelper.ActiveSceneName);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/// <summary>Called by Unity when the application is closed. Disconnects.</summary>
|
|
protected void OnApplicationQuit()
|
|
{
|
|
PhotonHandler.AppQuits = true;
|
|
PhotonHandler.StopFallbackSendAckThread();
|
|
PhotonNetwork.Disconnect();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called by Unity when the application gets paused (e.g. on Android when in background).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Sets a disconnect timer when PhotonNetwork.BackgroundTimeout > 0.1f. See PhotonNetwork.BackgroundTimeout.
|
|
///
|
|
/// Some versions of Unity will give false values for pause on Android (and possibly on other platforms).
|
|
/// </remarks>
|
|
/// <param name="pause">If the app pauses.</param>
|
|
protected void OnApplicationPause(bool pause)
|
|
{
|
|
if (PhotonNetwork.BackgroundTimeout > 0.1f)
|
|
{
|
|
if (timerToStopConnectionInBackground == null)
|
|
{
|
|
timerToStopConnectionInBackground = new Stopwatch();
|
|
}
|
|
timerToStopConnectionInBackground.Reset();
|
|
|
|
if (pause)
|
|
{
|
|
timerToStopConnectionInBackground.Start();
|
|
}
|
|
else
|
|
{
|
|
timerToStopConnectionInBackground.Stop();
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>Called by Unity when the play mode ends. Used to cleanup.</summary>
|
|
protected void OnDestroy()
|
|
{
|
|
//Debug.Log("OnDestroy on PhotonHandler.");
|
|
PhotonHandler.StopFallbackSendAckThread();
|
|
//PhotonNetwork.Disconnect();
|
|
}
|
|
|
|
protected void Update()
|
|
{
|
|
if (PhotonNetwork.networkingPeer == null)
|
|
{
|
|
Debug.LogError("NetworkPeer broke!");
|
|
return;
|
|
}
|
|
|
|
if (PhotonNetwork.connectionStateDetailed == ClientState.PeerCreated || PhotonNetwork.connectionStateDetailed == ClientState.Disconnected || PhotonNetwork.offlineMode)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// the messageQueue might be paused. in that case a thread will send acknowledgements only. nothing else to do here.
|
|
if (!PhotonNetwork.isMessageQueueRunning)
|
|
{
|
|
return;
|
|
}
|
|
|
|
bool doDispatch = true;
|
|
while (PhotonNetwork.isMessageQueueRunning && doDispatch)
|
|
{
|
|
// DispatchIncomingCommands() returns true of it found any command to dispatch (event, result or state change)
|
|
Profiler.BeginSample("DispatchIncomingCommands");
|
|
doDispatch = PhotonNetwork.networkingPeer.DispatchIncomingCommands();
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
int currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000); // avoiding Environment.TickCount, which could be negative on long-running platforms
|
|
if (PhotonNetwork.isMessageQueueRunning && currentMsSinceStart > this.nextSendTickCountOnSerialize)
|
|
{
|
|
PhotonNetwork.networkingPeer.RunViewUpdate();
|
|
this.nextSendTickCountOnSerialize = currentMsSinceStart + this.updateIntervalOnSerialize;
|
|
this.nextSendTickCount = 0; // immediately send when synchronization code was running
|
|
}
|
|
|
|
currentMsSinceStart = (int)(Time.realtimeSinceStartup * 1000);
|
|
if (currentMsSinceStart > this.nextSendTickCount)
|
|
{
|
|
bool doSend = true;
|
|
while (PhotonNetwork.isMessageQueueRunning && doSend)
|
|
{
|
|
// Send all outgoing commands
|
|
Profiler.BeginSample("SendOutgoingCommands");
|
|
doSend = PhotonNetwork.networkingPeer.SendOutgoingCommands();
|
|
Profiler.EndSample();
|
|
}
|
|
|
|
this.nextSendTickCount = currentMsSinceStart + this.updateInterval;
|
|
}
|
|
}
|
|
|
|
protected void OnJoinedRoom()
|
|
{
|
|
PhotonNetwork.networkingPeer.LoadLevelIfSynced();
|
|
}
|
|
|
|
protected void OnCreatedRoom()
|
|
{
|
|
PhotonNetwork.networkingPeer.SetLevelInPropsIfSynced(SceneManagerHelper.ActiveSceneName);
|
|
}
|
|
|
|
public static void StartFallbackSendAckThread()
|
|
{
|
|
#if !UNITY_WEBGL
|
|
if (sendThreadShouldRun)
|
|
{
|
|
return;
|
|
}
|
|
|
|
sendThreadShouldRun = true;
|
|
SupportClassPun.CallInBackground(FallbackSendAckThread); // thread will call this every 100ms until method returns false
|
|
#endif
|
|
}
|
|
|
|
public static void StopFallbackSendAckThread()
|
|
{
|
|
#if !UNITY_WEBGL
|
|
sendThreadShouldRun = false;
|
|
#endif
|
|
}
|
|
|
|
/// <summary>A thread which runs independent from the Update() calls. Keeps connections online while loading or in background. See PhotonNetwork.BackgroundTimeout.</summary>
|
|
public static bool FallbackSendAckThread()
|
|
{
|
|
if (sendThreadShouldRun && PhotonNetwork.networkingPeer != null)
|
|
{
|
|
// check if the client should disconnect after some seconds in background
|
|
if (timerToStopConnectionInBackground != null && PhotonNetwork.BackgroundTimeout > 0.1f)
|
|
{
|
|
if (timerToStopConnectionInBackground.ElapsedMilliseconds > PhotonNetwork.BackgroundTimeout * 1000)
|
|
{
|
|
if (PhotonNetwork.connected)
|
|
{
|
|
PhotonNetwork.Disconnect();
|
|
}
|
|
timerToStopConnectionInBackground.Stop();
|
|
timerToStopConnectionInBackground.Reset();
|
|
return sendThreadShouldRun;
|
|
}
|
|
}
|
|
|
|
if (PhotonNetwork.networkingPeer.ConnectionTime - PhotonNetwork.networkingPeer.LastSendOutgoingTime > 200)
|
|
{
|
|
PhotonNetwork.networkingPeer.SendAcksOnly();
|
|
}
|
|
}
|
|
|
|
return sendThreadShouldRun;
|
|
}
|
|
|
|
|
|
#region Photon Cloud Ping Evaluation
|
|
|
|
|
|
private const string PlayerPrefsKey = "PUNCloudBestRegion";
|
|
|
|
internal static CloudRegionCode BestRegionCodeCurrently = CloudRegionCode.none; // default to none
|
|
internal static CloudRegionCode BestRegionCodeInPreferences
|
|
{
|
|
get
|
|
{
|
|
string prefsRegionCode = PlayerPrefs.GetString(PlayerPrefsKey, "");
|
|
if (!string.IsNullOrEmpty(prefsRegionCode))
|
|
{
|
|
CloudRegionCode loadedRegion = Region.Parse(prefsRegionCode);
|
|
return loadedRegion;
|
|
}
|
|
|
|
return CloudRegionCode.none;
|
|
}
|
|
set
|
|
{
|
|
if (value == CloudRegionCode.none)
|
|
{
|
|
PlayerPrefs.DeleteKey(PlayerPrefsKey);
|
|
}
|
|
else
|
|
{
|
|
PlayerPrefs.SetString(PlayerPrefsKey, value.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
internal protected static void PingAvailableRegionsAndConnectToBest()
|
|
{
|
|
SP.StartCoroutine(SP.PingAvailableRegionsCoroutine(true));
|
|
}
|
|
|
|
|
|
internal IEnumerator PingAvailableRegionsCoroutine(bool connectToBest)
|
|
{
|
|
BestRegionCodeCurrently = CloudRegionCode.none;
|
|
while (PhotonNetwork.networkingPeer.AvailableRegions == null)
|
|
{
|
|
if (PhotonNetwork.connectionStateDetailed != ClientState.ConnectingToNameServer && PhotonNetwork.connectionStateDetailed != ClientState.ConnectedToNameServer)
|
|
{
|
|
Debug.LogError("Call ConnectToNameServer to ping available regions.");
|
|
yield break; // break if we don't connect to the nameserver at all
|
|
}
|
|
|
|
Debug.Log("Waiting for AvailableRegions. State: " + PhotonNetwork.connectionStateDetailed + " Server: " + PhotonNetwork.Server + " PhotonNetwork.networkingPeer.AvailableRegions " + (PhotonNetwork.networkingPeer.AvailableRegions != null));
|
|
yield return new WaitForSeconds(0.25f); // wait until pinging finished (offline mode won't ping)
|
|
}
|
|
|
|
if (PhotonNetwork.networkingPeer.AvailableRegions == null || PhotonNetwork.networkingPeer.AvailableRegions.Count == 0)
|
|
{
|
|
Debug.LogError("No regions available. Are you sure your appid is valid and setup?");
|
|
yield break; // break if we don't get regions at all
|
|
}
|
|
|
|
PhotonPingManager pingManager = new PhotonPingManager();
|
|
foreach (Region region in PhotonNetwork.networkingPeer.AvailableRegions)
|
|
{
|
|
SP.StartCoroutine(pingManager.PingSocket(region));
|
|
}
|
|
|
|
while (!pingManager.Done)
|
|
{
|
|
yield return new WaitForSeconds(0.1f); // wait until pinging finished (offline mode won't ping)
|
|
}
|
|
|
|
|
|
Region best = pingManager.BestRegion;
|
|
PhotonHandler.BestRegionCodeCurrently = best.Code;
|
|
PhotonHandler.BestRegionCodeInPreferences = best.Code;
|
|
|
|
Debug.Log("Found best region: " + best.Code + " ping: " + best.Ping + ". Calling ConnectToRegionMaster() is: " + connectToBest);
|
|
|
|
|
|
if (connectToBest)
|
|
{
|
|
PhotonNetwork.networkingPeer.ConnectToRegionMaster(best.Code);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|