Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add training ground gamemode #367

Open
wants to merge 65 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
146115e
create trainingmode gamemode based on duel
Muparadzi Dec 20, 2023
1c09f1c
tidy code
Muparadzi Dec 21, 2023
3a6b467
remove duel references
Muparadzi Dec 21, 2023
88f5632
tidy up
Muparadzi Dec 21, 2023
f19451e
remove respawning
Muparadzi Jan 2, 2024
c4e8db5
remove respawn from duel
Muparadzi Jan 4, 2024
832fef3
add nice gui
Muparadzi Jan 4, 2024
483807a
add clan and level to ui
Muparadzi Jan 4, 2024
c55bcf8
refine ui
Muparadzi Jan 5, 2024
c2ccc72
compress ui card
Muparadzi Jan 5, 2024
407e303
create trainingmode gamemode based on duel
Muparadzi Dec 20, 2023
2ebad30
tidy code
Muparadzi Dec 21, 2023
8223d88
remove duel references
Muparadzi Dec 21, 2023
7495d42
tidy up
Muparadzi Dec 21, 2023
72fd912
remove respawning
Muparadzi Jan 2, 2024
198f867
remove respawn from duel
Muparadzi Jan 4, 2024
2156f6f
add nice gui
Muparadzi Jan 4, 2024
2cc7b73
add clan and level to ui
Muparadzi Jan 4, 2024
5c41963
refine ui
Muparadzi Jan 5, 2024
df55ba2
compress ui card
Muparadzi Jan 5, 2024
edb511e
map
Muparadzi Jan 5, 2024
9e078a5
merge with remote
Muparadzi Jan 5, 2024
ef51f56
remove config
Muparadzi Jan 5, 2024
207599f
add colour coded rating
Muparadzi Jan 7, 2024
52d7812
use constants
Muparadzi Jan 7, 2024
89276fd
remove and tidy stuff
Muparadzi Jan 9, 2024
9599579
fix crash
Muparadzi Jan 9, 2024
1ed9501
add refresh character option and remove kill feed
Muparadzi Jan 10, 2024
c9d95f0
refill players after or before duel
Muparadzi Jan 10, 2024
b69e6e3
add duel result message
Muparadzi Jan 28, 2024
1704fa7
initial commit
Muparadzi Feb 18, 2024
48964ae
more commits
Muparadzi Feb 18, 2024
b2d7ddd
fix null limitation
Muparadzi Feb 19, 2024
4de7954
add gamemode buttons
Muparadzi Feb 19, 2024
494af53
seperate mmr into game statistics
Muparadzi Feb 27, 2024
0cf3968
null check
Muparadzi Feb 27, 2024
b25c2fc
use query param
Muparadzi Feb 28, 2024
1f8e7b3
remove route stuff
Muparadzi Feb 28, 2024
ab51863
use instance for stats, retrieve all stats in single query
Muparadzi Feb 28, 2024
8241fdb
remove unnecessary directives
Muparadzi Feb 28, 2024
227f98c
remove unecessary stuff
Muparadzi Feb 28, 2024
4ae3bb3
remove locale stuff
Muparadzi Feb 28, 2024
117a002
rebase with seperate gamemodes
Muparadzi Feb 29, 2024
d6da828
launch settings
Muparadzi Feb 29, 2024
d3beae6
revert changes
Muparadzi Feb 29, 2024
cc547c5
rebase
Muparadzi Feb 29, 2024
9ec4bca
add rating updates
Muparadzi Feb 29, 2024
53a1508
show new rating on change
Muparadzi Feb 29, 2024
933e36f
update representative with new rating
Muparadzi Mar 4, 2024
38a710a
Merge branch 'master' into droob-add-training-ground-rating
Muparadzi Jul 2, 2024
4aaf0aa
merge updates
Muparadzi Jul 2, 2024
1e846c1
leaderboard fix
Muparadzi Jul 2, 2024
cdb13e9
default value for gamemode query
Muparadzi Jul 2, 2024
f9531c3
update statistics
Muparadzi Jul 18, 2024
32cdf71
fix typo
Muparadzi Jul 18, 2024
4f41826
Merge branch 'master' into droob-add-training-ground-rating
Muparadzi Jul 18, 2024
f9500ba
update warnings and localisation
Muparadzi Jul 18, 2024
0f9c0a0
Merge branch 'master' into droob-add-training-ground-rating
Muparadzi Jul 18, 2024
8008427
orle-ui-tuning
or2e Jul 18, 2024
7302298
orle-remove-unused
or2e Jul 18, 2024
b245272
orle-spec-cleanup
or2e Jul 18, 2024
96228f3
orle-typo
or2e Jul 18, 2024
aa7b86d
orle-hotfix
or2e Jul 18, 2024
cba8311
orle-cleanup
or2e Jul 18, 2024
812a874
add migrations
Muparadzi Jul 19, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public async Task<Result<CharacterViewModel>> Handle(ResetCharacterRatingCommand
return new(CommonErrors.CharacterNotFound(req.CharacterId, req.UserId));
}

