Merge pull request #28 from OriolBonjoch/master
Added Leaderboard stats when playing with bots
This commit is contained in:
Коммит
0acaf82872
|
@ -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;
|
||||
|
@ -11,18 +12,21 @@ 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;
|
||||
|
@ -67,6 +71,11 @@ namespace RPSLS.Game.Api.GrpcServices
|
|||
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()
|
||||
{
|
||||
|
|
|
@ -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>
|
||||
|
|
Двоичный файл не отображается.
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче