#pragma warning disable 1587 /// \file /// Part of the [Optional GUI](@ref optionalGui). #pragma warning restore 1587 using ExitGames.Client.Photon; using UnityEngine; /// /// Basic GUI to show traffic and health statistics of the connection to Photon, /// toggled by shift+tab. /// /// /// The shown health values can help identify problems with connection losses or performance. /// Example: /// If the time delta between two consecutive SendOutgoingCommands calls is a second or more, /// chances rise for a disconnect being caused by this (because acknowledgements to the server /// need to be sent in due time). /// /// \ingroup optionalGui public class PhotonStatsGui : MonoBehaviour { /// Shows or hides GUI (does not affect if stats are collected). public bool statsWindowOn = true; /// Option to turn collecting stats on or off (used in Update()). public bool statsOn = true; /// Shows additional "health" values of connection. public bool healthStatsVisible; /// Shows additional "lower level" traffic stats. public bool trafficStatsOn; /// Show buttons to control stats and reset them. public bool buttonsOn; /// Positioning rect for window. public Rect statsRect = new Rect(0, 100, 200, 50); /// Unity GUI Window ID (must be unique or will cause issues). public int WindowId = 100; public void Start() { if (this.statsRect.x <= 0) { this.statsRect.x = Screen.width - this.statsRect.width; } } /// Checks for shift+tab input combination (to toggle statsOn). public void Update() { if (Input.GetKeyDown(KeyCode.Tab) && Input.GetKey(KeyCode.LeftShift)) { this.statsWindowOn = !this.statsWindowOn; this.statsOn = true; // enable stats when showing the window } } public void OnGUI() { if (PhotonNetwork.networkingPeer.TrafficStatsEnabled != statsOn) { PhotonNetwork.networkingPeer.TrafficStatsEnabled = this.statsOn; } if (!this.statsWindowOn) { return; } this.statsRect = GUILayout.Window(this.WindowId, this.statsRect, this.TrafficStatsWindow, "Messages (shift+tab)"); } public void TrafficStatsWindow(int windowID) { bool statsToLog = false; TrafficStatsGameLevel gls = PhotonNetwork.networkingPeer.TrafficStatsGameLevel; long elapsedMs = PhotonNetwork.networkingPeer.TrafficStatsElapsedMs / 1000; if (elapsedMs == 0) { elapsedMs = 1; } GUILayout.BeginHorizontal(); this.buttonsOn = GUILayout.Toggle(this.buttonsOn, "buttons"); this.healthStatsVisible = GUILayout.Toggle(this.healthStatsVisible, "health"); this.trafficStatsOn = GUILayout.Toggle(this.trafficStatsOn, "traffic"); GUILayout.EndHorizontal(); string total = string.Format("Out {0,4} | In {1,4} | Sum {2,4}", gls.TotalOutgoingMessageCount, gls.TotalIncomingMessageCount, gls.TotalMessageCount); string elapsedTime = string.Format("{0}sec average:", elapsedMs); string average = string.Format("Out {0,4} | In {1,4} | Sum {2,4}", gls.TotalOutgoingMessageCount / elapsedMs, gls.TotalIncomingMessageCount / elapsedMs, gls.TotalMessageCount / elapsedMs); GUILayout.Label(total); GUILayout.Label(elapsedTime); GUILayout.Label(average); if (this.buttonsOn) { GUILayout.BeginHorizontal(); this.statsOn = GUILayout.Toggle(this.statsOn, "stats on"); if (GUILayout.Button("Reset")) { PhotonNetwork.networkingPeer.TrafficStatsReset(); PhotonNetwork.networkingPeer.TrafficStatsEnabled = true; } statsToLog = GUILayout.Button("To Log"); GUILayout.EndHorizontal(); } string trafficStatsIn = string.Empty; string trafficStatsOut = string.Empty; if (this.trafficStatsOn) { GUILayout.Box("Traffic Stats"); trafficStatsIn = "Incoming: \n" + PhotonNetwork.networkingPeer.TrafficStatsIncoming.ToString(); trafficStatsOut = "Outgoing: \n" + PhotonNetwork.networkingPeer.TrafficStatsOutgoing.ToString(); GUILayout.Label(trafficStatsIn); GUILayout.Label(trafficStatsOut); } string healthStats = string.Empty; if (this.healthStatsVisible) { GUILayout.Box("Health Stats"); healthStats = string.Format( "ping: {6}[+/-{7}]ms resent:{8} \n\nmax ms between\nsend: {0,4} \ndispatch: {1,4} \n\nlongest dispatch for: \nev({3}):{2,3}ms \nop({5}):{4,3}ms", gls.LongestDeltaBetweenSending, gls.LongestDeltaBetweenDispatching, gls.LongestEventCallback, gls.LongestEventCallbackCode, gls.LongestOpResponseCallback, gls.LongestOpResponseCallbackOpCode, PhotonNetwork.networkingPeer.RoundTripTime, PhotonNetwork.networkingPeer.RoundTripTimeVariance, PhotonNetwork.networkingPeer.ResentReliableCommands); GUILayout.Label(healthStats); } if (statsToLog) { string complete = string.Format("{0}\n{1}\n{2}\n{3}\n{4}\n{5}", total, elapsedTime, average, trafficStatsIn, trafficStatsOut, healthStats); Debug.Log(complete); } // if anything was clicked, the height of this window is likely changed. reduce it to be layouted again next frame if (GUI.changed) { this.statsRect.height = 100; } GUI.DragWindow(); } }