Beispiel #1
0
        public async Task AllowOneThousandPlayersToMatchAtOnce()
        {
            const int playersPerParty = 1;
            const int parties         = 1000;

            var startTime = DateTime.UtcNow;
            var tasks     = new List <Task>();

            for (var i = 0; i < playersPerParty * parties; i++)
            {
                var myId       = i;
                var playerName = $"test_player_{startTime.ToLongTimeString()}_{myId}";
                var playerPit  = await CreatePlayerIdentityTokenForPlayer(playerName);

                var task = Task.Run(async() =>
                {
                    var playerMetadata = new Metadata {
                        { PitRequestHeaderName, playerPit }
                    };
                    if (myId % playersPerParty == 0)
                    {
                        // Lead player sets up the match and invites the others
                        var party = false;
                        while (!party)
                        {
                            try
                            {
                                GetPartyClient().CreateParty(new CreatePartyRequest(), playerMetadata);
                                party = true;
                            }
                            catch (RpcException e)
                            {
                                Console.WriteLine($"CreateParty exception: {e}");
                            }
                        }

                        for (var j = 0; j < playersPerParty - 1; j++)
                        {
                            var invitedPlayerId = $"test_player_{startTime}_{myId + j + 1}";
                            GetInviteClient().CreateInvite(new CreateInviteRequest
                            {
                                ReceiverPlayerId = invitedPlayerId
                            }, playerMetadata);
                        }

                        int members = 1;
                        while (members < playersPerParty)
                        {
                            var partyData =
                                GetPartyClient().GetPartyByPlayerId(new GetPartyByPlayerIdRequest(), playerMetadata);
                            members = partyData.Party.MemberIds.Count;
                            await Task.Delay(500);
                        }

                        Console.WriteLine($"Enough players joined: Continuing as master ({playerName})");

                        // Join matchmaking.
                        var joined = false;
                        while (!joined)
                        {
                            try
                            {
                                GetGatewayClient().Join(new JoinRequest
                                {
                                    MatchmakingType = "match1"
                                }, playerMetadata);
                                joined = true;
                            }
                            catch (RpcException e)
                            {
                                if (e.StatusCode == StatusCode.AlreadyExists)
                                {
                                    joined = true;
                                }
                                Console.WriteLine($"Exception in Join ({playerName}): {e}");
                            }
                        }
                    }
                    else
                    {
                        // All other players wait for an invite
                        Console.WriteLine("Beginning as player");
                        var joined = false;
                        do
                        {
                            var invites = GetInviteClient().ListAllInvites(new ListAllInvitesRequest(), playerMetadata);
                            if (invites.InboundInvites.Count > 0)
                            {
                                _ = GetPartyClient().JoinParty(new JoinPartyRequest
                                {
                                    PartyId = invites.InboundInvites[0].PartyId
                                }, playerMetadata);
                                joined = true;
                            }
                        } while (!joined);
                    }
                }).ContinueWith(async t =>
                {
                    // Non-leaders may not have started matchmaking yet so GetJoinStatus could fail a few times.
                    GetJoinStatusResponse status = null;
                    do
                    {
                        try
                        {
                            status = GetGatewayClient().GetJoinStatus(new GetJoinStatusRequest {
                                PlayerId = playerName
                            },
                                                                      new Metadata {
                                { PitRequestHeaderName, playerPit }
                            });
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine($"Failed to poll: {e}");
                        }

                        await Task.Delay(100);
                    } while (status == null || !status.Complete);
                }).ContinueWith(t =>
                {
                    var playerMetadata = new Metadata {
                        { PitRequestHeaderName, playerPit }
                    };
                    GetPartyClient().DeleteParty(new DeletePartyRequest(), playerMetadata);
                });
                tasks.Add(task);
            }

            Task.WaitAll(tasks.ToArray());

            var seconds = (DateTime.UtcNow - startTime).TotalSeconds;

            Console.WriteLine($"Test completed in {seconds}s");
            Assert.Less(seconds, TimeSpan.FromMinutes(2).TotalSeconds);
        }
