Пример #1
0
        public async Task OnEventAsync(GameEvent E, Server S)
        {
            if (E.Type == GameEvent.EventType.Join)
            {
                EFClient newPlayer = E.Origin;
                if (newPlayer.Level >= Permission.Trusted && !E.Origin.Masked)
                {
                    E.Owner.Broadcast(await ProcessAnnouncement(Config.Configuration().PrivilegedAnnouncementMessage, newPlayer));
                }

                newPlayer.Tell(await ProcessAnnouncement(Config.Configuration().UserWelcomeMessage, newPlayer));

                if (newPlayer.Level == Permission.Flagged)
                {
                    string penaltyReason;

                    using (var ctx = new DatabaseContext(disableTracking: true))
                    {
                        penaltyReason = await ctx.Penalties
                                        .Where(p => p.OffenderId == newPlayer.ClientId && p.Type == Penalty.PenaltyType.Flag)
                                        .OrderByDescending(p => p.When)
                                        .Select(p => p.AutomatedOffense ?? p.Offense)
                                        .FirstOrDefaultAsync();
                    }

                    E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penaltyReason}) has joined!");
                }
                else
                {
                    E.Owner.Broadcast(await ProcessAnnouncement(Config.Configuration().UserAnnouncementMessage, newPlayer));
                }
            }
        }
Пример #2
0
        public async Task OnLoadAsync(IManager manager)
        {
            AuthorizedClients = new ConcurrentDictionary <int, bool>();

            var cfg = new BaseConfigurationHandler <Configuration>("LoginPluginSettings");

            if (cfg.Configuration() == null)
            {
                cfg.Set((Configuration) new Configuration().Generate());
                await cfg.Save();
            }

            Config = cfg.Configuration();
        }
Пример #3
0
        public async Task OnLoadAsync(IManager manager)
        {
            var cfg = new BaseConfigurationHandler <Configuration>("AutomessageFeedPluginSettings");

            if (cfg.Configuration() == null)
            {
                cfg.Set((Configuration) new Configuration().Generate());
                await cfg.Save();
            }

            _configuration = cfg.Configuration();

            manager.GetMessageTokens().Add(new MessageToken("FEED", GetNextFeedItem));
        }
Пример #4
0
        public async Task OnEventAsync(GameEvent E, Server S)
        {
            HookSender hookSender = new DiscordAlertDotNet.HookSender(Config.Configuration().HookId, Config.Configuration().HookToken);

            if (E.Type == GameEvent.EventType.Connect)
            {
                Player p = E.Origin;

                if (p.Level >= Player.Permission.Trusted)
                {
                    await E.Owner.Broadcast(Announce($"Player ^1{p.Name} ^7announced in ^1D^7iscord!", p));
                }

                try
                {
                    await hookSender.Send(Config.Configuration().OnJoinedMessage.Replace("player", p.Name).Replace("svname", S.Hostname), Config.Configuration().BotName, null, false, null);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.StackTrace);
                }
            }

            if (E.Type == GameEvent.EventType.Disconnect)
            {
                Player p = E.Origin;
                if (p.Level >= Player.Permission.Trusted)
                {
                    await E.Owner.Broadcast(Announce($"Player ^1{p.Name} ^7announced in ^1D^7iscord!", p));
                }

                try
                {
                    await hookSender.Send(Config.Configuration().OnLeftMessage.Replace("player", p.Name).Replace("svname", S.Hostname), Config.Configuration().BotName, null, false, null);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.StackTrace);
                }
            }

            if (E.Type == GameEvent.EventType.Report)
            {
                await hookSender.Send($"**{E.Origin.Name}** has reported **{E.Target.Name}** for: {E.Data.Trim()}", E.Target.Name, E.Origin.Name);
            }
        }
Пример #5
0
 public async Task OnLoadAsync(IManager manager)
 {
     Config = new BaseConfigurationHandler <DiscordAlertCfg>("DiscordAlertCfg");
     if (Config.Configuration() == null)
     {
         Config.Set((DiscordAlertCfg) new DiscordAlertCfg().Generate());
         await Config.Save();
     }
 }
Пример #6
0
 public async Task OnLoadAsync(IManager manager)
 {
     // load custom configuration
     Config = new BaseConfigurationHandler <WelcomeConfiguration>("WelcomePluginSettings");
     if (Config.Configuration() == null)
     {
         Config.Set((WelcomeConfiguration) new WelcomeConfiguration().Generate());
         await Config.Save();
     }
 }
Пример #7
0
        public async Task OnLoadAsync(IManager manager)
        {
            // load custom configuration
            Settings = new BaseConfigurationHandler <Configuration>("ProfanityDetermentSettings");
            if (Settings.Configuration() == null)
            {
                Settings.Set((Configuration) new Configuration().Generate());
                await Settings.Save();
            }

            ProfanityCounts = new ConcurrentDictionary <int, Tracking>();
            Manager         = manager;
        }
Пример #8
0
        public async Task OnEventAsync(GameEvent E, Server S)
        {
            if (E.Type == GameEvent.EventType.Connect)
            {
                Player newPlayer = E.Origin;
                if (newPlayer.Level >= Player.Permission.Trusted && !E.Origin.Masked)
                {
                    await E.Owner.Broadcast(ProcessAnnouncement(Config.Configuration().PrivilegedAnnouncementMessage, newPlayer));
                }

                await newPlayer.Tell(ProcessAnnouncement(Config.Configuration().UserWelcomeMessage, newPlayer));

                if (newPlayer.Level == Player.Permission.Flagged)
                {
                    var penalty = await new GenericRepository <EFPenalty>().FindAsync(p => p.OffenderId == newPlayer.ClientId && p.Type == Penalty.PenaltyType.Flag);
                    await E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penalty.FirstOrDefault()?.Offense}) has joined!");
                }
                else
                {
                    await E.Owner.Broadcast(ProcessAnnouncement(Config.Configuration().UserAnnouncementMessage, newPlayer));
                }
            }
        }