_characterService.ResetRating(character);
_characterService.ResetAllRatings(character);

_db.ActivityLogs.Add(_activityLogService.CreateCharacterRatingResetLog(character.UserId, character.Id));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public async Task<Result<CharacterViewModel>> Handle(RetireCharacterCommand req,
}

int oldCharacterLevel = character.Level;
_characterService.ResetRating(character);
_characterService.ResetAllRatings(character);
var error = _characterService.Retire(character);
if (error != null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Crpg.Application.Common.Mediator;
using Crpg.Application.Common.Results;
using Crpg.Application.Common.Services;
using Crpg.Domain.Entities.Characters;
using Microsoft.EntityFrameworkCore;

namespace Crpg.Application.Characters.Commands;
Expand All @@ -25,7 +26,11 @@ public async Task<Result> Handle(UpdateEveryCharacterCompetitiveRatingCommand re

foreach (var character in characters)
{
character.Rating.CompetitiveValue = _competitiveRatingModel.ComputeCompetitiveRating(character.Rating);
foreach (CharacterStatistics statistics in character.Statistics)
{
statistics.Rating.CompetitiveValue = _competitiveRatingModel.ComputeCompetitiveRating(statistics.Rating);
}

// Trick to avoid UpdatedAt to be updated.
character.UpdatedAt = character.UpdatedAt;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ public record CharacterPublicViewModel : IMapFrom<Character>
public int Id { get; init; }
public int Level { get; init; }
public CharacterClass Class { get; init; }
public CharacterRatingViewModel Rating { get; init; } = new();
public IList<CharacterStatisticsViewModel> Statistics { get; init; } = Array.Empty<CharacterStatisticsViewModel>();
public UserPublicViewModel User { get; init; } = new();
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Crpg.Application.Common.Mappings;
using Crpg.Application.Common.Mappings;
using Crpg.Domain.Entities.Characters;
using Crpg.Domain.Entities.Servers;

Expand All @@ -11,4 +11,5 @@ public record CharacterStatisticsViewModel : IMapFrom<CharacterStatistics>
public int Assists { get; init; }
public TimeSpan PlayTime { get; init; }
public GameMode GameMode { get; init; }
public CharacterRatingViewModel Rating { get; init; } = new();
}
10 changes: 9 additions & 1 deletion src/Application/Characters/Models/GameCharacterViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using AutoMapper;
using Crpg.Application.Common.Mappings;
using Crpg.Application.Items.Models;
using Crpg.Domain.Entities.Characters;
Expand All @@ -14,6 +15,13 @@ public record GameCharacterViewModel : IMapFrom<Character>
public CharacterClass Class { get; init; }
public bool ForTournament { get; init; }
public CharacterCharacteristicsViewModel Characteristics { get; init; } = new();

public CharacterStatisticsViewModel Statistics { get; set; } = new();
public IList<GameEquippedItemViewModel> EquippedItems { get; init; } = Array.Empty<GameEquippedItemViewModel>();
public CharacterRatingViewModel Rating { get; init; } = new();

public void Mapping(Profile profile)
{
profile.CreateMap<Character, GameCharacterViewModel>()
.ForMember(gc => gc.Statistics, opt => opt.MapFrom(c => c.Statistics.FirstOrDefault()));
}
}
23 changes: 16 additions & 7 deletions src/Application/Characters/Queries/GetLeaderboardQuery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Crpg.Application.Common.Results;
using Crpg.Domain.Entities;
using Crpg.Domain.Entities.Characters;
using Crpg.Domain.Entities.Servers;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;

Expand All @@ -15,6 +16,7 @@ public record GetLeaderboardQuery : IMediatorRequest<IList<CharacterPublicViewMo
{
public Region? Region { get; set; }
public CharacterClass? CharacterClass { get; set; }
public GameMode? GameMode { get; set; }

internal class Handler : IMediatorRequestHandler<GetLeaderboardQuery, IList<CharacterPublicViewModel>>
{
Expand All @@ -35,15 +37,17 @@ public async Task<Result<IList<CharacterPublicViewModel>>> Handle(GetLeaderboard

if (_cache.TryGetValue(cacheKey, out IList<CharacterPublicViewModel>? results) == false)
{
var requestGameMode = req.GameMode ?? Domain.Entities.Servers.GameMode.CRPGBattle;
// Todo: use DistinctBy here when EfCore implements it (does not work for now: https://github.com/dotnet/efcore/issues/27470 )
var topRatedCharactersByRegion = await _db.Characters
.Include(c => c.User)
.OrderByDescending(c => c.Rating.CompetitiveValue)
.Where(c => (req.Region == null || req.Region == c.User!.Region)
&& (req.CharacterClass == null || req.CharacterClass == c.Class))
.Take(500)
.ProjectTo<CharacterPublicViewModel>(_mapper.ConfigurationProvider)
.ToArrayAsync(cancellationToken);
.Include(c => c.User)
.Where(c => (req.Region == null || req.Region == c.User!.Region)
&& (req.CharacterClass == null || req.CharacterClass == c.Class)
&& c.Statistics.First(s => s.GameMode == requestGameMode) != null)
.OrderByDescending(c => c.Statistics.First(s => s.GameMode == requestGameMode).Rating.CompetitiveValue)
.Take(500)
.ProjectTo<CharacterPublicViewModel>(_mapper.ConfigurationProvider)
.ToArrayAsync(cancellationToken);

IList<CharacterPublicViewModel> data = topRatedCharactersByRegion.DistinctBy(c => c.User.Id).Take(50).ToList();

Expand Down Expand Up @@ -71,6 +75,11 @@ private string GetCacheKey(GetLeaderboardQuery req)
keys.Add(req.CharacterClass.ToString()!);
}

if (req.GameMode != null)
{
keys.Add(req.GameMode.ToString()!);
}

return string.Join("::", keys);
}
}
Expand Down
42 changes: 0 additions & 42 deletions src/Application/Characters/Queries/GetUserCharacterRatingQuery.cs

This file was deleted.

65 changes: 43 additions & 22 deletions src/Application/Common/Services/ICharacterService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using Crpg.Common.Helpers;
using Crpg.Domain.Entities.Characters;
using Crpg.Domain.Entities.Limitations;
using Crpg.Domain.Entities.Servers;

namespace Crpg.Application.Common.Services;

Expand All @@ -22,9 +23,11 @@ internal interface ICharacterService
/// <param name="respecialization">If the stats points should be redistributed.</param>
void ResetCharacterCharacteristics(Character character, bool respecialization = false);

void UpdateRating(Character character, float value, float deviation, float volatility, bool isGameUserUpdate = false);
void UpdateRating(Character character, GameMode gameMode, float value, float deviation, float volatility, bool isGameUserUpdate = false);

void ResetRating(Character character);
void ResetAllRatings(Character character);

void ResetRating(Character character, GameMode gameMode);

void ResetStatistics(Character character);

Expand Down Expand Up @@ -56,8 +59,8 @@ public void SetValuesForNewUserStartingCharacter(Character character)
character.Level = _constants.NewUserStartingCharacterLevel;
character.Experience = _experienceTable.GetExperienceForLevel(character.Level);
character.Class = CharacterClass.Infantry;
ResetRating(character);
ResetStatistics(character);
ResetAllRatings(character);
}

public void SetDefaultValuesForCharacter(Character character)
Expand All @@ -66,9 +69,9 @@ public void SetDefaultValuesForCharacter(Character character)
character.Level = _constants.MinimumLevel;
character.Experience = _experienceTable.GetExperienceForLevel(character.Level);
character.ForTournament = false;
ResetCharacterCharacteristics(character);
ResetRating(character);
ResetStatistics(character);
ResetCharacterCharacteristics(character);
ResetAllRatings(character);
}