Beispiel #2
0
        static void Main(string[] args)
        {
            Parser.Default.ParseArguments <SampleClientArguments>(args)
            .WithParsed(parsedArgs =>
            {
                var gatewayServiceUrl = parsedArgs.Local
                        ? string.Format(LocalEndPointUrlFormat, "4040")
                        : string.Format(CloudEndPointUrlFormat, "gateway", parsedArgs.GoogleProject);

                var partyServiceUrl = parsedArgs.Local
                        ? string.Format(LocalEndPointUrlFormat, "4041")
                        : string.Format(CloudEndPointUrlFormat, "party", parsedArgs.GoogleProject);

                var authServiceUrl = parsedArgs.Local
                        ? string.Format(LocalEndPointUrlFormat, "4042")
                        : string.Format(CloudEndPointUrlFormat, "playfab-auth", parsedArgs.GoogleProject);

                var playerId = RandomString(15);
                Console.WriteLine($"Using a randomly generated PlayFab player ID: {playerId}");
                Console.WriteLine($"authServiceUrl: {authServiceUrl}");

                //This is the type of code i would put into the game because it is responsible
                // for talking directly to steam for encrypted app ticket and then sending it
                // to my servers to authenticate and exchange got a player identity token
                // First, get a token from PlayFab.
                PlayFabSettings.staticSettings.TitleId = parsedArgs.PlayFabTitleId;
                var playFabLoginTask = PlayFabClientAPI.LoginWithCustomIDAsync(new LoginWithCustomIDRequest
                {
                    TitleId       = parsedArgs.PlayFabTitleId,
                    CustomId      = playerId,
                    CreateAccount = true
                });
                var playFabLoginResult = playFabLoginTask.GetAwaiter().GetResult();
                if (playFabLoginResult.Error != null)
                {
                    Console.WriteLine($"Got login error from PlayFab: {playFabLoginResult.Error.ErrorMessage}");
                    Environment.Exit(1);
                    return;
                }

                var playFabId = playFabLoginResult.Result.PlayFabId;
                Console.WriteLine($"Got a token for PlayFab ID {playFabId}.");

                // Next, exchange the token with our auth service for a PIT.
                var playFabAuthClient = new AuthService.AuthServiceClient(
                    new Channel(authServiceUrl, ChannelCredentials.Insecure));
                var authResult = playFabAuthClient.ExchangePlayFabToken(new ExchangePlayFabTokenRequest
                {
                    PlayfabToken = playFabLoginResult.Result.SessionTicket
                });
                Console.WriteLine("Got a PIT.");
                var pitMetadata = new Metadata {
                    { PitRequestHeaderName, authResult.PlayerIdentityToken }
                };
                Console.WriteLine($"authResult.PlayerIdentityToken: {authResult.PlayerIdentityToken}");

                // Create a single-player party for the player.
                var partyClient = new PartyService.PartyServiceClient(
                    new Channel(partyServiceUrl, ChannelCredentials.Insecure));
                var partyResponse =
                    partyClient.CreateParty(new CreatePartyRequest {
                    MinMembers = 1, MaxMembers = 1
                }, pitMetadata);
                Console.WriteLine($"Created a new party with id {partyResponse.PartyId}.");

                var gatewayEndpoint = gatewayServiceUrl;
                var gatewayClient   =
                    new GatewayService.GatewayServiceClient(new Channel(gatewayEndpoint,
                                                                        ChannelCredentials.Insecure));

                gatewayClient.Join(new JoinRequest
                {
                    MatchmakingType = "match"
                }, pitMetadata);
                Console.WriteLine("Joined queue; waiting for match.");

                GetJoinStatusResponse resp = null;
                while (resp == null || !resp.Complete)
                {
                    Thread.Sleep(1000);
                    resp = gatewayClient.GetJoinStatus(new GetJoinStatusRequest {
                        PlayerId = playFabId
                    }, pitMetadata);
                }

                Console.WriteLine(
                    $"Got deployment: {resp.DeploymentName}. Login token: [{resp.LoginToken}].");
            });
        }
Beispiel #3
0
        public override async Task <GetJoinStatusResponse> GetJoinStatus(GetJoinStatusRequest request, ServerCallContext context)
        {
            var playerIdentity = AuthHeaders.ExtractPlayerId(context);

            if (!string.Equals(request.PlayerId, playerIdentity))
            {
                throw new RpcException(new Status(StatusCode.PermissionDenied,
                                                  "Fetching another player's join status is forbidden."));
            }

            PlayerJoinRequest joinRequest;

            using (var memClient = _memoryStoreClientManager.GetClient())
            {
                try
                {
                    joinRequest = await memClient.GetAsync <PlayerJoinRequest>(request.PlayerId) ??
                                  throw new EntryNotFoundException(request.PlayerId);

                    if (joinRequest.IsComplete())
                    {
                        using (var tx = memClient.CreateTransaction())
                        {
                            tx.DeleteAll(joinRequest.Yield());
                        }
                    }
                }
                catch (EntryNotFoundException e)
                {
                    Reporter.JoinStatusNotFoundInc();
                    Log.Warning($"Join request for {e.Id} does not exist");
                    throw new RpcException(new Status(StatusCode.NotFound, "requested player does not exist"));
                }
                catch (TransactionAbortedException)
                {
                    Reporter.TransactionAbortedInc("GetJoinStatus");
                    Log.Warning("Transaction for join request deletion was aborted");
                    throw new RpcException(new Status(StatusCode.Unavailable,
                                                      "deletion aborted due to concurrent modification; safe to retry"));
                }
            }

            var resp = new GetJoinStatusResponse
            {
                Complete = joinRequest.IsComplete(),
                Status   = MatchStateToJoinStatus(joinRequest.State)
            };

            switch (resp.Status)
            {
            case GetJoinStatusResponse.Types.Status.Joined:
                resp.DeploymentName = joinRequest.DeploymentName;
                resp.LoginToken     = await CreateLoginTokenForDeployment(joinRequest.DeploymentId, joinRequest.PlayerIdentityToken);

                break;

            case GetJoinStatusResponse.Types.Status.Error:
                resp.Error = "the join request encountered an error";
                break;
            }

            Reporter.JoinStatusInc(joinRequest.State);
            if (resp.Complete)
            {
                Log.Information($"Join request for {request.PlayerId} done in state {joinRequest.State}.");
            }

            return(resp);
        }