Пример #9
0
        public async Task OnEventAsync(GameEvent E, Server S)
        {
            if (!Settings.Configuration().EnableProfanityDeterment)
            {
                return;
            }

            if (E.Type == GameEvent.EventType.Connect)
            {
                if (!ProfanityCounts.TryAdd(E.Origin.ClientId, new Tracking(E.Origin)))
                {
                    S.Logger.WriteWarning("Could not add client to profanity tracking");
                }
            }

            if (E.Type == GameEvent.EventType.Disconnect)
            {
                if (!ProfanityCounts.TryRemove(E.Origin.ClientId, out Tracking old))
                {
                    S.Logger.WriteWarning("Could not remove client from profanity tracking");
                }
            }

            if (E.Type == GameEvent.EventType.Say)
            {
                var  objectionalWords        = Settings.Configuration().OffensiveWords;
                bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Data.ToLower().Contains(w)) != null;

                if (containsObjectionalWord)
                {
                    var clientProfanity = ProfanityCounts[E.Origin.ClientId];
                    if (clientProfanity.Infringements >= Settings.Configuration().KickAfterInfringementCount)
                    {
                        await clientProfanity.Client.Kick(Settings.Configuration().ProfanityKickMessage, new Player()
                        {
                            ClientId = 1
                        });
                    }

                    else if (clientProfanity.Infringements < Settings.Configuration().KickAfterInfringementCount)
                    {
                        clientProfanity.Infringements++;

                        await clientProfanity.Client.Warn(Settings.Configuration().ProfanityWarningMessage, new Player()
                        {
                            ClientId = 1
                        });
                    }
                }
            }
        }
Пример #10
0
        public async Task Init()
        {
            #region DATABASE
            var ipList = (await ClientSvc.Find(c => c.Level > Player.Permission.Trusted))
                         .Select(c => new
            {
                c.Password,
                c.PasswordSalt,
                c.ClientId,
                c.Level,
                c.Name
            });

            foreach (var a in ipList)
            {
                try
                {
                    PrivilegedClients.Add(a.ClientId, new Player()
                    {
                        Name         = a.Name,
                        ClientId     = a.ClientId,
                        Level        = a.Level,
                        PasswordSalt = a.PasswordSalt,
                        Password     = a.Password
                    });
                }

                catch (ArgumentException)
                {
                    continue;
                }
            }
            #endregion

            #region CONFIG
            var config = ConfigHandler.Configuration();

            // copy over default config if it doesn't exist
            if (config == null)
            {
                var defaultConfig = new BaseConfigurationHandler <DefaultConfiguration>("DefaultSettings").Configuration();
                ConfigHandler.Set((ApplicationConfiguration) new ApplicationConfiguration().Generate());
                var newConfig = ConfigHandler.Configuration();

                newConfig.AutoMessagePeriod = defaultConfig.AutoMessagePeriod;
                newConfig.AutoMessages      = defaultConfig.AutoMessages;
                newConfig.GlobalRules       = defaultConfig.GlobalRules;
                newConfig.Maps = defaultConfig.Maps;

                if (newConfig.Servers == null)
                {
                    ConfigHandler.Set(newConfig);
                    newConfig.Servers = new List <ServerConfiguration>();

                    do
                    {
                        newConfig.Servers.Add((ServerConfiguration) new ServerConfiguration().Generate());
                    } while (Utilities.PromptBool(Utilities.CurrentLocalization.LocalizationSet["SETUP_SERVER_SAVE"]));

                    config = newConfig;
                    await ConfigHandler.Save();
                }
            }

            else if (config != null)
            {
                if (string.IsNullOrEmpty(config.Id))
                {
                    config.Id = Guid.NewGuid().ToString();
                    await ConfigHandler.Save();
                }

                if (string.IsNullOrEmpty(config.WebfrontBindUrl))
                {
                    config.WebfrontBindUrl = "http://127.0.0.1:1624";
                    await ConfigHandler.Save();
                }
            }

            else if (config.Servers.Count == 0)
            {
                throw new ServerException("A server configuration in IW4MAdminSettings.json is invalid");
            }

            Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
            Utilities.EncodingType = Encoding.GetEncoding(!string.IsNullOrEmpty(config.CustomParserEncoding) ? config.CustomParserEncoding : "windows-1252");

            #endregion
            #region PLUGINS
            SharedLibraryCore.Plugins.PluginImporter.Load(this);

            foreach (var Plugin in SharedLibraryCore.Plugins.PluginImporter.ActivePlugins)
            {
                try
                {
                    await Plugin.OnLoadAsync(this);
                }

                catch (Exception e)
                {
                    Logger.WriteError($"An error occured loading plugin {Plugin.Name}");
                    Logger.WriteDebug($"Exception: {e.Message}");
                    Logger.WriteDebug($"Stack Trace: {e.StackTrace}");
                }
            }
            #endregion

            #region COMMANDS
            if (ClientSvc.GetOwners().Result.Count == 0)
            {
                Commands.Add(new COwner());
            }

            Commands.Add(new CQuit());
            Commands.Add(new CKick());
            Commands.Add(new CSay());
            Commands.Add(new CTempBan());
            Commands.Add(new CBan());
            Commands.Add(new CWhoAmI());
            Commands.Add(new CList());
            Commands.Add(new CHelp());
            Commands.Add(new CFastRestart());
            Commands.Add(new CMapRotate());
            Commands.Add(new CSetLevel());
            Commands.Add(new CUsage());
            Commands.Add(new CUptime());
            Commands.Add(new CWarn());
            Commands.Add(new CWarnClear());
            Commands.Add(new CUnban());
            Commands.Add(new CListAdmins());
            Commands.Add(new CLoadMap());
            Commands.Add(new CFindPlayer());
            Commands.Add(new CListRules());
            Commands.Add(new CPrivateMessage());
            Commands.Add(new CFlag());
            Commands.Add(new CReport());
            Commands.Add(new CListReports());
            Commands.Add(new CListBanInfo());
            Commands.Add(new CListAlias());
            Commands.Add(new CExecuteRCON());
            Commands.Add(new CPlugins());
            Commands.Add(new CIP());
            Commands.Add(new CMask());
            Commands.Add(new CPruneAdmins());
            Commands.Add(new CKillServer());
            Commands.Add(new CSetPassword());
            Commands.Add(new CPing());

            foreach (Command C in SharedLibraryCore.Plugins.PluginImporter.ActiveCommands)
            {
                Commands.Add(C);
            }
            #endregion

            #region INIT
            async Task Init(ServerConfiguration Conf)
            {
                try
                {
                    var ServerInstance = new IW4MServer(this, Conf);
                    await ServerInstance.Initialize();

                    lock (_servers)
                    {
                        _servers.Add(ServerInstance);
                    }

                    Logger.WriteVerbose($"Now monitoring {ServerInstance.Hostname}");

                    // this way we can keep track of execution time and see if problems arise.
                    var Status = new AsyncStatus(ServerInstance, UPDATE_FREQUENCY);
                    lock (TaskStatuses)
                    {
                        TaskStatuses.Add(Status);
                    }
                }

                catch (ServerException e)
                {
                    Logger.WriteError($"Not monitoring server {Conf.IPAddress}:{Conf.Port} due to uncorrectable errors");
                    if (e.GetType() == typeof(DvarException))
                    {
                        Logger.WriteDebug($"Could not get the dvar value for {(e as DvarException).Data["dvar_name"]} (ensure the server has a map loaded)");
                    }
                    else if (e.GetType() == typeof(NetworkException))
                    {
                        Logger.WriteDebug(e.Message);
                    }

                    // throw the exception to the main method to stop before instantly exiting
                    throw e;
                }
            }

            await Task.WhenAll(config.Servers.Select(c => Init(c)).ToArray());

            #endregion

            Running = true;
        }
