Example #1
0
        /// <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;
        }
Example #2
0
 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;
 }
Example #3
0
        /// <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);
        }
Example #4
0
        /// <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);
        }
Example #5
0
        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>();
        }
Example #6
0
        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();
        }
Example #7
0
        /// <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);
        }
Example #8
0
        /// <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);
        }
Example #9
0
        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();
        }
Example #10
0
        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
            });
        }
Example #11
0
        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);
            }
        }
Example #12
0
        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
        }