void PrintStats() { // Print out all the aggregate stats for (var i = 0; i < qosServers?.Length; ++i) { var ipAndPort = qosServers[i].ToString(); if (m_Stats.TryGetWeightedAverage(ipAndPort, out var result)) { m_Stats.TryGetAllResults(ipAndPort, out var allResults); // NOTE: You probably don't want Linq in your game, but it's convenient here to filter out the invalid results. Debug.Log($"Weighted average QoS report for {ipAndPort}: " + $"Latency: {result.LatencyMs}ms, " + $"Packet Loss: {result.PacketLoss * 100.0f:F1}%, " + $"All Results: {string.Join(", ", allResults.Select(x => x.IsValid() ? x.LatencyMs : 0))}"); } else { Debug.Log($"No results for {ipAndPort}."); } } #if USE_QOSCONNECTOR || USE_MMCONNECTOR // Print out what would be returned through the QosConnector QosTicketInfo results = QosConnector.Instance.Execute(); if (results.QosResults?.Count > 0) { Debug.Log("QosTicketInfo coming from the QosConnector:\n" + JsonUtility.ToJson(results, true)); } #endif }
/// <summary> /// Initialize a new MatchmakingRequest object /// </summary> /// <param name="client"> /// An already existing MatchmakingClient to use as the client for the request /// </param> /// <param name="request"> /// The ticket data to send with the matchmaking request. /// Data will be copied internally on construction and treated as immutable. /// </param> /// <param name="timeoutMs"> /// The amount of time to wait (in ms) before aborting an incomplete MatchmakingRequest after it has been sent. /// Match requests that time out on the client side will immediately be set to completed and stop listening for a match /// assignment. /// </param> public MatchmakingRequest(MatchmakingClient client, CreateTicketRequest request, uint timeoutMs = 0) { m_Client = client ?? throw new ArgumentNullException(nameof(client), logPre + $"Matchmaking {nameof(client)} must not be null"); if (request == null) { throw new ArgumentNullException(nameof(request), logPre + $"{nameof(request)} must be a non-null, valid {nameof(CreateTicketRequest)} object"); } // Try to immediately create and store the protobuf version of the CreateTicketRequest // This allows us to fail fast, and also copies the data to prevent it from being mutable // This may cause exceptions inside the protobuf code, which is fine since we're in the constructor var createTicketRequest = new Protobuf.CreateTicketRequest(); string key = nameof(QosTicketInfo).ToLower(); if (request.Properties != null && !request.Properties.ContainsKey(key)) { QosTicketInfo results = QosConnector.Instance.Execute(); if (results?.QosResults?.Count > 0) { request.Properties = request.Properties ?? new Dictionary <string, string>(); request.Properties.Add(key, JsonUtility.ToJson(results)); } } // Only set properties if not null // Request properties have to be massaged to be protobuf ByteString compatible if (request.Properties != null) { foreach (var kvp in request.Properties) { var keyToLower = kvp.Key.ToLower(); #if UNITY_EDITOR || DEVELOPMENT_BUILD if (!kvp.Key.Equals(keyToLower)) { Debug.LogWarning(logPre + $"Ticket property with key {kvp.Key} must be all lowercase; changing in-place."); } #endif createTicketRequest.Properties.Add(keyToLower, ByteString.CopyFrom(Encoding.UTF8.GetBytes(kvp.Value))); } } // Only add attributes if they exist if (request?.Attributes?.Count > 0) { createTicketRequest.Attributes.Add(request.Attributes); } m_CreateTicketRequest = createTicketRequest; State = MatchmakingRequestState.NotStarted; m_MatchRequestTimeoutMs = timeoutMs; }