Пример #11
0
        public async Task OnLoadAsync(IManager manager)
        {
            // load custom configuration
            Config = new BaseConfigurationHandler <StatsConfiguration>("StatsPluginSettings");
            if (Config.Configuration() == null)
            {
                Config.Set((StatsConfiguration) new StatsConfiguration().Generate());
                await Config.Save();
            }

            // meta data info
            async Task <List <ProfileMeta> > getStats(int clientId)
            {
                var statsSvc    = new GenericRepository <EFClientStatistics>();
                var clientStats = await statsSvc.FindAsync(c => c.ClientId == clientId);

                int    kills  = clientStats.Sum(c => c.Kills);
                int    deaths = clientStats.Sum(c => c.Deaths);
                double kdr    = Math.Round(kills / (double)deaths, 2);
                double skill  = Math.Round(clientStats.Sum(c => c.Skill) / clientStats.Count, 2);
                double spm    = Math.Round(clientStats.Sum(c => c.SPM), 1);

                return(new List <ProfileMeta>()
                {
                    new ProfileMeta()
                    {
                        Key = "Kills",
                        Value = kills
                    },
                    new ProfileMeta()
                    {
                        Key = "Deaths",
                        Value = deaths
                    },
                    new ProfileMeta()
                    {
                        Key = "KDR",
                        Value = kdr
                    },
                    new ProfileMeta()
                    {
                        Key = "Skill",
                        Value = skill
                    },
                    new ProfileMeta()
                    {
                        Key = "Score Per Minute",
                        Value = spm
                    }
                });
            }

            async Task <List <ProfileMeta> > getAnticheatInfo(int clientId)
            {
                var statsSvc    = new GenericRepository <EFClientStatistics>();
                var clientStats = await statsSvc.FindAsync(c => c.ClientId == clientId);

                double headRatio         = 0;
                double chestRatio        = 0;
                double abdomenRatio      = 0;
                double chestAbdomenRatio = 0;
                double hitOffsetAverage  = 0;

                if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
                {
                    chestRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
                                                                                                 c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
                                            (double)clientStats.Where(c => c.HitLocations.Count > 0)
                                            .Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount)), 2);

                    abdomenRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
                                                                                                   c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount) /
                                              (double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount)), 2);

                    chestAbdomenRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
                                                   (double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount), 2);

                    headRatio = Math.Round(clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.head).HitCount) /
                                           (double)clientStats.Where(c => c.HitLocations.Count > 0)
                                           .Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount)), 2);

                    hitOffsetAverage = clientStats.Sum(c => c.AverageHitOffset) / Math.Max(1, clientStats.Where(c => c.AverageHitOffset > 0).Count());
                }

                return(new List <ProfileMeta>()
                {
                    new ProfileMeta()
                    {
                        Key = "Chest Ratio",
                        Value = chestRatio,
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = "Abdomen Ratio",
                        Value = abdomenRatio,
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = "Chest To Abdomen Ratio",
                        Value = chestAbdomenRatio,
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = "Headshot Ratio",
                        Value = headRatio,
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = "Hit Offset Average",
                        Value = $"{Math.Round(((float)hitOffsetAverage).ToDegrees(), 4)}°",
                        Sensitive = true
                    }
                });
            }

            async Task <List <ProfileMeta> > getMessages(int clientId)
            {
                var messageSvc = new GenericRepository <EFClientMessage>();
                var messages   = await messageSvc.FindAsync(m => m.ClientId == clientId);

                var messageMeta = messages.Select(m => new ProfileMeta()
                {
                    Key   = "EventMessage",
                    Value = m.Message,
                    When  = m.TimeSent
                }).ToList();

                messageMeta.Add(new ProfileMeta()
                {
                    Key   = "Messages",
                    Value = messages.Count
                });

                return(messageMeta);
            }

            MetaService.AddMeta(getStats);

            if (Config.Configuration().EnableAntiCheat)
            {
                MetaService.AddMeta(getAnticheatInfo);
            }

            MetaService.AddMeta(getMessages);

            string totalKills()
            {
                var serverStats = new GenericRepository <EFServerStatistics>();

                return(serverStats.Find(s => s.Active)
                       .Sum(c => c.TotalKills).ToString("#,##0"));
            }

            string totalPlayTime()
            {
                var serverStats = new GenericRepository <EFServerStatistics>();

                return(Math.Ceiling((serverStats.GetQuery(s => s.Active)
                                     .Sum(c => c.TotalPlayTime) / 3600.0)).ToString("#,##0"));
            }

            manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", totalKills));
            manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", totalPlayTime));

            ServerManager = manager;

            Manager = new StatManager(manager);
        }
