hopeful topstats fixes
This commit is contained in:
parent
fb11bf54a6
commit
686b297d32
@ -22,7 +22,7 @@ namespace Stats.Client
|
|||||||
|
|
||||||
private readonly IDataValueCache<EFClientStatistics, Dictionary<long, Extensions.LogParams>>
|
private readonly IDataValueCache<EFClientStatistics, Dictionary<long, Extensions.LogParams>>
|
||||||
_distributionCache;
|
_distributionCache;
|
||||||
|
|
||||||
private readonly IDataValueCache<EFClientStatistics, double>
|
private readonly IDataValueCache<EFClientStatistics, double>
|
||||||
_maxZScoreCache;
|
_maxZScoreCache;
|
||||||
|
|
||||||
@ -51,9 +51,9 @@ namespace Stats.Client
|
|||||||
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
||||||
|
|
||||||
var distributions = new Dictionary<long, Extensions.LogParams>();
|
var distributions = new Dictionary<long, Extensions.LogParams>();
|
||||||
|
|
||||||
await LoadServers();
|
await LoadServers();
|
||||||
|
|
||||||
foreach (var serverId in _serverIds)
|
foreach (var serverId in _serverIds)
|
||||||
{
|
{
|
||||||
var performance = await set
|
var performance = await set
|
||||||
@ -63,14 +63,14 @@ namespace Stats.Client
|
|||||||
.Where(s => s.Client.Level != EFClient.Permission.Banned)
|
.Where(s => s.Client.Level != EFClient.Permission.Banned)
|
||||||
.Where(s => s.TimePlayed >= validPlayTime)
|
.Where(s => s.TimePlayed >= validPlayTime)
|
||||||
.Where(s => s.UpdatedAt >= Extensions.FifteenDaysAgo())
|
.Where(s => s.UpdatedAt >= Extensions.FifteenDaysAgo())
|
||||||
.Select(s => s.EloRating * 1/3.0 + s.Skill * 2/3.0).ToListAsync();
|
.Select(s => s.EloRating * 1 / 3.0 + s.Skill * 2 / 3.0).ToListAsync();
|
||||||
var distributionParams = performance.GenerateDistributionParameters();
|
var distributionParams = performance.GenerateDistributionParameters();
|
||||||
distributions.Add(serverId, distributionParams);
|
distributions.Add(serverId, distributionParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
return distributions;
|
return distributions;
|
||||||
}), DistributionCacheKey, Utilities.IsDevelopment ? TimeSpan.FromMinutes(5) : TimeSpan.FromHours(1));
|
}), DistributionCacheKey, Utilities.IsDevelopment ? TimeSpan.FromMinutes(5) : TimeSpan.FromHours(1));
|
||||||
|
|
||||||
_maxZScoreCache.SetCacheItem(async (set, token) =>
|
_maxZScoreCache.SetCacheItem(async (set, token) =>
|
||||||
{
|
{
|
||||||
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
var validPlayTime = _configurationHandler.Configuration()?.TopPlayersMinPlayTime ?? 3600 * 3;
|
||||||
@ -79,13 +79,16 @@ namespace Stats.Client
|
|||||||
.Where(AdvancedClientStatsResourceQueryHelper.GetRankingFunc(validPlayTime))
|
.Where(AdvancedClientStatsResourceQueryHelper.GetRankingFunc(validPlayTime))
|
||||||
.Where(s => s.Skill > 0)
|
.Where(s => s.Skill > 0)
|
||||||
.Where(s => s.EloRating > 0)
|
.Where(s => s.EloRating > 0)
|
||||||
.MaxAsync(s => (double?)s.ZScore, token);
|
.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;
|
return zScore ?? 0;
|
||||||
}, MaxZScoreCacheKey, Utilities.IsDevelopment ? TimeSpan.FromMinutes(5) : TimeSpan.FromMinutes(30));
|
}, MaxZScoreCacheKey, Utilities.IsDevelopment ? TimeSpan.FromMinutes(5) : TimeSpan.FromMinutes(30));
|
||||||
|
|
||||||
await _distributionCache.GetCacheItem(DistributionCacheKey);
|
await _distributionCache.GetCacheItem(DistributionCacheKey);
|
||||||
await _maxZScoreCache.GetCacheItem(MaxZScoreCacheKey);
|
await _maxZScoreCache.GetCacheItem(MaxZScoreCacheKey);
|
||||||
|
|
||||||
/*foreach (var serverId in _serverIds)
|
/*foreach (var serverId in _serverIds)
|
||||||
{
|
{
|
||||||
await using var ctx = _contextFactory.CreateContext(enableTracking: true);
|
await using var ctx = _contextFactory.CreateContext(enableTracking: true);
|
||||||
@ -138,6 +141,7 @@ namespace Stats.Client
|
|||||||
{
|
{
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
var zScore = (Math.Log(value) - sdParams.Mean) / sdParams.Sigma;
|
var zScore = (Math.Log(value) - sdParams.Mean) / sdParams.Sigma;
|
||||||
return zScore;
|
return zScore;
|
||||||
}
|
}
|
||||||
@ -145,7 +149,7 @@ namespace Stats.Client
|
|||||||
public async Task<double?> GetRatingForZScore(double? value)
|
public async Task<double?> GetRatingForZScore(double? value)
|
||||||
{
|
{
|
||||||
var maxZScore = await _maxZScoreCache.GetCacheItem(MaxZScoreCacheKey);
|
var maxZScore = await _maxZScoreCache.GetCacheItem(MaxZScoreCacheKey);
|
||||||
return maxZScore == 0 ? 0 : value.GetRatingForZScore(maxZScore);
|
return maxZScore == 0 ? null : value.GetRatingForZScore(maxZScore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +121,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
{
|
{
|
||||||
return (ranking) => ranking.ServerId == serverId
|
return (ranking) => ranking.ServerId == serverId
|
||||||
&& ranking.Client.Level != Data.Models.Client.EFClient.Permission.Banned
|
&& ranking.Client.Level != Data.Models.Client.EFClient.Permission.Banned
|
||||||
&& ranking.Client.LastConnection >= Extensions.FifteenDaysAgo()
|
&& ranking.CreatedDateTime >= Extensions.FifteenDaysAgo()
|
||||||
&& ranking.ZScore != null
|
&& ranking.ZScore != null
|
||||||
&& ranking.PerformanceMetric != null
|
&& ranking.PerformanceMetric != null
|
||||||
&& ranking.Newest
|
&& ranking.Newest
|
||||||
@ -895,7 +895,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
public async Task AddStandardKill(EFClient attacker, EFClient victim)
|
public async Task AddStandardKill(EFClient attacker, EFClient victim)
|
||||||
{
|
{
|
||||||
long serverId = GetIdForServer(attacker.CurrentServer);
|
var serverId = GetIdForServer(attacker.CurrentServer);
|
||||||
|
|
||||||
var attackerStats = attacker.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
var attackerStats = attacker.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
||||||
var victimStats = victim.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
var victimStats = victim.GetAdditionalProperty<EFClientStatistics>(CLIENT_STATS_KEY);
|
||||||
@ -903,6 +903,18 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
// update the total stats
|
// update the total stats
|
||||||
_servers[serverId].ServerStatistics.TotalKills += 1;
|
_servers[serverId].ServerStatistics.TotalKills += 1;
|
||||||
|
|
||||||
|
if (attackerStats == null)
|
||||||
|
{
|
||||||
|
_log.LogWarning("Stats for {Client} are not yet initialized", attacker.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (victimStats == null)
|
||||||
|
{
|
||||||
|
_log.LogWarning("Stats for {Client} are not yet initialized", victim.ToString());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// this happens when the round has changed
|
// this happens when the round has changed
|
||||||
if (attackerStats.SessionScore == 0)
|
if (attackerStats.SessionScore == 0)
|
||||||
{
|
{
|
||||||
@ -961,7 +973,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
|
|
||||||
// update their performance
|
// update their performance
|
||||||
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >=
|
if ((DateTime.UtcNow - attackerStats.LastStatHistoryUpdate).TotalMinutes >=
|
||||||
(Utilities.IsDevelopment ? 0.5 : _configHandler.Configuration().EnableAdvancedMetrics ? 10.0 : 2.5))
|
(Utilities.IsDevelopment ? 0.5 : _configHandler.Configuration().EnableAdvancedMetrics ? 5.0 : 2.5))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -1178,16 +1190,17 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
public async Task UpdateHistoricalRanking(int clientId, EFClientStatistics clientStats, long serverId)
|
public async Task UpdateHistoricalRanking(int clientId, EFClientStatistics clientStats, long serverId)
|
||||||
{
|
{
|
||||||
await using var context = _contextFactory.CreateContext();
|
await using var context = _contextFactory.CreateContext();
|
||||||
|
var minPlayTime = _configHandler.Configuration().TopPlayersMinPlayTime;
|
||||||
|
|
||||||
var performances = await context.Set<EFClientStatistics>()
|
var performances = await context.Set<EFClientStatistics>()
|
||||||
.AsNoTracking()
|
.AsNoTracking()
|
||||||
.Where(stat => stat.ClientId == clientId)
|
.Where(stat => stat.ClientId == clientId)
|
||||||
.Where(stat => stat.ServerId != serverId) // ignore the one we're currently tracking
|
.Where(stat => stat.ServerId != serverId) // ignore the one we're currently tracking
|
||||||
.Where(stats => stats.UpdatedAt >= Extensions.FifteenDaysAgo())
|
.Where(stats => stats.UpdatedAt >= Extensions.FifteenDaysAgo())
|
||||||
.Where(stats => stats.TimePlayed >= _configHandler.Configuration().TopPlayersMinPlayTime)
|
.Where(stats => stats.TimePlayed >= minPlayTime)
|
||||||
.ToListAsync();
|
.ToListAsync();
|
||||||
|
|
||||||
if (clientStats.TimePlayed >= _configHandler.Configuration().TopPlayersMinPlayTime)
|
if (clientStats.TimePlayed >= minPlayTime)
|
||||||
{
|
{
|
||||||
clientStats.ZScore = await _serverDistributionCalculator.GetZScoreForServer(serverId,
|
clientStats.ZScore = await _serverDistributionCalculator.GetZScoreForServer(serverId,
|
||||||
clientStats.Performance);
|
clientStats.Performance);
|
||||||
@ -1198,7 +1211,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
_configHandler.Configuration().TopPlayersMinPlayTime, clientStats.ZScore, serverId))
|
_configHandler.Configuration().TopPlayersMinPlayTime, clientStats.ZScore, serverId))
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
|
|
||||||
var serverRankingSnapshot = new EFClientRankingHistory()
|
var serverRankingSnapshot = new EFClientRankingHistory
|
||||||
{
|
{
|
||||||
ClientId = clientId,
|
ClientId = clientId,
|
||||||
ServerId = serverId,
|
ServerId = serverId,
|
||||||
@ -1215,27 +1228,35 @@ namespace IW4MAdmin.Plugins.Stats.Helpers
|
|||||||
performances.Add(clientStats);
|
performances.Add(clientStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (performances.Any(performance => performance.TimePlayed >= _configHandler.Configuration().TopPlayersMinPlayTime))
|
if (performances.Any(performance => performance.TimePlayed >= minPlayTime))
|
||||||
{
|
{
|
||||||
var aggregateZScore = performances.WeightValueByPlaytime(nameof(EFClientStatistics.ZScore), _configHandler.Configuration().TopPlayersMinPlayTime);
|
var aggregateZScore = performances.WeightValueByPlaytime(nameof(EFClientStatistics.ZScore), minPlayTime);
|
||||||
|
|
||||||
int? aggregateRanking = await context.Set<EFClientStatistics>()
|
int? aggregateRanking = await context.Set<EFClientStatistics>()
|
||||||
.Where(stat => stat.ClientId != clientId)
|
.Where(stat => stat.ClientId != clientId)
|
||||||
.Where(AdvancedClientStatsResourceQueryHelper.GetRankingFunc(_configHandler.Configuration()
|
.Where(AdvancedClientStatsResourceQueryHelper.GetRankingFunc(minPlayTime))
|
||||||
.TopPlayersMinPlayTime))
|
|
||||||
.GroupBy(stat => stat.ClientId)
|
.GroupBy(stat => stat.ClientId)
|
||||||
.Where(group =>
|
.Where(group =>
|
||||||
group.Sum(stat => stat.ZScore * stat.TimePlayed) / group.Sum(stat => stat.TimePlayed) >
|
group.Sum(stat => stat.ZScore * stat.TimePlayed) / group.Sum(stat => stat.TimePlayed) >
|
||||||
aggregateZScore)
|
aggregateZScore)
|
||||||
.Select(c => c.Key)
|
.Select(c => c.Key)
|
||||||
.CountAsync();
|
.CountAsync();
|
||||||
|
|
||||||
|
var newPerformanceMetric = await _serverDistributionCalculator.GetRatingForZScore(aggregateZScore);
|
||||||
|
|
||||||
|
if (newPerformanceMetric == null)
|
||||||
|
{
|
||||||
|
_log.LogWarning("Could not determine performance metric for {Client} {AggregateZScore}",
|
||||||
|
clientStats.Client?.ToString(), aggregateZScore);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var aggregateRankingSnapshot = new EFClientRankingHistory()
|
var aggregateRankingSnapshot = new EFClientRankingHistory
|
||||||
{
|
{
|
||||||
ClientId = clientId,
|
ClientId = clientId,
|
||||||
ZScore = aggregateZScore,
|
ZScore = aggregateZScore,
|
||||||
Ranking = aggregateRanking,
|
Ranking = aggregateRanking,
|
||||||
PerformanceMetric = await _serverDistributionCalculator.GetRatingForZScore(aggregateZScore),
|
PerformanceMetric = newPerformanceMetric,
|
||||||
Newest = true,
|
Newest = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user