/// <inheritdoc />
Expand Down Expand Up @@ -96,36 +99,54 @@ public void ResetCharacterCharacteristics(Character character, bool respecializa

public void ResetStatistics(Character character)
{
foreach (CharacterStatistics modeStats in character.Statistics)
character.Statistics = new List<CharacterStatistics>();

foreach (GameMode gameMode in Enum.GetValues(typeof(GameMode)))
{
modeStats.Kills = 0;
modeStats.Deaths = 0;
modeStats.Assists = 0;
modeStats.PlayTime = TimeSpan.Zero;
character.Statistics.Add(new CharacterStatistics
{
GameMode = gameMode,
Kills = 0,
Deaths = 0,
Assists = 0,
PlayTime = TimeSpan.Zero,
});
}
}

public void UpdateRating(Character character, float value, float deviation, float volatility, bool isGameUserUpdate = false)
public void UpdateRating(Character character, GameMode gameMode, float value, float deviation, float volatility, bool isGameUserUpdate = false)
{
if (character.Level == 1
&& isGameUserUpdate == true)
if (character.Level == 1 && isGameUserUpdate)
{
return;
}

character.Rating = new CharacterRating
var statistic = character.Statistics.FirstOrDefault(s => s.GameMode == gameMode);
if (statistic != null)
{
Value = value,
Deviation = deviation,
Volatility = volatility,
};
character.Rating.CompetitiveValue = _competitiveRatingModel.ComputeCompetitiveRating(character.Rating);
statistic.Rating = new CharacterRating
{
Value = value,
Deviation = deviation,
Volatility = volatility,
};

statistic.Rating.CompetitiveValue = _competitiveRatingModel.ComputeCompetitiveRating(statistic.Rating);
}
}