Пример #12
0
        public async Task OnLoadAsync(IManager manager)
        {
            // load custom configuration
            Config = new BaseConfigurationHandler <StatsConfiguration>("StatsPluginSettings");
            if (Config.Configuration() == null)
            {
                Config.Set((StatsConfiguration) new StatsConfiguration().Generate());
                await Config.Save();
            }

            // register the topstats page
            // todo:generate the URL/Location instead of hardcoding
            manager.GetPageList()
            .Pages.Add(
                Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_TOP_TEXT"],
                "/Stats/TopPlayersAsync");

            // meta data info
            async Task <List <ProfileMeta> > getStats(int clientId, int offset, int count, DateTime?startAt)
            {
                if (count > 1)
                {
                    return(new List <ProfileMeta>());
                }

                IList <EFClientStatistics> clientStats;

                using (var ctx = new DatabaseContext(disableTracking: true))
                {
                    clientStats = await ctx.Set <EFClientStatistics>().Where(c => c.ClientId == clientId).ToListAsync();
                }

                int    kills  = clientStats.Sum(c => c.Kills);
                int    deaths = clientStats.Sum(c => c.Deaths);
                double kdr    = Math.Round(kills / (double)deaths, 2);
                var    validPerformanceValues = clientStats.Where(c => c.Performance > 0);
                int    performancePlayTime    = validPerformanceValues.Sum(s => s.TimePlayed);
                double performance            = Math.Round(validPerformanceValues.Sum(c => c.Performance * c.TimePlayed / performancePlayTime), 2);
                double spm = Math.Round(clientStats.Sum(c => c.SPM) / clientStats.Where(c => c.SPM > 0).Count(), 1);

                return(new List <ProfileMeta>()
                {
                    new ProfileMeta()
                    {
                        Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_RANKING"],
                        Value = "#" + (await StatManager.GetClientOverallRanking(clientId)).ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                        Column = 0,
                        Order = 0,
                        Type = ProfileMeta.MetaType.Information
                    },
                    new ProfileMeta()
                    {
                        Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KILLS"],
                        Value = kills.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                        Column = 0,
                        Order = 1,
                        Type = ProfileMeta.MetaType.Information
                    },
                    new ProfileMeta()
                    {
                        Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_DEATHS"],
                        Value = deaths.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                        Column = 0,
                        Order = 2,
                        Type = ProfileMeta.MetaType.Information
                    },
                    new ProfileMeta()
                    {
                        Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"],
                        Value = kdr.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                        Column = 0,
                        Order = 3,
                        Type = ProfileMeta.MetaType.Information
                    },
                    new ProfileMeta()
                    {
                        Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_PERFORMANCE"],
                        Value = performance.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                        Column = 0,
                        Order = 4,
                        Type = ProfileMeta.MetaType.Information
                    },
                    new ProfileMeta()
                    {
                        Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_META_SPM"],
                        Value = spm.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                        Column = 0,
                        Order = 5,
                        Type = ProfileMeta.MetaType.Information
                    }
                });
            }

            async Task <List <ProfileMeta> > getAnticheatInfo(int clientId, int offset, int count, DateTime?startAt)
            {
                if (count > 1)
                {
                    return(new List <ProfileMeta>());
                }

                IList <EFClientStatistics> clientStats;

                using (var ctx = new DatabaseContext(disableTracking: true))
                {
                    clientStats = await ctx.Set <EFClientStatistics>()
                                  .Include(c => c.HitLocations)
                                  .Where(c => c.ClientId == clientId)
                                  .ToListAsync();
                }

                double headRatio         = 0;
                double chestRatio        = 0;
                double abdomenRatio      = 0;
                double chestAbdomenRatio = 0;
                double hitOffsetAverage  = 0;
                double maxStrain         = clientStats.Count(c => c.MaxStrain > 0) == 0 ? 0 : clientStats.Max(cs => cs.MaxStrain);

                if (clientStats.Where(cs => cs.HitLocations.Count > 0).FirstOrDefault() != null)
                {
                    chestRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
                                                                                                  c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
                                             (double)clientStats.Where(c => c.HitLocations.Count > 0)
                                             .Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0);

                    abdomenRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(c =>
                                                                                                    c.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount) /
                                               (double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0);

                    chestAbdomenRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_upper).HitCount) /
                                                    (double)clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.torso_lower).HitCount)) * 100.0, 0);

                    headRatio = Math.Round((clientStats.Where(c => c.HitLocations.Count > 0).Sum(cs => cs.HitLocations.First(hl => hl.Location == IW4Info.HitLocation.head).HitCount) /
                                            (double)clientStats.Where(c => c.HitLocations.Count > 0)
                                            .Sum(c => c.HitLocations.Where(hl => hl.Location != IW4Info.HitLocation.none).Sum(f => f.HitCount))) * 100.0, 0);

                    var validOffsets = clientStats.Where(c => c.HitLocations.Count(hl => hl.HitCount > 0) > 0).SelectMany(hl => hl.HitLocations);
                    hitOffsetAverage = validOffsets.Sum(o => o.HitCount * o.HitOffsetAverage) / (double)validOffsets.Sum(o => o.HitCount);
                }

                return(new List <ProfileMeta>()
                {
                    new ProfileMeta()
                    {
                        Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 1",
                        Value = chestRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
                        Type = ProfileMeta.MetaType.Information,
                        Column = 2,
                        Order = 0,
                        Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM1"],
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 2",
                        Value = abdomenRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
                        Type = ProfileMeta.MetaType.Information,
                        Column = 2,
                        Order = 1,
                        Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM2"],
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 3",
                        Value = chestAbdomenRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
                        Type = ProfileMeta.MetaType.Information,
                        Column = 2,
                        Order = 2,
                        Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM3"],
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 4",
                        Value = headRatio.ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)) + '%',
                        Type = ProfileMeta.MetaType.Information,
                        Column = 2,
                        Order = 3,
                        Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM4"],
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 5",
                        // todo: make sure this is wrapped somewhere else
                        Value = $"{Math.Round(((float)hitOffsetAverage), 4).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName))}°",
                        Type = ProfileMeta.MetaType.Information,
                        Column = 2,
                        Order = 4,
                        Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM5"],
                        Sensitive = true
                    },
                    new ProfileMeta()
                    {
                        Key = $"{Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_META_AC_METRIC"]} 6",
                        Value = Math.Round(maxStrain, 3).ToString(new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                        Type = ProfileMeta.MetaType.Information,
                        Column = 2,
                        Order = 5,
                        Extra = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_CLIENT_TITLE_ACM6"],
                        Sensitive = true
                    },
                });
            }

            async Task <List <ProfileMeta> > getMessages(int clientId, int offset, int count, DateTime?startAt)
            {
                if (count <= 1)
                {
                    using (var ctx = new DatabaseContext(true))
                    {
                        return(new List <ProfileMeta>
                        {
                            new ProfileMeta()
                            {
                                Key = Utilities.CurrentLocalization.LocalizationIndex["WEBFRONT_PROFILE_MESSAGES"],
                                Value = (await ctx.Set <EFClientMessage>()
                                         .CountAsync(_message => _message.ClientId == clientId))
                                        .ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)),
                                Column = 1,
                                Order = 4,
                                Type = ProfileMeta.MetaType.Information
                            }
                        });
                    }
                }

                List <ProfileMeta> messageMeta;

                using (var ctx = new DatabaseContext(disableTracking: true))
                {
                    var messages = ctx.Set <EFClientMessage>()
                                   .Where(m => m.ClientId == clientId)
                                   .Where(_message => _message.TimeSent < startAt)
                                   .OrderByDescending(_message => _message.TimeSent)
                                   .Skip(offset)
                                   .Take(count);

                    messageMeta = await messages.Select(m => new ProfileMeta()
                    {
                        Key   = null,
                        Value = new { m.Message, m.Server.GameName },
                        When  = m.TimeSent,
                        Extra = m.ServerId.ToString(),
                        Type  = ProfileMeta.MetaType.ChatMessage
                    }).ToListAsync();

                    foreach (var message in messageMeta)
                    {
                        if ((message.Value.Message as string).IsQuickMessage())
                        {
                            try
                            {
                                var quickMessages = ServerManager.GetApplicationSettings().Configuration()
                                                    .QuickMessages
                                                    .First(_qm => _qm.Game == message.Value.GameName);
                                message.Value = quickMessages.Messages[(message.Value.Message as string).Substring(1)];
                                message.Type  = ProfileMeta.MetaType.QuickMessage;
                            }
                            catch
                            {
                                message.Value = message.Value.Message;
                            }
                        }

                        else
                        {
                            message.Value = message.Value.Message;
                        }
                    }
                }

                return(messageMeta);
            }

            if (Config.Configuration().EnableAntiCheat)
            {
                MetaService.AddRuntimeMeta(getAnticheatInfo);
            }

            MetaService.AddRuntimeMeta(getStats);
            MetaService.AddRuntimeMeta(getMessages);

            async Task <string> totalKills(Server server)
            {
                using (var ctx = new DatabaseContext(disableTracking: true))
                {
                    long kills = await ctx.Set <EFServerStatistics>().Where(s => s.Active).SumAsync(s => s.TotalKills);

                    return(kills.ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)));
                }
            }

            async Task <string> totalPlayTime(Server server)
            {
                using (var ctx = new DatabaseContext(disableTracking: true))
                {
                    long playTime = await ctx.Set <EFServerStatistics>().Where(s => s.Active).SumAsync(s => s.TotalPlayTime);

                    return((playTime / 3600.0).ToString("#,##0", new System.Globalization.CultureInfo(Utilities.CurrentLocalization.LocalizationName)));
                }
            }

            async Task <string> topStats(Server s)
            {
                return(string.Join(Environment.NewLine, await Commands.TopStats.GetTopStats(s)));
            }

            async Task <string> mostPlayed(Server s)
            {
                return(string.Join(Environment.NewLine, await Commands.MostPlayed.GetMostPlayed(s)));
            }

            manager.GetMessageTokens().Add(new MessageToken("TOTALKILLS", totalKills));
            manager.GetMessageTokens().Add(new MessageToken("TOTALPLAYTIME", totalPlayTime));
            manager.GetMessageTokens().Add(new MessageToken("TOPSTATS", topStats));
            manager.GetMessageTokens().Add(new MessageToken("MOSTPLAYED", mostPlayed));

            ServerManager = manager;
            Manager       = new StatManager(manager);
        }
