Merge pull request #28 from OriolBonjoch/master

Added Leaderboard stats when playing with bots
This commit is contained in:
Eduard Tomàs 2020-04-17 15:29:51 +02:00 коммит произвёл GitHub
Родитель d93a8f6748 2b22a59111
Коммит 0acaf82872
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 126 добавлений и 31 удалений

Просмотреть файл

@ -118,11 +118,11 @@ namespace RPSLS.Game.Api.Data
if (_constr == null) return;
var cResponse = await GetContainer();
var existing = cResponse.Container.GetItemLinqQueryable<MatchDto>(allowSynchronousQueryExecution: true)
.Where(m => m.PlayFabMatchId == matchId)
.FirstOrDefault();
var allExisting = cResponse.Container.GetItemLinqQueryable<MatchDto>(allowSynchronousQueryExecution: true)
.Where(m => m.PlayFabMatchId == matchId).ToList();
if (existing == null) return;
if (allExisting == null || !allExisting.Any()) return;
var existing = allExisting.First();
await cResponse.Container.DeleteItemAsync<MatchDto>(matchId, new PartitionKey(existing.PlayerName));
}

Просмотреть файл

@ -3,6 +3,7 @@ using Grpc.Core;
using Microsoft.Extensions.Logging;
using RPSLS.Game.Api.Data;
using RPSLS.Game.Api.Services;
using RPSLS.Game.Multiplayer.Services;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -10,19 +11,22 @@ using System.Threading.Tasks;
namespace RPSLS.Game.Api.GrpcServices
{
public class BotGameManagerService : BotGameManager.BotGameManagerBase
{
{
private readonly IPlayFabService _playFabService;
private readonly IChallengerService _challengersService;
private readonly IGameService _gameService;
private readonly IMatchesRepository _resultsDao;
private readonly ILogger<BotGameManagerService> _logger;
public BotGameManagerService(
IPlayFabService playFabService,
IChallengerService challengers,
IGameService gameService,
IMatchesRepository resultsDao,
ILogger<BotGameManagerService> logger
)
{
{
_playFabService = playFabService;
_challengersService = challengers;
_gameService = gameService;
_resultsDao = resultsDao;
@ -64,7 +68,12 @@ namespace RPSLS.Game.Api.GrpcServices
if (result.IsValid && request.TwitterLogged)
{
await _resultsDao.SaveMatch(pick, request.Username, request.Pick, result.Result);
await _resultsDao.SaveMatch(pick, request.Username, request.Pick, result.Result);
}
if (_playFabService.HasCredentials)
{
await _playFabService.UpdateStats(request.Username, result.Result == Result.Player);
}
return result;

Просмотреть файл

@ -102,7 +102,7 @@ namespace RPSLS.Game.Api.GrpcServices
{
var username = GetUsername(request.Username, request.TwitterLogged);
var dto = await _repository.GetMatch(request.MatchId);
while (dto.PlayerName == UnknownUser && dto.Challenger.Name == UnknownUser)
while (!context.CancellationToken.IsCancellationRequested && (dto == null || (dto.PlayerName == UnknownUser && dto.Challenger.Name == UnknownUser)))
{
await Task.Delay(_multiplayerSettings.GameStatusUpdateDelay);
dto = await _repository.GetMatch(request.MatchId);

Просмотреть файл

@ -10,5 +10,6 @@
public TokenSettings Token { get; set; } = new TokenSettings();
public int GameStatusUpdateDelay { get; set; } = 1000;
public int GameStatusMaxWait { get; set; } = 60;
public int EntityTokenExpirationMinutes { get; set; } = 60;
}
}

Просмотреть файл

@ -0,0 +1,28 @@
using System;
namespace RPSLS.Game.Multiplayer.Models
{
public class Token
{
private readonly int _maxTokenLifeMinutes;
private readonly DateTime _creationTimeStamp;
public Token(string value, int maxTokenLifeMinutes)
{
Value = value;
_maxTokenLifeMinutes = maxTokenLifeMinutes;
_creationTimeStamp = DateTime.UtcNow;
}
public string Value { get; private set; }
public bool IsExpired
{
get
{
var tokenLife = DateTime.UtcNow.Subtract(_creationTimeStamp);
return tokenLife.Minutes > _maxTokenLifeMinutes;
}
}
}
}

Просмотреть файл

@ -22,6 +22,8 @@ namespace RPSLS.Game.Multiplayer.Services
private readonly ILogger<PlayFabService> _logger;
private readonly MultiplayerSettings _settings;
private Token _entityToken = null;
public bool HasCredentials { get => !string.IsNullOrWhiteSpace(_settings.Title) && !string.IsNullOrWhiteSpace(_settings.SecretKey); }
public PlayFabService(ILogger<PlayFabService> logger, IOptions<MultiplayerSettings> settings)
@ -43,6 +45,13 @@ namespace RPSLS.Game.Multiplayer.Services
public async Task<string> GetEntityToken(string userTitleId = null)
{
if (_entityToken?.Value != null && !_entityToken.IsExpired)
{
return _entityToken.Value;
}
PlayFabAuthenticationAPI.ForgetAllCredentials();
var tokenRequestBuilder = new GetEntityTokenRequestBuilder();
if (!string.IsNullOrWhiteSpace(userTitleId))
{
@ -52,7 +61,10 @@ namespace RPSLS.Game.Multiplayer.Services
var entityTokenResult = await Call(
PlayFabAuthenticationAPI.GetEntityTokenAsync,
tokenRequestBuilder);
return entityTokenResult.EntityToken;
_entityToken = new Token(entityTokenResult.EntityToken, _settings.EntityTokenExpirationMinutes);
return _entityToken.Value;
}
public async Task<string> CreateTicket(string username, string token)
@ -125,13 +137,7 @@ namespace RPSLS.Game.Multiplayer.Services
return;
}
var loginResult = await Call(
PlayFabClientAPI.LoginWithCustomIDAsync,
new LoginWithCustomIDRequestBuilder()
.WithUser(username.ToUpperInvariant())
.WithAccountInfo()
.CreateIfDoesntExist());
var loginResult = await UserLogin(username.ToUpperInvariant());
var statsRequestBuilder = new UpdatePlayerStatisticsRequestBuilder()
.WithPlayerId(loginResult.PlayFabId)
.WithStatsIncrease(TotalStat);
@ -154,7 +160,7 @@ namespace RPSLS.Game.Multiplayer.Services
.WithStats(WinsStat)
.WithLimits(0, _settings.Leaderboard.Top));
var players = new List<LeaderboardEntry>();
var players = new List<LeaderboardEntry>();
foreach (var entry in leaderboardResult.Leaderboard)
{
var isTwitterUser = !(entry.DisplayName?.StartsWith("$") ?? false);
@ -172,6 +178,12 @@ namespace RPSLS.Game.Multiplayer.Services
}
private async Task<EntityKey> GetUserEntity(string username)
{
var loginResult = await UserLogin(username);
return loginResult.EntityToken.Entity;
}
private async Task<LoginResult> UserLogin(string username)
{
var loginResult = await Call(
PlayFabClientAPI.LoginWithCustomIDAsync,
@ -180,7 +192,6 @@ namespace RPSLS.Game.Multiplayer.Services
.WithAccountInfo()
.CreateIfDoesntExist());
var userEntity = loginResult.EntityToken.Entity;
if (loginResult.NewlyCreated || loginResult.InfoResultPayload?.AccountInfo?.TitleInfo?.DisplayName != username)
{
// Add a DisplayName to the title user so its easier to retrieve the user;
@ -190,7 +201,7 @@ namespace RPSLS.Game.Multiplayer.Services
.WithName(username.ToUpperInvariant()));
}
return userEntity;
return loginResult;
}
private async Task EnsureQueueExist()

Просмотреть файл

@ -24,6 +24,11 @@
<div class="subtitle-container">
<h2 class="subtitle">The geek version of rock-paper-scissors.</h2>
<h2 class="subtitle">Play with a friend or try to defeat our bot!</h2>
<p class="info-contest">
April 17th - May 15th, play to get to a chance to win awesome prizes.
<a href="/assets/pdfs/RPSLS_Rules.pdf" target="_blank">See Rules</a>
for more information.
</p>
</div>
@if (string.IsNullOrWhiteSpace(Username))
@ -44,7 +49,7 @@
</div>
}
<div class="custom-button-container" >
<div class="custom-button-container">
<div class="custom-button @(UserNameIsEmpty? "custom-button-disabled" : "")">
<button type="button" @onclick="PlayAgainstBots" class="custom-button-link" disabled="@UserNameIsEmpty">Play with a bot</button>
</div>
@ -68,15 +73,15 @@
@code
{
private string CustomUsername { get; set; }
private string CustomUsername { get; set; }
[Parameter]
public string RedirectUrl { get; set; }
[Parameter]
public string RedirectUrl { get; set; }
public string Username { get; set; }
public bool IsTwitterUser { get; set; }
public string Username { get; set; }
public bool IsTwitterUser { get; set; }
public bool UserNameIsEmpty => String.IsNullOrEmpty(Username) && String.IsNullOrEmpty(CustomUsername);
public bool UserNameIsEmpty => String.IsNullOrEmpty(Username) && String.IsNullOrEmpty(CustomUsername);
protected override async Task OnInitializedAsync()
{
@ -115,7 +120,7 @@
{
if (!string.IsNullOrWhiteSpace(Username))
{
}
NavigationManager.NavigateTo("/", true);

Просмотреть файл

@ -9,6 +9,11 @@
<div class="leaderboard-container">
<h1 class="leaderboard-title">THE LEADERBOARD</h1>
<h2 class="leaderboard-subtitle">Only Twitter users will be shown on the leaderboard.</h2>
<p class="info-contest">
April 17th - May 15th, play to get to a chance to win awesome prizes.
<a href="/assets/pdfs/RPSLS_Rules.pdf" target="_blank">See Rules</a>
for more information.
</p>
<table class="leaderboard">
<thead>
<tr>
@ -28,6 +33,9 @@
}
</tbody>
</table>
<div class="leaderboard-powered">
<p>Powered by <a href="https://playfab.com/" target="_blank">Playfab</a></p>
</div>
<div class="leaderboard-buttons">
<div class="custom-button">
<a class="custom-button-link" href="/">play again</a>

Двоичные данные
Source/Services/RPSLS.Web/wwwroot/assets/pdfs/RPSLS_Rules.pdf Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -30,7 +30,7 @@
.leaderboard-link img {
width: auto;
height: 100px;
height: 80px;
}
.leaderboard-link a {
@ -112,7 +112,7 @@
}
.login-section .logo {
width: 72%;
width: 60%;
}
/* Twitter */
@ -120,7 +120,7 @@
margin-top: 1rem;
color: #ffffff;
font-size: 1.1rem;
margin-bottom: 2.5rem;
margin-bottom: 1.5rem;
}
.login-section .sign_twitter a {
@ -128,6 +128,23 @@
color: #ffffff;
}
/* Contest */
.info-contest {
background: rgb(249, 194, 85,0.3);
border: 1px solid #f9c255;
margin-top: 1.5rem;
border-radius: 5px;
color: #ffffff;
padding: 0.75rem;
margin-bottom: 0;
}
.info-contest a {
text-decoration: underline;
color: #ffffff;
}
/* Form */
form {
display: flex;

Просмотреть файл

@ -27,6 +27,11 @@
flex-direction: column;
}
.leaderboard-container .info-contest {
text-align: center;
margin: 1rem 0;
}
.leaderboard-title {
margin: 0;
padding-top: 35px;
@ -52,6 +57,17 @@
height: 40px;
}
.leaderboard-powered {
color: #FFFFFF;
font-size: 0.8rem;
text-align: center;
}
.leaderboard-powered a {
color: #FFFFFF;
text-decoration: underline;
}
.leaderboard {
margin-top: 20px;
font-family: "Work Sans";
@ -59,7 +75,7 @@
font-size: 1.5rem;
color: white;
border-spacing: 0;
height: calc(100% - 270px);
height: calc(100% - 400px);
table-layout: fixed;
}