/// <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; }
/// <summary> /// <para>Send a Create Ticket (POST) request to the matchmaker, including custom request data.</para> /// <para>On completion, response body will contain a unique Ticket ID, used for GET and DELETE calls</para> /// </summary> /// <param name="request">The request data to include with the request</param> /// <param name="timeout">The timeout for the underlying web request</param> /// <returns> /// A UnityWebRequestAsyncOperation containing the underlying UnityWebRequest; can be yielded or used to track /// completion of the request /// </returns> public UnityWebRequestAsyncOperation CreateTicketAsync(Protobuf.CreateTicketRequest request, int timeout = 0) { return(CreateTicketAsync(MatchmakingServiceUrl, request, timeout)); }
/// <summary> /// <para>Send a Create Ticket (POST) request to the matchmaker, including custom request data.</para> /// <para>On completion, response body will contain a unique Ticket ID, used for GET and DELETE calls</para> /// </summary> /// <param name="matchmakingServiceUrl">The matchmaker to send the request to</param> /// <param name="request">The request data to include with the request</param> /// <param name="timeout">The timeout for the underlying web request</param> /// <returns> /// A UnityWebRequestAsyncOperation containing the underlying UnityWebRequest; can be yielded or used to track /// completion of the request /// </returns> public static UnityWebRequestAsyncOperation CreateTicketAsync(string matchmakingServiceUrl, Protobuf.CreateTicketRequest request, int timeout = 0) { if (string.IsNullOrEmpty(matchmakingServiceUrl)) { throw new ArgumentException(k_LogPre + $"{nameof(matchmakingServiceUrl)} must be a non-null, non-0-length string", nameof(matchmakingServiceUrl)); } if (request == null) { throw new ArgumentNullException(nameof(request), k_LogPre + $"{nameof(request)} must not be null"); } var url = matchmakingServiceUrl + k_TicketsPath; var webRequest = new UnityWebRequest(url, "POST"); webRequest.SetRequestHeader("Accept", k_ContentTypeProtobuf); webRequest.SetRequestHeader("Content-Type", k_ContentTypeProtobuf); webRequest.downloadHandler = new DownloadHandlerBuffer(); webRequest.timeout = timeout > 0 ? timeout : k_DefaultCreateCallTimeoutSeconds; // Upload body data if it exists (if sending no attributes and no properties, this may be empty) var requestBody = request.ToByteArray(); if (requestBody.Length > 0) { webRequest.uploadHandler = new UploadHandlerRaw(requestBody); } return(webRequest.SendWebRequest()); }