Пример #13
0
        public async Task UpdateServerStates(CancellationToken token)
        {
            // store the server hash code and task for it
            var runningUpdateTasks = new Dictionary <long, Task>();

            while (Running)
            {
                // select the server ids that have completed the update task
                var serverTasksToRemove = runningUpdateTasks
                                          .Where(ut => ut.Value.Status == TaskStatus.RanToCompletion ||
                                                 ut.Value.Status == TaskStatus.Canceled ||
                                                 ut.Value.Status == TaskStatus.Faulted)
                                          .Select(ut => ut.Key)
                                          .ToList();

                // this is to prevent the log reader from starting before the initial
                // query of players on the server
                if (serverTasksToRemove.Count > 0)
                {
                    IsInitialized = true;
                }

                // remove the update tasks as they have completd
                foreach (long serverId in serverTasksToRemove)
                {
                    runningUpdateTasks.Remove(serverId);
                }

                // select the servers where the tasks have completed
                var serverIds = Servers.Select(s => s.EndPoint).Except(runningUpdateTasks.Select(r => r.Key)).ToList();
                foreach (var server in Servers.Where(s => serverIds.Contains(s.EndPoint)))
                {
                    runningUpdateTasks.Add(server.EndPoint, Task.Run(async() =>
                    {
                        try
                        {
                            await server.ProcessUpdatesAsync(token);
                            if (server.Throttled)
                            {
                                await Task.Delay((int)_throttleTimeout.TotalMilliseconds);
                            }
                        }

                        catch (Exception e)
                        {
                            Logger.WriteWarning($"Failed to update status for {server}");
                            Logger.WriteDebug(e.GetExceptionInfo());
                        }

                        finally
                        {
                            server.IsInitialized = true;
                        }
                    }));
                }
#if DEBUG
                Logger.WriteDebug($"{runningUpdateTasks.Count} servers queued for stats updates");
                ThreadPool.GetMaxThreads(out int workerThreads, out int n);
                ThreadPool.GetAvailableThreads(out int availableThreads, out int m);
                Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
#endif
                try
                {
                    await Task.Delay(ConfigHandler.Configuration().RConPollRate, token);
                }
                // if a cancellation is received, we want to return immediately
                catch { break; }
            }
        }
