using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using System.Reflection; using SharedLibraryCore; using SharedLibraryCore.Configuration; using SharedLibraryCore.Dtos; using SharedLibraryCore.Helpers; using SharedLibraryCore.Interfaces; using SharedLibraryCore.Services; using IW4MAdmin.Plugins.Stats.Config; using IW4MAdmin.Plugins.Stats.Helpers; using IW4MAdmin.Plugins.Stats.Models; namespace IW4MAdmin.Plugins.Stats { class Plugin : IPlugin { public string Name => "Simple Stats"; public float Version => Assembly.GetExecutingAssembly().GetName().Version.Major + Assembly.GetExecutingAssembly().GetName().Version.Minor / 10.0f; public string Author => "RaidMax"; public static StatManager Manager { get; private set; } private IManager ServerManager; public static BaseConfigurationHandler Config { get; private set; } public async Task OnEventAsync(GameEvent E, Server S) { switch (E.Type) { case GameEvent.EventType.Start: Manager.AddServer(S); break; case GameEvent.EventType.Stop: break; case GameEvent.EventType.Connect: await Manager.AddPlayer(E.Origin); break; case GameEvent.EventType.Disconnect: await Manager.RemovePlayer(E.Origin); break; case GameEvent.EventType.Say: if (E.Data != string.Empty && E.Data.Trim().Length > 0 && E.Message.Trim()[0] != '!' && E.Origin.ClientId > 1) await Manager.AddMessageAsync(E.Origin.ClientId, E.Owner.GetHashCode(), E.Data); break; case GameEvent.EventType.MapChange: Manager.ResetKillstreaks(S.GetHashCode()); await Manager.Sync(S); break; case GameEvent.EventType.MapEnd: break; case GameEvent.EventType.Broadcast: break; case GameEvent.EventType.Tell: break; case GameEvent.EventType.Kick: break; case GameEvent.EventType.Ban: break; case GameEvent.EventType.Remote: break; case GameEvent.EventType.Unknown: break; case GameEvent.EventType.Report: break; case GameEvent.EventType.Flag: break; case GameEvent.EventType.Script: break; case GameEvent.EventType.Kill: string[] killInfo = (E.Data != null) ? E.Data.Split(';') : new string[0]; if (killInfo.Length >= 9 && killInfo[0].Contains("ScriptKill") && E.Owner.CustomCallback) await Manager.AddScriptKill(E.Origin, E.Target, S.GetHashCode(), S.CurrentMap.Name, killInfo[7], killInfo[8], killInfo[5], killInfo[6], killInfo[3], killInfo[4], killInfo[9], killInfo[10], killInfo[11], killInfo[12]); else if (!E.Owner.CustomCallback) await Manager.AddStandardKill(E.Origin, E.Target); break; case GameEvent.EventType.Death: break; } } public async Task OnLoadAsync(IManager manager) { // load custom configuration Config = new BaseConfigurationHandler("StatsPluginSettings"); if (Config.Configuration() == null) { Config.Set((StatsConfiguration)new StatsConfiguration().Generate()); await Config.Save(); } // meta data info async Task> getStats(int clientId) { var statsSvc = new GenericRepository(); 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() { 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> getAnticheatInfo(int clientId) { var statsSvc = new GenericRepository(); 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() { 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> getMessages(int clientId) { var messageSvc = new GenericRepository(); 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(); return serverStats.Find(s => s.Active) .Sum(c => c.TotalKills).ToString("#,##0"); } string totalPlayTime() { var serverStats = new GenericRepository(); 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); } public Task OnTickAsync(Server S) => Task.CompletedTask; public async Task OnUnloadAsync() { foreach (var sv in ServerManager.GetServers()) await Manager.Sync(sv); } } }