/// <summary> /// Performs the incrementation of kills and deaths for client statistics /// </summary> /// <param name="attackerStats">Stats of the attacker</param> /// <param name="victimStats">Stats of the victim</param> public void CalculateKill(EFClientStatistics attackerStats, EFClientStatistics victimStats) { bool suicide = attackerStats.ClientId == victimStats.ClientId; // only update their kills if they didn't kill themselves if (!suicide) { attackerStats.Kills += 1; attackerStats.SessionKills += 1; attackerStats.KillStreak += 1; attackerStats.DeathStreak = 0; } victimStats.Deaths += 1; victimStats.SessionDeaths += 1; victimStats.DeathStreak += 1; victimStats.KillStreak = 0; // process the attacker's stats after the kills attackerStats = UpdateStats(attackerStats); // update after calculation attackerStats.TimePlayed += (int)(DateTime.UtcNow - attackerStats.LastActive).TotalSeconds; victimStats.TimePlayed += (int)(DateTime.UtcNow - victimStats.LastActive).TotalSeconds; attackerStats.LastActive = DateTime.UtcNow; victimStats.LastActive = DateTime.UtcNow; }
public Detection(ILogger log, EFClientStatistics clientStats) { Log = log; HitLocationCount = new Dictionary <IW4Info.HitLocation, int>(); foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation))) { HitLocationCount.Add((IW4Info.HitLocation)loc, 0); } LastKill = DateTime.UtcNow; ClientStats = clientStats; }
/// <summary> /// Add Player to the player stats /// </summary> /// <param name="pl">Player to add/retrieve stats for</param> /// <returns>EFClientStatistic of specified player</returns> public EFClientStatistics AddPlayer(Player pl) { int serverId = pl.CurrentServer.GetHashCode(); var playerStats = Servers[serverId].PlayerStats; var statsSvc = ContextThreads[serverId]; // get the client's stats from the database if it exists, otherwise create and attach a new one // if this fails we want to throw an exception var clientStats = statsSvc.ClientStatSvc.Find(c => c.ClientId == pl.ClientId && c.ServerId == serverId).FirstOrDefault(); if (clientStats == null) { clientStats = new EFClientStatistics() { Active = true, ClientId = pl.ClientId, Deaths = 0, Kills = 0, ServerId = serverId, Skill = 0.0, SPM = 0.0, }; clientStats = statsSvc.ClientStatSvc.Insert(clientStats); } // set these on connecting clientStats.LastActive = DateTime.UtcNow; clientStats.LastStatCalculation = DateTime.UtcNow; lock (playerStats) { if (playerStats.ContainsKey(pl.ClientNumber)) { Log.WriteWarning($"Duplicate clientnumber in stats {pl.ClientId} vs {playerStats[pl.ClientNumber].ClientId}"); playerStats.Remove(pl.ClientNumber); } playerStats.Add(pl.ClientNumber, clientStats); } var detectionStats = Servers[serverId].PlayerDetections; lock (detectionStats) { if (detectionStats.ContainsKey(pl.ClientNumber)) { detectionStats.Remove(pl.ClientNumber); } detectionStats.Add(pl.ClientNumber, new Cheat.Detection(Log)); } return(clientStats); }
/// <summary> /// Update the client stats (skill etc) /// </summary> /// <param name="clientStats">Client statistics</param> /// <returns></returns> private EFClientStatistics UpdateStats(EFClientStatistics clientStats) { // prevent NaN or inactive time lowering SPM if ((DateTime.UtcNow - clientStats.LastStatCalculation).TotalSeconds / 60.0 < 0.01 || (DateTime.UtcNow - clientStats.LastActive).TotalSeconds / 60.0 > 3 || clientStats.SessionScore < 1) { return(clientStats); } double timeSinceLastCalc = (DateTime.UtcNow - clientStats.LastStatCalculation).TotalSeconds / 60.0; double timeSinceLastActive = (DateTime.UtcNow - clientStats.LastActive).TotalSeconds / 60.0; // calculate the players Score Per Minute for the current session int scoreDifference = clientStats.LastScore == 0 ? 0 : clientStats.SessionScore - clientStats.LastScore; double killSPM = scoreDifference / timeSinceLastCalc; // calculate how much the KDR should weigh // 1.637 is a Eddie-Generated number that weights the KDR nicely double kdr = clientStats.Deaths == 0 ? clientStats.Kills : clientStats.KDR; double KDRWeight = Math.Round(Math.Pow(kdr, 1.637 / Math.E), 3); // if no SPM, weight is 1 else the weight ishe current session's spm / lifetime average score per minute //double SPMWeightAgainstAverage = (clientStats.SPM < 1) ? 1 : killSPM / clientStats.SPM; // calculate the weight of the new play time against last 10 hours of gameplay int totalPlayTime = (clientStats.TimePlayed == 0) ? (int)(DateTime.UtcNow - clientStats.LastActive).TotalSeconds : clientStats.TimePlayed + (int)(DateTime.UtcNow - clientStats.LastActive).TotalSeconds; double SPMAgainstPlayWeight = timeSinceLastCalc / Math.Min(600, (totalPlayTime / 60.0)); // calculate the new weight against average times the weight against play time clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight)); clientStats.SPM = Math.Round(clientStats.SPM, 3); clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight), 3); // fixme: how does this happen? if (double.IsNaN(clientStats.SPM) || double.IsNaN(clientStats.Skill)) { Log.WriteWarning("[StatManager::UpdateStats] clientStats SPM/Skill NaN"); Log.WriteDebug($"{killSPM}-{KDRWeight}-{totalPlayTime}-{SPMAgainstPlayWeight}-{clientStats.SPM}-{clientStats.Skill}-{scoreDifference}"); clientStats.SPM = 0; clientStats.Skill = 0; } clientStats.LastStatCalculation = DateTime.UtcNow; clientStats.LastScore = clientStats.SessionScore; return(clientStats); }
public Detection(ILogger log, EFClientStatistics clientStats) { Log = log; HitLocationCount = new Dictionary <IW4Info.HitLocation, HitInfo>(); foreach (var loc in Enum.GetValues(typeof(IW4Info.HitLocation))) { HitLocationCount.Add((IW4Info.HitLocation)loc, new HitInfo()); } ClientStats = clientStats; Strain = new Strain(); Tracker = new ChangeTracking <EFACSnapshot>(); TrackedHits = new List <EFClientKill>(); }
public async Task Test_StatsQueryHelper_Get() { var queryHelper = serviceProvider.GetRequiredService <StatsResourceQueryHelper>(); await using var context = contextFactory.CreateContext(); var server = new EFServer() { ServerId = 1 }; var stats = new EFClientStatistics() { Client = ClientGenerators.CreateBasicClient(null), SPM = 100, Server = server }; var ratingHistory = new EFClientRatingHistory() { Client = stats.Client, Ratings = new[] { new EFRating() { Ranking = 100, Server = server, Newest = true } } }; context.Set <EFClientStatistics>().Add(stats); context.Set <EFClientRatingHistory>().Add(ratingHistory); await context.SaveChangesAsync(); var query = new StatsInfoRequest() { ClientId = stats.Client.ClientId }; var result = await queryHelper.QueryResource(query); Assert.IsNotEmpty(result.Results); Assert.AreEqual(stats.SPM, result.Results.First().ScorePerMinute); Assert.AreEqual(ratingHistory.Ratings.First().Ranking, result.Results.First().Ranking); context.Set <EFClientStatistics>().Remove(stats); context.Set <EFClientRatingHistory>().Remove(ratingHistory); context.Set <EFServer>().Remove(server); await context.SaveChangesAsync(); }
/// <summary> /// Update the client stats (skill etc) /// </summary> /// <param name="clientStats">Client statistics</param> /// <returns></returns> private EFClientStatistics UpdateStats(EFClientStatistics clientStats) { double timeSinceLastCalc = (DateTime.UtcNow - clientStats.LastStatCalculation).TotalSeconds / 60.0; double timeSinceLastActive = (DateTime.UtcNow - clientStats.LastActive).TotalSeconds / 60.0; // prevent NaN or inactive time lowering SPM if (timeSinceLastCalc == 0 || timeSinceLastActive > 3) { return(clientStats); } // calculate the players Score Per Minute for the current session int currentScore = Manager.GetActiveClients() .First(c => c.ClientId == clientStats.ClientId) .Score; double killSPM = currentScore / (timeSinceLastCalc * 60.0); // calculate how much the KDR should weigh // 1.637 is a Eddie-Generated number that weights the KDR nicely double KDRWeight = Math.Round(Math.Pow(clientStats.KDR, 1.637 / Math.E), 3); // if no SPM, weight is 1 else the weight ishe current session's spm / lifetime average score per minute double SPMWeightAgainstAverage = (clientStats.SPM < 1) ? 1 : killSPM / clientStats.SPM; // calculate the weight of the new play time against last 10 hours of gameplay int totalPlayTime = (clientStats.TimePlayed == 0) ? (int)(DateTime.UtcNow - clientStats.LastActive).TotalSeconds : clientStats.TimePlayed + (int)(DateTime.UtcNow - clientStats.LastActive).TotalSeconds; double SPMAgainstPlayWeight = timeSinceLastCalc / Math.Min(600, (totalPlayTime / 60.0)); // calculate the new weight against average times the weight against play time clientStats.SPM = (killSPM * SPMAgainstPlayWeight) + (clientStats.SPM * (1 - SPMAgainstPlayWeight)); clientStats.SPM = Math.Round(clientStats.SPM, 3); clientStats.Skill = Math.Round((clientStats.SPM * KDRWeight), 3); clientStats.LastStatCalculation = DateTime.UtcNow; clientStats.LastScore = currentScore; return(clientStats); }
/// <summary> /// Add Player to the player stats /// </summary> /// <param name="pl">Player to add/retrieve stats for</param> /// <returns>EFClientStatistic of specified player</returns> public async Task <EFClientStatistics> AddPlayer(Player pl) { Log.WriteInfo($"Adding {pl} to stats"); int serverId = pl.CurrentServer.GetHashCode(); if (!Servers.ContainsKey(serverId)) { Log.WriteError($"[Stats::AddPlayer] Server with id {serverId} could not be found"); return(null); } var playerStats = Servers[serverId].PlayerStats; var statsSvc = ContextThreads[serverId]; // get the client's stats from the database if it exists, otherwise create and attach a new one // if this fails we want to throw an exception var clientStats = statsSvc.ClientStatSvc.Find(c => c.ClientId == pl.ClientId && c.ServerId == serverId).FirstOrDefault(); if (clientStats == null) { clientStats = new EFClientStatistics() { Active = true, ClientId = pl.ClientId, Deaths = 0, Kills = 0, ServerId = serverId, Skill = 0.0, SPM = 0.0, HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType <IW4Info.HitLocation>().Select(hl => new EFHitLocationCount() { Active = true, HitCount = 0, Location = hl }) .ToList() }; clientStats = statsSvc.ClientStatSvc.Insert(clientStats); await statsSvc.ClientStatSvc.SaveChangesAsync(); } // migration for previous existing stats else if (clientStats.HitLocations.Count == 0) { clientStats.HitLocations = Enum.GetValues(typeof(IW4Info.HitLocation)).OfType <IW4Info.HitLocation>().Select(hl => new EFHitLocationCount() { Active = true, HitCount = 0, Location = hl }) .ToList(); await statsSvc.ClientStatSvc.SaveChangesAsync(); } // set these on connecting clientStats.LastActive = DateTime.UtcNow; clientStats.LastStatCalculation = DateTime.UtcNow; clientStats.SessionScore = pl.Score; if (playerStats.ContainsKey(pl.ClientId)) { Log.WriteWarning($"Duplicate ClientId in stats {pl.ClientId} vs {playerStats[pl.ClientId].ClientId}"); playerStats.TryRemove(pl.ClientId, out EFClientStatistics removedValue); } playerStats.TryAdd(pl.ClientId, clientStats); var detectionStats = Servers[serverId].PlayerDetections; if (detectionStats.ContainsKey(pl.ClientId)) { detectionStats.TryRemove(pl.ClientId, out Cheat.Detection removedValue); } detectionStats.TryAdd(pl.ClientId, new Cheat.Detection(Log, clientStats)); // todo: look at this more statsSvc.ClientStatSvc.Update(clientStats); await statsSvc.ClientStatSvc.SaveChangesAsync(); return(clientStats); }
public async Task AddStandardKill(Player attacker, Player victim) { int serverId = attacker.CurrentServer.GetHashCode(); EFClientStatistics attackerStats = null; try { attackerStats = Servers[serverId].PlayerStats[attacker.ClientId]; } catch (KeyNotFoundException) { Log.WriteError($"[Stats::AddStandardKill] kill attacker ClientId is invalid {attacker.ClientId}-{attacker}"); return; } EFClientStatistics victimStats = null; try { victimStats = Servers[serverId].PlayerStats[victim.ClientId]; } catch (KeyNotFoundException) { Log.WriteError($"[Stats::AddStandardKill] kill victim ClientId is invalid {victim.ClientId}-{victim}"); return; } // update the total stats Servers[serverId].ServerStatistics.TotalKills += 1; attackerStats.SessionScore = attacker.Score; victimStats.SessionScore = victim.Score; // calculate for the clients CalculateKill(attackerStats, victimStats); // show encouragement/discouragement string streakMessage = (attackerStats.ClientId != victimStats.ClientId) ? StreakMessage.MessageOnStreak(attackerStats.KillStreak, attackerStats.DeathStreak) : StreakMessage.MessageOnStreak(-1, -1); if (streakMessage != string.Empty) { await attacker.Tell(streakMessage); } // fixme: why? if (double.IsNaN(victimStats.SPM) || double.IsNaN(victimStats.Skill)) { Log.WriteDebug($"[StatManager::AddStandardKill] victim SPM/SKILL {victimStats.SPM} {victimStats.Skill}"); victimStats.SPM = 0.0; victimStats.Skill = 0.0; } if (double.IsNaN(attackerStats.SPM) || double.IsNaN(attackerStats.Skill)) { Log.WriteDebug($"[StatManager::AddStandardKill] attacker SPM/SKILL {victimStats.SPM} {victimStats.Skill}"); attackerStats.SPM = 0.0; attackerStats.Skill = 0.0; } // todo: do we want to save this immediately? var statsSvc = ContextThreads[serverId]; statsSvc.ClientStatSvc.Update(attackerStats); statsSvc.ClientStatSvc.Update(victimStats); await statsSvc.ClientStatSvc.SaveChangesAsync(); }
public DetectionPenaltyResult ProcessTotalRatio(EFClientStatistics stats) { int totalChestKills = stats.HitLocations.Single(c => c.Location == IW4Info.HitLocation.torso_upper).HitCount; if (totalChestKills >= 60) { double marginOfError = Thresholds.GetMarginOfError(totalChestKills); double lerpAmount = Math.Min(1.0, (totalChestKills - 60) / 250.0); // determine max acceptable ratio of chest to abdomen kills double chestAbdomenRatioLerpValueForFlag = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdHighSample(3.0), Thresholds.ChestAbdomenRatioThresholdHighSample(2), lerpAmount) + marginOfError; double chestAbdomenLerpValueForBan = Thresholds.Lerp(Thresholds.ChestAbdomenRatioThresholdHighSample(4.0), Thresholds.ChestAbdomenRatioThresholdHighSample(4.0), lerpAmount) + marginOfError; double currentChestAbdomenRatio = totalChestKills / stats.HitLocations.Single(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount; if (currentChestAbdomenRatio > chestAbdomenRatioLerpValueForFlag) { if (currentChestAbdomenRatio > chestAbdomenLerpValueForBan) { Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Ban**"); Log.WriteDebug($"ClientId: {stats.ClientId}"); Log.WriteDebug($"**Total Chest Kills: {totalChestKills}"); Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}"); Log.WriteDebug($"**MaxRatio {chestAbdomenLerpValueForBan}"); var sb = new StringBuilder(); foreach (var location in stats.HitLocations) { sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n"); } Log.WriteDebug(sb.ToString()); // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); return(new DetectionPenaltyResult() { ClientPenalty = Penalty.PenaltyType.Ban, RatioAmount = currentChestAbdomenRatio, Bone = IW4Info.HitLocation.torso_upper, KillCount = totalChestKills }); } else { Log.WriteDebug("**Maximum Lifetime Chest/Abdomen Ratio Reached For Flag**"); Log.WriteDebug($"ClientId: {stats.ClientId}"); Log.WriteDebug($"**Total Chest Kills: {totalChestKills}"); Log.WriteDebug($"**Ratio {currentChestAbdomenRatio}"); Log.WriteDebug($"**MaxRatio {chestAbdomenRatioLerpValueForFlag}"); var sb = new StringBuilder(); foreach (var location in stats.HitLocations) { sb.Append($"HitLocation: {location.Location} -> {location.HitCount}\r\n"); } Log.WriteDebug(sb.ToString()); // Log.WriteDebug($"ThresholdReached: {AboveThresholdCount}"); return(new DetectionPenaltyResult() { ClientPenalty = Penalty.PenaltyType.Flag, RatioAmount = currentChestAbdomenRatio, Bone = IW4Info.HitLocation.torso_upper, KillCount = totalChestKills }); } } } return(new DetectionPenaltyResult() { Bone = IW4Info.HitLocation.none, ClientPenalty = Penalty.PenaltyType.Any }); }
public override async Task ExecuteAsync(GameEvent E) { string statLine; EFClientStatistics pStats = null; if (E.Data.Length > 0 && E.Target == null) { E.Target = E.Owner.GetClientByName(E.Data).FirstOrDefault(); if (E.Target == null) { E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_VIEW_FAIL"]); } } var serverId = StatManager.GetIdForServer(E.Owner); var totalRankedPlayers = await Plugin.Manager.GetTotalRankedPlayers(serverId); // getting stats for a particular client if (E.Target != null) { var performanceRanking = await Plugin.Manager.GetClientOverallRanking(E.Target.ClientId, serverId); var performanceRankingString = performanceRanking == 0 ? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} (Color::Accent)#{performanceRanking}/{totalRankedPlayers}"; // target is currently connected so we want their cached stats if they exist if (E.Owner.GetClientsAsList().Any(client => client.Equals(E.Target))) { pStats = E.Target.GetAdditionalProperty <EFClientStatistics>(StatManager.CLIENT_STATS_KEY); } // target is not connected so we want to look up via database if (pStats == null) { await using var context = _contextFactory.CreateContext(false); pStats = await context.Set <EFClientStatistics>() .FirstOrDefaultAsync(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId); } // if it's still null then they've not gotten a kill or death yet statLine = pStats == null ? _translationLookup["PLUGINS_STATS_COMMANDS_NOTAVAILABLE"] : _translationLookup["COMMANDS_VIEW_STATS_RESULT"].FormatExt(pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Performance, performanceRankingString); } // getting self stats else { var performanceRanking = await Plugin.Manager.GetClientOverallRanking(E.Origin.ClientId, serverId); var performanceRankingString = performanceRanking == 0 ? _translationLookup["WEBFRONT_STATS_INDEX_UNRANKED"] : $"{_translationLookup["WEBFRONT_STATS_INDEX_RANKED"]} (Color::Accent)#{performanceRanking}/{totalRankedPlayers}"; // check if current client is connected to the server if (E.Owner.GetClientsAsList().Any(client => client.Equals(E.Origin))) { pStats = E.Origin.GetAdditionalProperty <EFClientStatistics>(StatManager.CLIENT_STATS_KEY); } // happens if the user has not gotten a kill/death since connecting if (pStats == null) { await using var context = _contextFactory.CreateContext(false); pStats = (await context.Set <EFClientStatistics>() .FirstOrDefaultAsync(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId)); } // if it's still null then they've not gotten a kill or death yet statLine = pStats == null ? _translationLookup["PLUGINS_STATS_COMMANDS_NOTAVAILABLE"] : _translationLookup["COMMANDS_VIEW_STATS_RESULT"].FormatExt(pStats.Kills, pStats.Deaths, pStats.KDR, pStats.Performance, performanceRankingString); } if (E.Message.IsBroadcastCommand(_config.BroadcastCommandPrefix)) { var name = E.Target == null ? E.Origin.Name : E.Target.Name; E.Owner.Broadcast(_translationLookup["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(name)); E.Owner.Broadcast(statLine); } else { if (E.Target != null) { E.Origin.Tell(_translationLookup["PLUGINS_STATS_COMMANDS_VIEW_SUCCESS"].FormatExt(E.Target.Name)); } E.Origin.Tell(statLine); } }
public async Task OnLoadAsync(IManager manager) { // #if DO_IMPORT var svc = new GenericRepository <EFServer>(); svc.Insert(new EFServer() { Active = true, Port = 28960, ServerId = Math.Abs("127.0.0.1:28960".GetHashCode()), }); svc.Insert(new EFServer() { Active = true, Port = 28965, ServerId = Math.Abs("127.0.0.1:28965".GetHashCode()), }); svc.Insert(new EFServer() { Active = true, Port = 28970, ServerId = Math.Abs("127.0.0.1:28970".GetHashCode()), }); svc.SaveChanges(); // #endif Interval = DateTime.Now; var clients = new List <Player>(); var oldClients = new Dictionary <int, Player>(); #region CLIENTS if (File.Exists("import_clients.csv")) { manager.GetLogger().WriteVerbose("Beginning import of existing clients"); var lines = File.ReadAllLines("import_clients.csv").Skip(1); foreach (string line in lines) { string[] fields = Regex.Replace(line, "\".*\"", "").Split(','); fields.All(f => { f = f.StripColors().Trim(); return(true); }); if (fields.Length != 11) { manager.GetLogger().WriteError("Invalid client import file... aborting import"); return; } if (fields[1].Substring(0, 5) == "01100" || fields[0] == string.Empty || fields[1] == string.Empty || fields[6] == string.Empty) { continue; } if (!Regex.Match(fields[6], @"^\d+\.\d+\.\d+.\d+$").Success) { fields[6] = "0"; } var client = new Player() { Name = fields[0], NetworkId = fields[1].ConvertLong(), IPAddress = fields[6].ConvertToIP(), Level = (Player.Permission)Convert.ToInt32(fields[3]), Connections = Convert.ToInt32(fields[5]), LastConnection = DateTime.Parse(fields[7]), }; clients.Add(client); oldClients.Add(Convert.ToInt32(fields[2]), client); } clients = clients.Distinct().ToList(); // #if DO_IMPORT /*clients = clients * .GroupBy(c => new { c.Name, c.IPAddress }) * .Select(c => c.FirstOrDefault()) * .ToList();*/ //newClients = clients.ToList(); //newClients.ForEach(c => c.ClientId = 0); manager.GetLogger().WriteVerbose($"Read {clients.Count} clients for import"); try { SharedLibrary.Database.Importer.ImportClients(clients); } catch (Exception e) { manager.GetLogger().WriteError("Saving imported clients failed"); } // #endif } #endregion // load the entire database lol var ctx = new DatabaseContext(); ctx.Configuration.ProxyCreationEnabled = false; var cls = ctx.Clients.Include("AliasLink.Children").ToList(); //manager.GetClientService().Find(c => c.Active).Result; ctx.Dispose(); #region ALIASES if (File.Exists("import_aliases.csv")) { manager.GetLogger().WriteVerbose("Beginning import of existing aliases"); var aliases = new List <EFAlias>(); var lines = File.ReadAllLines("import_aliases.csv").Skip(1); foreach (string line in lines) { string[] fields = Regex.Replace(line, "\".*\"", "").Split(','); fields.All(f => { f = f.StripColors().Trim(); return(true); }); if (fields.Length != 3) { manager.GetLogger().WriteError("Invalid alias import file... aborting import"); return; } try { int number = Int32.Parse(fields[0]); var names = fields[1].Split(';').Where(n => n != String.Empty && n.Length > 2); var oldClient = oldClients[number]; var newClient = cls.FirstOrDefault(c => c.NetworkId == oldClient.NetworkId); foreach (string name in names) { // this is slow :D if (newClient.AliasLink.Children.FirstOrDefault(n => n.Name == name) != null) { continue; } var alias = new EFAlias() { Active = true, DateAdded = DateTime.UtcNow, Name = name, LinkId = newClient.AliasLinkId, IPAddress = newClient.IPAddress }; aliases.Add(alias); } } catch (KeyNotFoundException) { continue; } catch (Exception) { manager.GetLogger().WriteVerbose($"Could not import alias with line {line}"); } } SharedLibrary.Database.Importer.ImportSQLite(aliases); } #endregion #region PENALTIES if (File.Exists("import_penalties.csv")) { var penalties = new List <Penalty>(); manager.GetLogger().WriteVerbose("Beginning import of existing penalties"); foreach (string line in File.ReadAllLines("import_penalties.csv").Skip(1)) { string comma = Regex.Match(line, "\".*,.*\"").Value.Replace(",", ""); string[] fields = Regex.Replace(line, "\".*,.*\"", comma).Split(','); fields.All(f => { f = f.StripColors().Trim(); return(true); }); if (fields.Length != 7) { manager.GetLogger().WriteError("Invalid penalty import file... aborting import"); return; } if (fields[2].Substring(0, 5) == "01100" || fields[2].Contains("0000000")) { continue; } try { var expires = DateTime.Parse(fields[6]); var when = DateTime.Parse(fields[5]); var penaltyType = (Penalty.PenaltyType)Int32.Parse(fields[0]); if (penaltyType == Penalty.PenaltyType.Ban) { expires = DateTime.MaxValue; } var penalty = new Penalty() { Type = penaltyType, Expires = expires == DateTime.MinValue ? when : expires, Punisher = new SharedLibrary.Database.Models.EFClient() { NetworkId = fields[3].ConvertLong() }, Offender = new SharedLibrary.Database.Models.EFClient() { NetworkId = fields[2].ConvertLong() }, Offense = fields[1].Replace("\"", "").Trim(), Active = true, When = when, }; penalties.Add(penalty); } catch (Exception e) { manager.GetLogger().WriteVerbose($"Could not import penalty with line {line}"); } } //#if DO_IMPORT SharedLibrary.Database.Importer.ImportPenalties(penalties); manager.GetLogger().WriteVerbose($"Imported {penalties.Count} penalties"); //#endif } #endregion #region CHATHISTORY if (File.Exists("import_chathistory.csv")) { var chatHistory = new List <EFClientMessage>(); manager.GetLogger().WriteVerbose("Beginning import of existing messages"); foreach (string line in File.ReadAllLines("import_chathistory.csv").Skip(1)) { string comma = Regex.Match(line, "\".*,.*\"").Value.Replace(",", ""); string[] fields = Regex.Replace(line, "\".*,.*\"", comma).Split(','); fields.All(f => { f = f.StripColors().Trim(); return(true); }); if (fields.Length != 4) { manager.GetLogger().WriteError("Invalid chat history import file... aborting import"); return; } try { int cId = Convert.ToInt32(fields[0]); var linkedClient = oldClients[cId]; var newcl = cls.FirstOrDefault(c => c.NetworkId == linkedClient.NetworkId); if (newcl == null) { newcl = cls.FirstOrDefault(c => c.Name == linkedClient.Name && c.IPAddress == linkedClient.IPAddress); } int newCId = newcl.ClientId; var chatMessage = new EFClientMessage() { Active = true, ClientId = newCId, Message = fields[1], TimeSent = DateTime.Parse(fields[3]), ServerId = Math.Abs($"127.0.0.1:{Convert.ToInt32(fields[2]).ToString()}".GetHashCode()) }; chatHistory.Add(chatMessage); } catch (Exception e) { manager.GetLogger().WriteVerbose($"Could not import chatmessage with line {line}"); } } manager.GetLogger().WriteVerbose($"Read {chatHistory.Count} messages for import"); SharedLibrary.Database.Importer.ImportSQLite(chatHistory); } #endregion #region STATS foreach (string file in Directory.GetFiles(Environment.CurrentDirectory)) { if (Regex.Match(file, @"import_stats_[0-9]+.csv").Success) { int port = Int32.Parse(Regex.Match(file, "[0-9]{5}").Value); var stats = new List <EFClientStatistics>(); manager.GetLogger().WriteVerbose("Beginning import of existing client stats"); var lines = File.ReadAllLines(file).Skip(1); foreach (string line in lines) { string[] fields = line.Split(','); if (fields.Length != 9) { manager.GetLogger().WriteError("Invalid client import file... aborting import"); return; } try { if (fields[0].Substring(0, 5) == "01100") { continue; } long id = fields[0].ConvertLong(); var client = cls.Single(c => c.NetworkId == id); var time = Convert.ToInt32(fields[8]); double spm = time < 60 ? 0 : Math.Round(Convert.ToInt32(fields[1]) * 100.0 / time, 3); if (spm > 1000) { spm = 0; } var st = new EFClientStatistics() { Active = true, ClientId = client.ClientId, ServerId = Math.Abs($"127.0.0.1:{port}".GetHashCode()), Kills = Convert.ToInt32(fields[1]), Deaths = Convert.ToInt32(fields[2]), SPM = spm, Skill = 0, TimePlayed = time * 60 }; // client.TotalConnectionTime += time; stats.Add(st); stats = stats.AsEnumerable() .GroupBy(c => new { c.ClientId }) .Select(c => c.FirstOrDefault()).ToList(); var cl = await manager.GetClientService().Get(st.ClientId); cl.TotalConnectionTime += time * 60; await manager.GetClientService().Update(cl); } catch (Exception e) { continue; } } manager.GetLogger().WriteVerbose($"Read {stats.Count} clients stats for import"); try { SharedLibrary.Database.Importer.ImportSQLite(stats); } catch (Exception e) { manager.GetLogger().WriteError("Saving imported stats failed"); } } } #endregion }