IW4M-Admin/Plugins/Stats/Helpers/AdvancedClientStatsResourceQueryHelper.cs
RaidMax c5375b661b huge commit for advanced stats feature.
broke data out into its own library.
may be breaking changes with existing plugins
2021-03-22 11:09:25 -05:00

156 lines
6.4 KiB
C#

using System;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Data.Abstractions;
using Data.Models.Client;
using Data.Models.Client.Stats;
using IW4MAdmin.Plugins.Stats;
using IW4MAdmin.Plugins.Stats.Config;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using SharedLibraryCore.Dtos;
using SharedLibraryCore.Helpers;
using SharedLibraryCore.Interfaces;
using Stats.Client.Abstractions;
using Stats.Dtos;
using ILogger = Microsoft.Extensions.Logging.ILogger;
namespace Stats.Helpers
{
public class AdvancedClientStatsResourceQueryHelper : IResourceQueryHelper<StatsInfoRequest, AdvancedStatsInfo>
{
private readonly IDatabaseContextFactory _contextFactory;
private readonly ILogger _logger;
private readonly IManager _manager;
public AdvancedClientStatsResourceQueryHelper(ILogger<AdvancedClientStatsResourceQueryHelper> logger,
IDatabaseContextFactory contextFactory, IManager manager)
{
_contextFactory = contextFactory;
_logger = logger;
_manager = manager;
}
public async Task<ResourceQueryHelperResult<AdvancedStatsInfo>> QueryResource(StatsInfoRequest query)
{
await using var context = _contextFactory.CreateContext(enableTracking: false);
long? serverId = null;
if (!string.IsNullOrEmpty(query.ServerEndpoint))
{
serverId = (await context.Servers
.Select(server => new {server.EndPoint, server.Id})
.FirstOrDefaultAsync(server => server.EndPoint == query.ServerEndpoint))
?.Id;
}
var clientInfo = await context.Clients.Select(client => new
{
client.ClientId,
client.CurrentAlias.Name,
client.Level
}).FirstOrDefaultAsync(client => client.ClientId == query.ClientId);
if (clientInfo == null)
{
return null;
}
// gets all the hit stats for the client
var hitStats = await context.Set<EFClientHitStatistic>()
.Include(stat => stat.HitLocation)
.Include(stat => stat.MeansOfDeath)
.Include(stat => stat.Weapon)
.Include(stat => stat.WeaponAttachmentCombo)
.ThenInclude(attachment => attachment.Attachment1)
.Include(stat => stat.WeaponAttachmentCombo)
.ThenInclude(attachment => attachment.Attachment2)
.Include(stat => stat.WeaponAttachmentCombo)
.ThenInclude(attachment => attachment.Attachment3)
.Where(stat => stat.ClientId == query.ClientId)
.Where(stat => stat.ServerId == serverId)
.ToListAsync();
var ratings = await context.Set<EFClientRankingHistory>()
.Where(r => r.ClientId == clientInfo.ClientId)
.Where(r => r.ServerId == serverId)
.Where(r => r.Ranking != null)
.OrderByDescending(r => r.UpdatedDateTime)
.ToListAsync();
var mostRecentRanking = ratings.FirstOrDefault(ranking => ranking.Newest);
var ranking = mostRecentRanking?.Ranking + 1;
// get stat for server, or all if no serverId
var legacyStats = await context.Set<EFClientStatistics>()
.Where(stat => stat.ClientId == query.ClientId)
.Where(stat => serverId == null || stat.ServerId == serverId)
.ToListAsync();
if (mostRecentRanking != null && mostRecentRanking.CreatedDateTime < Extensions.FifteenDaysAgo())
{
ranking = 0;
}
if (clientInfo.Level == EFClient.Permission.Banned)
{
ranking = null;
}
var hitInfo = new AdvancedStatsInfo()
{
ServerId = serverId,
Performance = mostRecentRanking?.PerformanceMetric,
ZScore = mostRecentRanking?.ZScore,
ServerEndpoint = query.ServerEndpoint,
ClientName = clientInfo.Name,
ClientId = clientInfo.ClientId,
Level = clientInfo.Level,
Rating = mostRecentRanking?.PerformanceMetric,
All = hitStats,
Servers = _manager.GetServers()
.Select(server => new ServerInfo()
{Name = server.Hostname, IPAddress = server.IP, Port = server.Port})
.ToList(),
Aggregate = hitStats.FirstOrDefault(hit =>
hit.HitLocationId == null && hit.ServerId == serverId && hit.WeaponId == null &&
hit.MeansOfDeathId == null),
ByHitLocation = hitStats
.Where(hit => hit.HitLocationId != null)
.Where(hit => hit.WeaponId == null)
.Where(hit => hit.WeaponAttachmentComboId == null)
.ToList(),
ByWeapon = hitStats
.Where(hit => hit.HitLocationId == null)
.Where(hit => hit.WeaponId != null)
.ToList(),
ByAttachmentCombo = hitStats
.Where(hit => hit.HitLocationId == null)
.Where(hit => hit.WeaponId != null)
.Where(hit => hit.WeaponAttachmentComboId != null)
.ToList(),
Ratings = ratings,
LegacyStats = legacyStats,
Ranking = ranking,
};
// todo: when nothign found
return new ResourceQueryHelperResult<AdvancedStatsInfo>()
{
Results = new[] {hitInfo}
};
}
public static Expression<Func<EFClientStatistics, bool>> GetRankingFunc(int minPlayTime, double? zScore = null,
long? serverId = null)
{
return (stats) => (serverId == null || stats.ServerId == serverId) &&
stats.UpdatedAt >= Extensions.FifteenDaysAgo() &&
stats.Client.Level != EFClient.Permission.Banned &&
stats.TimePlayed >= minPlayTime
&& (zScore == null || stats.ZScore > zScore);
}
}
}