public void ResetAllRatings(Character character)
{
foreach (GameMode gameMode in Enum.GetValues(typeof(GameMode)))
{
ResetRating(character, gameMode);
}
}

public void ResetRating(Character character)
public void ResetRating(Character character, GameMode gameMode)
{
UpdateRating(character, _constants.DefaultRating, _constants.DefaultRatingDeviation,
_constants.DefaultRatingVolatility);
UpdateRating(character, gameMode, _constants.DefaultRating, _constants.DefaultRatingDeviation,
_constants.DefaultRatingVolatility);
}

public Error? Retire(Character character)
Expand Down
35 changes: 34 additions & 1 deletion src/Application/Games/Commands/GetGameUserCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Crpg.Domain.Entities.Characters;
using Crpg.Domain.Entities.Items;
using Crpg.Domain.Entities.Limitations;
using Crpg.Domain.Entities.Servers;
using Crpg.Domain.Entities.Users;
using Crpg.Sdk.Abstractions;
using FluentValidation;
Expand All @@ -25,6 +26,7 @@ public record GetGameUserCommand : IMediatorRequest<GameUserViewModel>
public Platform Platform { get; init; }
public string PlatformUserId { get; init; } = default!;
public Region Region { get; init; }
public string Instance { get; init; } = string.Empty;

public class Validator : AbstractValidator<GetGameUserCommand>
{
Expand Down Expand Up @@ -135,10 +137,11 @@ internal class Handler : IMediatorRequestHandler<GetGameUserCommand, GameUserVie
private readonly IUserService _userService;
private readonly ICharacterService _characterService;
private readonly IActivityLogService _activityLogService;
private readonly IGameModeService _gameModeService;

public Handler(ICrpgDbContext db, IMapper mapper, IDateTime dateTime,
IRandom random, IUserService userService, ICharacterService characterService,
IActivityLogService activityLogService)
IActivityLogService activityLogService, IGameModeService gameModeService)
{
_db = db;
_mapper = mapper;
Expand All @@ -147,6 +150,7 @@ internal class Handler : IMediatorRequestHandler<GetGameUserCommand, GameUserVie
_userService = userService;
_characterService = characterService;
_activityLogService = activityLogService;
_gameModeService = gameModeService;
}

public async Task<Result<GameUserViewModel>> Handle(GetGameUserCommand req, CancellationToken cancellationToken)
Expand Down Expand Up @@ -211,6 +215,35 @@ await _db.Entry(user.ActiveCharacter)
.Query()
.Include(ei => ei.UserItem)
.LoadAsync(cancellationToken);

if (!Enum.TryParse(req.Instance, true, out GameModeAlias instanceAlias))
{
instanceAlias = GameModeAlias.Z; // Default value if parsing fails.
}

GameMode currentGameMode = _gameModeService.GameModeByInstanceAlias(instanceAlias);

var statistics = await _db.Entry(user.ActiveCharacter)
.Collection(c => c.Statistics)
.Query()
.Where(s => s.GameMode == currentGameMode)
.Include(s => s.Rating)
.AsNoTracking()
.ToListAsync(cancellationToken);

var statistic = statistics.FirstOrDefault();

if (statistic == null)
{
user.ActiveCharacter.Statistics.Add(new CharacterStatistics { GameMode = currentGameMode });
_characterService.ResetRating(user.ActiveCharacter, currentGameMode);
await _db.SaveChangesAsync(cancellationToken);

statistic = user.ActiveCharacter.Statistics.First(s => s.GameMode == currentGameMode);
}

// Only load the relevant statistic for the gameMode
user.ActiveCharacter.Statistics = new List<CharacterStatistics> { statistic };
}

var gameUser = _mapper.Map<GameUserViewModel>(user);
Expand Down
Loading
Loading