Пример #14
0
        public Task OnEventAsync(GameEvent E, Server S)
        {
            if (!Settings.Configuration().EnableProfanityDeterment)
            {
                return(Task.CompletedTask);
            }

            if (E.Type == GameEvent.EventType.Connect)
            {
                if (!ProfanityCounts.TryAdd(E.Origin.ClientId, new Tracking(E.Origin)))
                {
                    S.Logger.WriteWarning("Could not add client to profanity tracking");
                }

                var  objectionalWords        = Settings.Configuration().OffensiveWords;
                bool containsObjectionalWord = objectionalWords.FirstOrDefault(w => E.Origin.Name.ToLower().Contains(w)) != null;

                // we want to run regex against it just incase
                if (!containsObjectionalWord)
                {
                    foreach (string word in objectionalWords)
                    {
                        containsObjectionalWord |= Regex.IsMatch(E.Origin.Name.ToLower(), word, RegexOptions.IgnoreCase);
                    }
                }

                if (containsObjectionalWord)
                {
                    E.Origin.Kick(Settings.Configuration().ProfanityKickMessage, Utilities.IW4MAdminClient(E.Owner));
                }
                ;
            }

            if (E.Type == GameEvent.EventType.Disconnect)
            {
                if (!ProfanityCounts.TryRemove(E.Origin.ClientId, out Tracking old))
                {
                    S.Logger.WriteWarning("Could not remove client from profanity tracking");
                }
            }

            if (E.Type == GameEvent.EventType.Say)
            {
                var  objectionalWords        = Settings.Configuration().OffensiveWords;
                bool containsObjectionalWord = false;

                foreach (string word in objectionalWords)
                {
                    containsObjectionalWord |= Regex.IsMatch(E.Data.ToLower(), word, RegexOptions.IgnoreCase);

                    // break out early because there's at least one objectional word
                    if (containsObjectionalWord)
                    {
                        break;
                    }
                }

                if (containsObjectionalWord)
                {
                    var clientProfanity = ProfanityCounts[E.Origin.ClientId];
                    if (clientProfanity.Infringements >= Settings.Configuration().KickAfterInfringementCount)
                    {
                        clientProfanity.Client.Kick(Settings.Configuration().ProfanityKickMessage, Utilities.IW4MAdminClient(E.Owner));
                    }

                    else if (clientProfanity.Infringements < Settings.Configuration().KickAfterInfringementCount)
                    {
                        clientProfanity.Infringements++;

                        clientProfanity.Client.Warn(Settings.Configuration().ProfanityWarningMessage, Utilities.IW4MAdminClient(E.Owner));
                    }
                }
            }
            return(Task.CompletedTask);
        }
