Beispiel #1
0
 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;
            }
        }
Beispiel #3
0
        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);
                        }
                    }
                }
            }
        }