public MatchmakingRequestCompletionArgs(string ticketId, MatchmakingRequestState state, Assignment assignment, string error) { this.TicketId = ticketId; this.State = state; this.Assignment = assignment; this.Error = error; }
/// <summary> /// <para>Dispose the MatchmakingRequest and release resources. All in-flight web requests will be disposed regardless of state. /// Object methods will no-op after disposal.</para> /// <para>Best practice is to ensure that Cancel() has been called and completed before calling Dispose().</para> /// </summary> public void Dispose() { if (!m_Disposed) { // Dispose any leftover web requests; most of these should be disposed of elsewhere // This is just a catch-all in case we Dispose() in the middle of a request var createInFlight = false; var getInFlight = false; var deleteInFlight = false; if (m_CreateTicketAsyncOperation != null) { createInFlight = MatchmakingClient.IsWebRequestSent(m_CreateTicketAsyncOperation); m_CreateTicketAsyncOperation.completed -= OnCreateTicketAsyncCompleted; m_CreateTicketAsyncOperation.webRequest?.Dispose(); m_CreateTicketAsyncOperation = null; } if (m_GetTicketAsyncOperation != null) { getInFlight = State == MatchmakingRequestState.Polling; m_GetTicketAsyncOperation.completed -= OnGetTicketAsyncCompleted; m_GetTicketAsyncOperation.webRequest?.Dispose(); m_GetTicketAsyncOperation = null; } if (m_DeleteTicketAsyncOperation != null) { deleteInFlight = !m_DeleteTicketAsyncOperation.isDone; m_DeleteTicketAsyncOperation.completed -= OnDeleteTicketAsyncCompleted; m_DeleteTicketAsyncOperation.webRequest?.Dispose(); m_DeleteTicketAsyncOperation = null; } if ((createInFlight || getInFlight) && State != MatchmakingRequestState.Canceled) { Debug.LogWarning(logPre + $"{nameof(MatchmakingRequest)} was terminated without being deleted." + " This may cause ghost tickets in the matchmaker."); } if (deleteInFlight) { Debug.LogWarning(logPre + $"{nameof(MatchmakingRequest)} was terminated while a Delete request was in flight" + "; Delete may not be processed by the matchmaker."); } if (!IsDone) { State = MatchmakingRequestState.Disposed; SetTerminalState(); } m_Disposed = true; } }
public async Task FindMatch(RequestContext <IScenePeerClient> request) { _logger.Log(LogLevel.Trace, "matchmaker", "received a matchmaking request", new { }); var group = new Group(); var provider = request.ReadObject <string>(); var currentUser = await _sessions.GetUser(request.RemotePeer); foreach (var extractor in _extractors) { if (await extractor.ExtractData(provider, request, group)) { break; } } _logger.Log(LogLevel.Trace, "matchmaker", "data extracted from the matchmaking request", new { group }); foreach (var p in group.Players) { if (_usersToGroup.ContainsKey(p.UserId)) { throw new ClientException($"'{p.UserId} is already waiting for a match."); } } var state = new MatchmakingRequestState(group); _waitingGroups[group] = state; foreach (var user in group.Players) { _usersToGroup[user.UserId] = group; } request.CancellationToken.Register(() => { state.Tcs.TrySetCanceled(); }); var memStream = new MemoryStream(); request.InputStream.Seek(0, SeekOrigin.Begin); request.InputStream.CopyTo(memStream); await BroadcastToPlayers(group, UPDATE_FINDMATCH_REQUEST_PARAMS_ROUTE, (s, sz) => { memStream.Seek(0, System.IO.SeekOrigin.Begin); memStream.CopyTo(s); }); await BroadcastToPlayers(group, UPDATE_NOTIFICATION_ROUTE, (s, sz) => { s.WriteByte((byte)MatchmakingStatusUpdate.SearchStart); }); state.State = RequestState.Ready; IMatchResolverContext resolutionContext; try { resolutionContext = await state.Tcs.Task; } catch (TaskCanceledException) { await BroadcastToPlayers(group, UPDATE_NOTIFICATION_ROUTE, (s, sz) => s.WriteByte((byte)MatchmakingStatusUpdate.Cancelled)); } finally //Always remove group from list. { MatchmakingRequestState _; foreach (var player in group.Players) { Group grp1; _usersToGroup.TryRemove(player.UserId, out grp1); } _waitingGroups.TryRemove(group, out _); if (_.Candidate != null) { MatchReadyCheck rc; if (_pendingReadyChecks.TryGetValue(_.Candidate.Id, out rc)) { if (!rc.RanToCompletion) { rc.Cancel(currentUser.Id); } } } } }
public async Task FindMatch(RequestContext <IScenePeerClient> request) { var group = new Group(); var provider = request.ReadObject <string>(); var currentUser = await _sessions.GetUser(request.RemotePeer); var dataExtracted = false; foreach (var extractor in _extractors) { if (await extractor.ExtractData(provider, request, group)) { dataExtracted = true; break; } } if (!dataExtracted) { throw new ClientException($"Unkown matchmaking provider '{provider}'."); } var peersInGroup = await Task.WhenAll(group.Players.Select(async p => new { Peer = await _sessions.GetPeer(p.UserId), Player = p })); foreach (var p in peersInGroup) { if (p.Peer == null) { throw new ClientException($"'{p.Player.UserId} has disconnected."); } if (_peersToGroup.ContainsKey(p.Peer.Id)) { throw new ClientException($"'{p.Player.UserId} is already waiting for a match."); } } var state = new MatchmakingRequestState(group); _waitingGroups[group] = state; foreach (var p in peersInGroup) { _peersToGroup[p.Peer.Id] = group; } request.CancellationToken.Register(() => { state.Tcs.TrySetCanceled(); }); var memStream = new MemoryStream(); request.InputStream.Seek(0, SeekOrigin.Begin); request.InputStream.CopyTo(memStream); await BroadcastToPlayers(group, UPDATE_FINDMATCH_REQUEST_PARAMS_ROUTE, (s, sz) => { memStream.Seek(0, System.IO.SeekOrigin.Begin); memStream.CopyTo(s); }); await BroadcastToPlayers(group, UPDATE_NOTIFICATION_ROUTE, (s, sz) => { s.WriteByte((byte)MatchmakingStatusUpdate.SearchStart); }); state.State = RequestState.Ready; IMatchResolverContext resolutionContext; try { resolutionContext = await state.Tcs.Task; } catch (TaskCanceledException) { _scene.Send(new MatchArrayFilter(peersInGroup.Select(p => p.Peer.Id)), UPDATE_NOTIFICATION_ROUTE, s => s.WriteByte((byte)MatchmakingStatusUpdate.Cancelled), PacketPriority.MEDIUM_PRIORITY, PacketReliability.RELIABLE); } finally //Always remove group from list. { MatchmakingRequestState _; foreach (var p in peersInGroup) { Group grp1; _peersToGroup.TryRemove(p.Peer.Id, out grp1); } _waitingGroups.TryRemove(group, out _); if (_.Candidate != null) { MatchReadyCheck rc; if (_pendingReadyChecks.TryGetValue(_.Candidate.Id, out rc)) { if (!rc.RanToCompletion) { rc.Cancel(currentUser.Id); } } } } }