Пример #15
0
        /// <summary>
        /// Configures the dependency injection services
        /// </summary>
        private static IServiceCollection ConfigureServices(string[] args)
        {
            var appConfigHandler = new BaseConfigurationHandler <ApplicationConfiguration>("IW4MAdminSettings");
            var appConfig        = appConfigHandler.Configuration();
            var defaultLogger    = new Logger("IW4MAdmin-Manager");

            var masterUri      = Utilities.IsDevelopment ? new Uri("http://127.0.0.1:8080") : appConfig?.MasterUrl ?? new ApplicationConfiguration().MasterUrl;
            var apiClient      = RestClient.For <IMasterApi>(masterUri);
            var pluginImporter = new PluginImporter(defaultLogger, appConfig, apiClient, new RemoteAssemblyHandler(defaultLogger, appConfig));

            var serviceCollection = new ServiceCollection();

            serviceCollection.AddSingleton <IServiceCollection>(_serviceProvider => serviceCollection)
            .AddSingleton(appConfigHandler as IConfigurationHandler <ApplicationConfiguration>)
            .AddSingleton(new BaseConfigurationHandler <CommandConfiguration>("CommandConfiguration") as IConfigurationHandler <CommandConfiguration>)
            .AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService <IConfigurationHandler <ApplicationConfiguration> >().Configuration() ?? new ApplicationConfiguration())
            .AddSingleton(_serviceProvider => _serviceProvider.GetRequiredService <IConfigurationHandler <CommandConfiguration> >().Configuration() ?? new CommandConfiguration())
            .AddSingleton <ILogger>(_serviceProvider => defaultLogger)
            .AddSingleton <IPluginImporter, PluginImporter>()
            .AddSingleton <IMiddlewareActionHandler, MiddlewareActionHandler>()
            .AddSingleton <IRConConnectionFactory, RConConnectionFactory>()
            .AddSingleton <IGameServerInstanceFactory, GameServerInstanceFactory>()
            .AddSingleton <IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
            .AddSingleton <IParserRegexFactory, ParserRegexFactory>()
            .AddSingleton <IDatabaseContextFactory, DatabaseContextFactory>()
            .AddSingleton <IGameLogReaderFactory, GameLogReaderFactory>()
            .AddSingleton <IScriptCommandFactory, ScriptCommandFactory>()
            .AddSingleton <IAuditInformationRepository, AuditInformationRepository>()
            .AddSingleton <IEntityService <EFClient>, ClientService>()
            .AddSingleton <IMetaService, MetaService>()
            .AddSingleton <IMetaRegistration, MetaRegistration>()
            .AddSingleton <IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
            .AddSingleton <IResourceQueryHelper <ClientPaginationRequest, ReceivedPenaltyResponse>, ReceivedPenaltyResourceQueryHelper>()
            .AddSingleton <IResourceQueryHelper <ClientPaginationRequest, AdministeredPenaltyResponse>, AdministeredPenaltyResourceQueryHelper>()
            .AddSingleton <IResourceQueryHelper <ClientPaginationRequest, UpdatedAliasResponse>, UpdatedAliasResourceQueryHelper>()
            .AddSingleton <IResourceQueryHelper <ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>()
            .AddTransient <IParserPatternMatcher, ParserPatternMatcher>()
            .AddSingleton <IRemoteAssemblyHandler, RemoteAssemblyHandler>()
            .AddSingleton <IMasterCommunication, MasterCommunication>()
            .AddSingleton <IManager, ApplicationManager>()
            .AddSingleton(apiClient)
            .AddSingleton(_serviceProvider =>
            {
                var config = _serviceProvider.GetRequiredService <IConfigurationHandler <ApplicationConfiguration> >().Configuration();
                return(Localization.Configure.Initialize(useLocalTranslation: config?.UseLocalTranslations ?? false,
                                                         apiInstance: _serviceProvider.GetRequiredService <IMasterApi>(),
                                                         customLocale: config?.EnableCustomLocale ?? false ? (config.CustomLocale ?? "en-US") : "en-US"));
            });

            if (args.Contains("serialevents"))
            {
                serviceCollection.AddSingleton <IEventHandler, SerialGameEventHandler>();
            }
            else
            {
                serviceCollection.AddSingleton <IEventHandler, GameEventHandler>();
            }

            // register the native commands
            foreach (var commandType in typeof(SharedLibraryCore.Commands.QuitCommand).Assembly.GetTypes()
                     .Where(_command => _command.BaseType == typeof(Command)))
            {
                defaultLogger.WriteInfo($"Registered native command type {commandType.Name}");
                serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
            }

            // register the plugin implementations
            var pluginImplementations = pluginImporter.DiscoverAssemblyPluginImplementations();

            foreach (var pluginType in pluginImplementations.Item1)
            {
                defaultLogger.WriteInfo($"Registered plugin type {pluginType.FullName}");
                serviceCollection.AddSingleton(typeof(IPlugin), pluginType);
            }

            // register the plugin commands
            foreach (var commandType in pluginImplementations.Item2)
            {
                defaultLogger.WriteInfo($"Registered plugin command type {commandType.FullName}");
                serviceCollection.AddSingleton(typeof(IManagerCommand), commandType);
            }

            // register any script plugins
            foreach (var scriptPlugin in pluginImporter.DiscoverScriptPlugins())
            {
                serviceCollection.AddSingleton(scriptPlugin);
            }

            // register any eventable types
            foreach (var assemblyType in typeof(Program).Assembly.GetTypes()
                     .Where(_asmType => typeof(IRegisterEvent).IsAssignableFrom(_asmType))
                     .Union(pluginImplementations
                            .Item1.SelectMany(_asm => _asm.Assembly.GetTypes())
                            .Distinct()
                            .Where(_asmType => typeof(IRegisterEvent).IsAssignableFrom(_asmType))))
            {
                var instance = Activator.CreateInstance(assemblyType) as IRegisterEvent;
                serviceCollection.AddSingleton(instance);
            }

            return(serviceCollection);
        }
