IW4M-Admin/Plugins/Stats/Client/ServerDistributionCalculator.cs

159 lines
6.5 KiB
C#
Raw Normal View History

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
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 SharedLibraryCore;
using SharedLibraryCore.Interfaces;
using Stats.Client.Abstractions;
using Stats.Config;
using Stats.Helpers;
namespace Stats.Client
{
public class ServerDistributionCalculator : IServerDistributionCalculator
{
private readonly IDatabaseContextFactory _contextFactory;
private readonly IDataValueCache<EFClientStatistics, Dictionary<long, Extensions.LogParams>>
_distributionCache;
2022-01-24 16:08:31 -05:00
private readonly IDataValueCache<EFClientStatistics, double>
_maxZScoreCache;
private readonly IConfigurationHandler<StatsConfiguration> _configurationHandler;
private readonly List<long> _serverIds = new List<long>();
private const string DistributionCacheKey = nameof(DistributionCacheKey);
private const string MaxZScoreCacheKey = nameof(MaxZScoreCacheKey);
public ServerDistributionCalculator(IDatabaseContextFactory contextFactory,
IDataValueCache<EFClientStatistics, Dictionary<long, Extensions.LogParams>> distributionCache,
IDataValueCache<EFClientStatistics, double> maxZScoreCache,
IConfigurationHandlerFactory configFactory)
{
_contextFactory = contextFactory;
_distributionCache = distributionCache;
_maxZScoreCache = maxZScoreCache;
_configurationHandler = configFactory.GetConfigurationHandler<StatsConfiguration>("StatsPluginSettings");
}
public async Task Initialize()
{
await LoadServers();
2021-08-27 22:05:30 -04:00
_distributionCache.SetCacheItem((async (set, token) =>
{
2022-01-28 10:35:01 -05:00
await _configurationHandler.BuildAsync();
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
var distributions = new Dictionary<long, Extensions.LogParams>();
2022-01-24 16:08:31 -05:00
await LoadServers();
2022-01-24 16:08:31 -05:00
foreach (var serverId in _serverIds)
{
var performance = await set
.Where(s => s.ServerId == serverId)
.Where(s => s.Skill > 0)
.Where(s => s.EloRating > 0)
.Where(s => s.Client.Level != EFClient.Permission.Banned)
.Where(s => s.TimePlayed >= validPlayTime)
.Where(s => s.UpdatedAt >= Extensions.FifteenDaysAgo())
2022-01-24 16:08:31 -05:00
.Select(s => s.EloRating * 1 / 3.0 + s.Skill * 2 / 3.0).ToListAsync();
var distributionParams = performance.GenerateDistributionParameters();
distributions.Add(serverId, distributionParams);
}
return distributions;
}), DistributionCacheKey, Utilities.IsDevelopment ? TimeSpan.FromMinutes(5) : TimeSpan.FromHours(1));
2022-01-24 16:08:31 -05:00
2021-08-27 22:05:30 -04:00
_maxZScoreCache.SetCacheItem(async (set, token) =>
{
2022-01-28 10:35:01 -05:00
await _configurationHandler.BuildAsync();
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
var zScore = await set
.Where(AdvancedClientStatsResourceQueryHelper.GetRankingFunc(validPlayTime))
.Where(s => s.Skill > 0)
.Where(s => s.EloRating > 0)
2022-01-24 16:08:31 -05:00
.GroupBy(stat => stat.ClientId)
.Select(group =>
group.Sum(stat => stat.ZScore * stat.TimePlayed) / group.Sum(stat => stat.TimePlayed))
.MaxAsync(avgZScore => (double?) avgZScore, token);
return zScore ?? 0;
}, MaxZScoreCacheKey, Utilities.IsDevelopment ? TimeSpan.FromMinutes(5) : TimeSpan.FromMinutes(30));
await _distributionCache.GetCacheItem(DistributionCacheKey, new CancellationToken());
await _maxZScoreCache.GetCacheItem(MaxZScoreCacheKey, new CancellationToken());
2022-01-24 16:08:31 -05:00
/*foreach (var serverId in _serverIds)
{
await using var ctx = _contextFactory.CreateContext(enableTracking: true);
var a = await ctx.Set<EFClientStatistics>()
.Where(s => s.ServerId == serverId)
//.Where(s=> s.ClientId == 216105)
.Where(s => s.Skill > 0)
.Where(s => s.EloRating > 0)
.Where(s => s.Client.Level != EFClient.Permission.Banned)
.Where(s => s.TimePlayed >= 3600 * 3)
.Where(s => s.UpdatedAt >= Extensions.FifteenDaysAgo())
.ToListAsync();
var b = a.Distinct();
foreach (var item in b)
{
await Plugin.Manager.UpdateHistoricalRanking(item.ClientId, item, item.ServerId);
//item.ZScore = await GetZScoreForServer(serverId, item.Performance);
//item.UpdatedAt = DateTime.UtcNow;
}
await ctx.SaveChangesAsync();
}*/
}
private async Task LoadServers()
{
if (_serverIds.Count == 0)
{
await using var context = _contextFactory.CreateContext(false);
_serverIds.AddRange(await context.Servers
.Where(s => s.EndPoint != null && s.HostName != null)
.Select(s => s.ServerId)
.ToListAsync());
}
}
public async Task<double> GetZScoreForServer(long serverId, double value)
{
var serverParams = await _distributionCache.GetCacheItem(DistributionCacheKey, new CancellationToken());
if (!serverParams.ContainsKey(serverId))
{
return 0.0;
}
var sdParams = serverParams[serverId];
if (sdParams.Sigma == 0)
{
return 0.0;
}
2022-01-24 16:08:31 -05:00
var zScore = (Math.Log(value) - sdParams.Mean) / sdParams.Sigma;
return zScore;
}
public async Task<double?> GetRatingForZScore(double? value)
{
var maxZScore = await _maxZScoreCache.GetCacheItem(MaxZScoreCacheKey, new CancellationToken());
2022-01-24 16:08:31 -05:00
return maxZScore == 0 ? null : value.GetRatingForZScore(maxZScore);
}
}
2022-01-24 16:08:31 -05:00
}