Пример #16
0
        /// <summary>
        /// Configures the dependency injection services
        /// </summary>
        private static IServiceCollection ConfigureServices(string[] args)
        {
            // setup the static resources (config/master api/translations)
            var serviceCollection    = new ServiceCollection();
            var appConfigHandler     = new BaseConfigurationHandler <ApplicationConfiguration>("IW4MAdminSettings");
            var defaultConfigHandler = new BaseConfigurationHandler <DefaultSettings>("DefaultSettings");
            var defaultConfig        = defaultConfigHandler.Configuration();
            var appConfig            = appConfigHandler.Configuration();
            var masterUri            = Utilities.IsDevelopment
                ? new Uri("http://127.0.0.1:8080")
                : appConfig?.MasterUrl ?? new ApplicationConfiguration().MasterUrl;
            var httpClient = new HttpClient
            {
                BaseAddress = masterUri,
                Timeout     = TimeSpan.FromSeconds(15)
            };
            var masterRestClient  = RestClient.For <IMasterApi>(httpClient);
            var translationLookup = Configure.Initialize(Utilities.DefaultLogger, masterRestClient, appConfig);

            if (appConfig == null)
            {
                appConfig = (ApplicationConfiguration) new ApplicationConfiguration().Generate();
                appConfigHandler.Set(appConfig);
                appConfigHandler.Save();
            }

            // register override level names
            foreach (var(key, value) in appConfig.OverridePermissionLevelNames)
            {
                if (!Utilities.PermissionLevelOverrides.ContainsKey(key))
                {
                    Utilities.PermissionLevelOverrides.Add(key, value);
                }
            }

            // build the dependency list
            HandlePluginRegistration(appConfig, serviceCollection, masterRestClient);

            serviceCollection
            .AddBaseLogger(appConfig)
            .AddSingleton(defaultConfig)
            .AddSingleton <IServiceCollection>(_serviceProvider => serviceCollection)
            .AddSingleton <IConfigurationHandler <DefaultSettings>, BaseConfigurationHandler <DefaultSettings> >()
            .AddSingleton((IConfigurationHandler <ApplicationConfiguration>)appConfigHandler)
            .AddSingleton(
                new BaseConfigurationHandler <CommandConfiguration>("CommandConfiguration") as
                IConfigurationHandler <CommandConfiguration>)
            .AddSingleton(appConfig)
            .AddSingleton(_serviceProvider =>
                          _serviceProvider.GetRequiredService <IConfigurationHandler <CommandConfiguration> >()
                          .Configuration() ?? new CommandConfiguration())
            .AddSingleton <IPluginImporter, PluginImporter>()
            .AddSingleton <IMiddlewareActionHandler, MiddlewareActionHandler>()
            .AddSingleton <IRConConnectionFactory, RConConnectionFactory>()
            .AddSingleton <IGameServerInstanceFactory, GameServerInstanceFactory>()
            .AddSingleton <IConfigurationHandlerFactory, ConfigurationHandlerFactory>()
            .AddSingleton <IParserRegexFactory, ParserRegexFactory>()
            .AddSingleton <IDatabaseContextFactory, DatabaseContextFactory>()
            .AddSingleton <IGameLogReaderFactory, GameLogReaderFactory>()
            .AddSingleton <IScriptCommandFactory, ScriptCommandFactory>()
            .AddSingleton <IAuditInformationRepository, AuditInformationRepository>()
            .AddSingleton <IEntityService <EFClient>, ClientService>()
            .AddSingleton <IMetaService, MetaService>()
            .AddSingleton <ClientService>()
            .AddSingleton <PenaltyService>()
            .AddSingleton <ChangeHistoryService>()
            .AddSingleton <IMetaRegistration, MetaRegistration>()
            .AddSingleton <IScriptPluginServiceResolver, ScriptPluginServiceResolver>()
            .AddSingleton <IResourceQueryHelper <ClientPaginationRequest, ReceivedPenaltyResponse>,
                           ReceivedPenaltyResourceQueryHelper>()
            .AddSingleton <IResourceQueryHelper <ClientPaginationRequest, AdministeredPenaltyResponse>,
                           AdministeredPenaltyResourceQueryHelper>()
            .AddSingleton <IResourceQueryHelper <ClientPaginationRequest, UpdatedAliasResponse>,
                           UpdatedAliasResourceQueryHelper>()
            .AddSingleton <IResourceQueryHelper <ChatSearchQuery, MessageResponse>, ChatResourceQueryHelper>()
            .AddSingleton <IResourceQueryHelper <ClientPaginationRequest, ConnectionHistoryResponse>, ConnectionsResourceQueryHelper>()
            .AddTransient <IParserPatternMatcher, ParserPatternMatcher>()
            .AddSingleton <IRemoteAssemblyHandler, RemoteAssemblyHandler>()
            .AddSingleton <IMasterCommunication, MasterCommunication>()
            .AddSingleton <IManager, ApplicationManager>()
            .AddSingleton <SharedLibraryCore.Interfaces.ILogger, Logger>()
            .AddSingleton <IClientNoticeMessageFormatter, ClientNoticeMessageFormatter>()
            .AddSingleton <IClientStatisticCalculator, HitCalculator>()
            .AddSingleton <IServerDistributionCalculator, ServerDistributionCalculator>()
            .AddSingleton <IWeaponNameParser, WeaponNameParser>()
            .AddSingleton <IHitInfoBuilder, HitInfoBuilder>()
            .AddSingleton(typeof(ILookupCache <>), typeof(LookupCache <>))
            .AddSingleton(typeof(IDataValueCache <,>), typeof(DataValueCache <,>))
            .AddSingleton <IServerDataViewer, ServerDataViewer>()
            .AddSingleton <IServerDataCollector, ServerDataCollector>()
            .AddSingleton <IEventPublisher, EventPublisher>()
            .AddSingleton(translationLookup)
            .AddDatabaseContextOptions(appConfig);

            if (args.Contains("serialevents"))
            {
                serviceCollection.AddSingleton <IEventHandler, SerialGameEventHandler>();
            }
            else
            {
                serviceCollection.AddSingleton <IEventHandler, GameEventHandler>();
            }

            serviceCollection.AddSource();

            return(serviceCollection);
        }