From 4d585e6ab24a64fbd107c06c4367c1ce82a03971 Mon Sep 17 00:00:00 2001 From: RaidMax Date: Thu, 17 May 2018 18:31:58 -0500 Subject: [PATCH] set default elo rating maybe fix deadlock again :c changed "skill" to Performance (Skill + Elo / 2) --- Application/Application.csproj | 4 +- Application/Manager.cs | 14 +- Application/RconParsers/IW4RConParser.cs | 2 +- Plugins/Stats/Cheat/Detection.cs | 14 +- Plugins/Stats/Commands/ResetStats.cs | 2 + Plugins/Stats/Commands/TopStats.cs | 7 +- Plugins/Stats/Commands/ViewStats.cs | 8 +- Plugins/Stats/Helpers/StatManager.cs | 17 +- Plugins/Stats/Models/EFClientStatistics.cs | 8 + Plugins/Stats/Plugin.cs | 10 +- .../20180517223349_AddRollingKDR.Designer.cs | 438 ++++++++++++++++++ .../20180517223349_AddRollingKDR.cs | 25 + .../DatabaseContextModelSnapshot.cs | 2 + 13 files changed, 517 insertions(+), 34 deletions(-) create mode 100644 SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.Designer.cs create mode 100644 SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.cs diff --git a/Application/Application.csproj b/Application/Application.csproj index 960042f2..370817d2 100644 --- a/Application/Application.csproj +++ b/Application/Application.csproj @@ -27,9 +27,9 @@ - + diff --git a/Application/Manager.cs b/Application/Manager.cs index 26ded3da..894fbfee 100644 --- a/Application/Manager.cs +++ b/Application/Manager.cs @@ -332,7 +332,7 @@ namespace IW4MAdmin.Application #endregion } - private void SendHeartbeat(object state) + private async Task SendHeartbeat(object state) { var heartbeatState = (HeartbeatState)state; @@ -342,7 +342,7 @@ namespace IW4MAdmin.Application { try { - Heartbeat.Send(this, true).Wait(5000); + await Heartbeat.Send(this, true); heartbeatState.Connected = true; } @@ -357,7 +357,7 @@ namespace IW4MAdmin.Application { try { - Heartbeat.Send(this).Wait(5000); + await Heartbeat.Send(this); } catch (System.Net.Http.HttpRequestException e) @@ -393,7 +393,7 @@ namespace IW4MAdmin.Application } } - Task.Delay(30000).Wait(); + await Task.Delay(30000); } } @@ -447,16 +447,16 @@ namespace IW4MAdmin.Application while (Running) { // wait for new event to be added - OnEvent.Wait(5000); + OnEvent.Wait(); // todo: sequencially or parallelize? while ((queuedEvent = Handler.GetNextEvent()) != null) { - eventList.Add(processEvent(queuedEvent)); + await processEvent(queuedEvent); } // this should allow parallel processing of events - await Task.WhenAll(eventList); + // await Task.WhenAll(eventList); // signal that all events have been processed OnEvent.Reset(); diff --git a/Application/RconParsers/IW4RConParser.cs b/Application/RconParsers/IW4RConParser.cs index 5791449c..028316b0 100644 --- a/Application/RconParsers/IW4RConParser.cs +++ b/Application/RconParsers/IW4RConParser.cs @@ -127,7 +127,7 @@ namespace Application.RconParsers } // this happens if status is requested while map is rotating - if (Status[1] == "Rotating map...") + if (Status[1] == "Server Initialization") { throw new ServerException("Server is rotating map"); } diff --git a/Plugins/Stats/Cheat/Detection.cs b/Plugins/Stats/Cheat/Detection.cs index 96f7e5a2..aebc15d3 100644 --- a/Plugins/Stats/Cheat/Detection.cs +++ b/Plugins/Stats/Cheat/Detection.cs @@ -126,7 +126,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat #endif } double currentStrain = Strain.GetStrain(isDamage, kill.Damage, kill.ViewAngles, Math.Max(50, kill.TimeOffset - LastOffset)); - currentStrain *= ClientStats.SPM / 179.0; + double currentWeightedStrain = (currentStrain * ClientStats.SPM) / 170.0; LastOffset = kill.TimeOffset; if (currentStrain > ClientStats.MaxStrain) @@ -134,7 +134,7 @@ namespace IW4MAdmin.Plugins.Stats.Cheat ClientStats.MaxStrain = currentStrain; } - if (currentStrain > Thresholds.MaxStrainFlag) + if (currentWeightedStrain > Thresholds.MaxStrainFlag) { Tracker.OnChange(Strain); @@ -151,25 +151,25 @@ namespace IW4MAdmin.Plugins.Stats.Cheat } // flag - if (currentStrain > Thresholds.MaxStrainFlag) + if (currentWeightedStrain > Thresholds.MaxStrainFlag) { return new DetectionPenaltyResult() { ClientPenalty = Penalty.PenaltyType.Flag, - Value = currentStrain, + Value = currentWeightedStrain, HitCount = HitCount, Type = DetectionType.Strain }; } // ban - if (currentStrain > Thresholds.MaxStrainBan + if (currentWeightedStrain > Thresholds.MaxStrainBan && Kills > Thresholds.LowSampleMinKills) { return new DetectionPenaltyResult() { - ClientPenalty = Penalty.PenaltyType.Flag, - Value = currentStrain, + ClientPenalty = Penalty.PenaltyType.Ban, + Value = currentWeightedStrain, HitCount = HitCount, Type = DetectionType.Strain }; diff --git a/Plugins/Stats/Commands/ResetStats.cs b/Plugins/Stats/Commands/ResetStats.cs index 8135ffc6..ce3e142d 100644 --- a/Plugins/Stats/Commands/ResetStats.cs +++ b/Plugins/Stats/Commands/ResetStats.cs @@ -26,6 +26,8 @@ namespace IW4MAdmin.Plugins.Stats.Commands stats.SPM = 0.0; stats.Skill = 0.0; stats.TimePlayed = 0; + // todo: make this more dynamic + stats.EloRating = 200.0; // reset the cached version Plugin.Manager.ResetStats(E.Origin.ClientId, E.Owner.GetHashCode()); diff --git a/Plugins/Stats/Commands/TopStats.cs b/Plugins/Stats/Commands/TopStats.cs index 719866a6..78582065 100644 --- a/Plugins/Stats/Commands/TopStats.cs +++ b/Plugins/Stats/Commands/TopStats.cs @@ -39,18 +39,17 @@ namespace IW4MAdmin.Plugins.Stats.Commands where stats.TimePlayed >= 3600 where client.Level != Player.Permission.Banned where client.LastConnection >= thirtyDaysAgo - orderby stats.Skill descending + orderby stats.Performance descending select new { stats.KDR, - stats.Skill, - stats.EloRating, + stats.Performance, alias.Name }) .Take(5); var statsList = (await iqStats.ToListAsync()) - .Select(stats => $"^3{stats.Name}^7 - ^5{stats.KDR} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"]} | ^5{stats.Skill} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_SKILL"]} | ^5{stats.EloRating} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_TOPSTATS_RATING"]}"); + .Select(stats => $"^3{stats.Name}^7 - ^5{stats.KDR} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_KDR"]} | ^5{stats.Performance} ^7{Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_PERFORMANCE"]}"); topStatsText.AddRange(statsList); } diff --git a/Plugins/Stats/Commands/ViewStats.cs b/Plugins/Stats/Commands/ViewStats.cs index 7a659ff2..8b37868a 100644 --- a/Plugins/Stats/Commands/ViewStats.cs +++ b/Plugins/Stats/Commands/ViewStats.cs @@ -26,7 +26,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands { var loc = Utilities.CurrentLocalization.LocalizationIndex; - if (E.Target?.ClientNumber < 0) + /*if (E.Target?.ClientNumber < 0) { await E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME"]); return; @@ -36,7 +36,7 @@ namespace IW4MAdmin.Plugins.Stats.Commands { await E.Origin.Tell(loc["PLUGINS_STATS_COMMANDS_VIEW_FAIL_INGAME_SELF"]); return; - } + }*/ String statLine; EFClientStatistics pStats; @@ -53,13 +53,13 @@ namespace IW4MAdmin.Plugins.Stats.Commands if (E.Target != null) { pStats = clientStats.Find(c => c.ServerId == serverId && c.ClientId == E.Target.ClientId).First(); - statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Skill} ^7{loc["PLUGINS_STATS_TEXT_SKILL"]} | ^5{pStats.EloRating} ^7{loc["PLUGINS_STATS_COMMANDS_TOPSTATS_RATING"].ToUpper()}"; + statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}"; } else { pStats = pStats = clientStats.Find(c => c.ServerId == serverId && c.ClientId == E.Origin.ClientId).First(); - statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Skill} ^7{loc["PLUGINS_STATS_TEXT_SKILL"]} | ^5{pStats.EloRating} ^7{loc["PLUGINS_STATS_COMMANDS_TOPSTATS_RATING"].ToUpper()}"; + statLine = $"^5{pStats.Kills} ^7{loc["PLUGINS_STATS_TEXT_KILLS"]} | ^5{pStats.Deaths} ^7{loc["PLUGINS_STATS_TEXT_DEATHS"]} | ^5{pStats.KDR} ^7KDR | ^5{pStats.Performance} ^7{loc["PLUGINS_STATS_COMMANDS_PERFORMANCE"].ToUpper()}"; } if (E.Message.IsBroadcastCommand()) diff --git a/Plugins/Stats/Helpers/StatManager.cs b/Plugins/Stats/Helpers/StatManager.cs index 11d3826a..cdc16a5d 100644 --- a/Plugins/Stats/Helpers/StatManager.cs +++ b/Plugins/Stats/Helpers/StatManager.cs @@ -146,11 +146,17 @@ namespace IW4MAdmin.Plugins.Stats.Helpers //await statsSvc.ClientStatSvc.SaveChangesAsync(); } + // for stats before rating if (clientStats.EloRating == 0.0) { clientStats.EloRating = clientStats.Skill; } + if (clientStats.RollingWeightedKDR == 0) + { + clientStats.RollingWeightedKDR = clientStats.KDR; + } + // set these on connecting clientStats.LastActive = DateTime.UtcNow; clientStats.LastStatCalculation = DateTime.UtcNow; @@ -497,10 +503,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers .Average(cs => cs.Value.EloRating); double attackerEloDifference = Math.Log(attackerLobbyRating) - Math.Log(attackerStats.EloRating); - double winPercentage = 1.0 / (1 + Math.Pow(10, attackerEloDifference / 3.0)); + double winPercentage = 1.0 / (1 + Math.Pow(10, attackerEloDifference / 0.5)); double victimEloDifference = Math.Log(victimLobbyRating) - Math.Log(victimStats.EloRating); - double lossPercentage = 1.0 / (1 + Math.Pow(10, victimEloDifference / 3.0)); + double lossPercentage = 1.0 / (1 + Math.Pow(10, victimEloDifference / 0.5)); attackerStats.EloRating += 24.0 * (1 - winPercentage); victimStats.EloRating -= 24.0 * winPercentage; @@ -551,8 +557,10 @@ namespace IW4MAdmin.Plugins.Stats.Helpers // 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); + double currentKDR = clientStats.SessionDeaths == 0 ? clientStats.SessionKills : clientStats.SessionKills / clientStats.SessionDeaths; + double alpha = Math.Sqrt(2) / Math.Min(600, clientStats.Kills + clientStats.Deaths); + clientStats.RollingWeightedKDR = (alpha * currentKDR) + (1.0 - alpha) * currentKDR; + double KDRWeight = Math.Round(Math.Pow(clientStats.RollingWeightedKDR, 1.637 / Math.E), 3); // calculate the weight of the new play time against last 10 hours of gameplay int totalPlayTime = (clientStats.TimePlayed == 0) ? @@ -632,6 +640,7 @@ namespace IW4MAdmin.Plugins.Stats.Helpers stats.SPM = 0; stats.Skill = 0; stats.TimePlayed = 0; + stats.EloRating = 200; } public async Task AddMessageAsync(int clientId, int serverId, string message) diff --git a/Plugins/Stats/Models/EFClientStatistics.cs b/Plugins/Stats/Models/EFClientStatistics.cs index 72d32cc8..158e279f 100644 --- a/Plugins/Stats/Models/EFClientStatistics.cs +++ b/Plugins/Stats/Models/EFClientStatistics.cs @@ -24,6 +24,12 @@ namespace IW4MAdmin.Plugins.Stats.Models public int Deaths { get; set; } public double EloRating { get; set; } public virtual ICollection HitLocations { get; set; } + public double RollingWeightedKDR { get; set; } + [NotMapped] + public double Performance + { + get => Math.Round((EloRating + Skill) / 2.0, 2); + } [NotMapped] public double KDR { @@ -57,6 +63,8 @@ namespace IW4MAdmin.Plugins.Stats.Models public int LastScore { get; set; } [NotMapped] public DateTime LastActive { get; set; } + [NotMapped] + public double MaxSessionStrain { get; set; } public void StartNewSession() { KillStreak = 0; diff --git a/Plugins/Stats/Plugin.cs b/Plugins/Stats/Plugin.cs index 44dc47ab..263983ee 100644 --- a/Plugins/Stats/Plugin.cs +++ b/Plugins/Stats/Plugin.cs @@ -114,9 +114,9 @@ namespace IW4MAdmin.Plugins.Stats int kills = clientStats.Sum(c => c.Kills); int deaths = clientStats.Sum(c => c.Deaths); double kdr = Math.Round(kills / (double)deaths, 2); - var validSkillValues = clientStats.Where(c => c.Skill > 0); - int skillPlayTime = validSkillValues.Sum(s => s.TimePlayed); - double skill = Math.Round(validSkillValues.Sum(c => c.Skill * c.TimePlayed / skillPlayTime), 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() @@ -138,8 +138,8 @@ namespace IW4MAdmin.Plugins.Stats }, new ProfileMeta() { - Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_TEXT_SKILL"], - Value = skill + Key = Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_STATS_COMMANDS_PERFORMANCE"], + Value = performance }, new ProfileMeta() { diff --git a/SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.Designer.cs b/SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.Designer.cs new file mode 100644 index 00000000..c2def3fd --- /dev/null +++ b/SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.Designer.cs @@ -0,0 +1,438 @@ +// +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage; +using Microsoft.EntityFrameworkCore.Storage.Internal; +using SharedLibraryCore.Database; +using SharedLibraryCore.Objects; +using System; + +namespace SharedLibraryCore.Migrations +{ + [DbContext(typeof(DatabaseContext))] + [Migration("20180517223349_AddRollingKDR")] + partial class AddRollingKDR + { + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "2.0.2-rtm-10011"); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => + { + b.Property("KillId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("AttackerId"); + + b.Property("Damage"); + + b.Property("DeathOriginVector3Id"); + + b.Property("DeathType"); + + b.Property("HitLoc"); + + b.Property("KillOriginVector3Id"); + + b.Property("Map"); + + b.Property("ServerId"); + + b.Property("VictimId"); + + b.Property("ViewAnglesVector3Id"); + + b.Property("Weapon"); + + b.Property("When"); + + b.HasKey("KillId"); + + b.HasIndex("AttackerId"); + + b.HasIndex("DeathOriginVector3Id"); + + b.HasIndex("KillOriginVector3Id"); + + b.HasIndex("ServerId"); + + b.HasIndex("VictimId"); + + b.HasIndex("ViewAnglesVector3Id"); + + b.ToTable("EFClientKills"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b => + { + b.Property("MessageId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ClientId"); + + b.Property("Message"); + + b.Property("ServerId"); + + b.Property("TimeSent"); + + b.HasKey("MessageId"); + + b.HasIndex("ClientId"); + + b.HasIndex("ServerId"); + + b.ToTable("EFClientMessages"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => + { + b.Property("ClientId"); + + b.Property("ServerId"); + + b.Property("Active"); + + b.Property("Deaths"); + + b.Property("EloRating"); + + b.Property("Kills"); + + b.Property("MaxStrain"); + + b.Property("RollingWeightedKDR"); + + b.Property("SPM"); + + b.Property("Skill"); + + b.Property("TimePlayed"); + + b.HasKey("ClientId", "ServerId"); + + b.HasIndex("ServerId"); + + b.ToTable("EFClientStatistics"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b => + { + b.Property("HitLocationCountId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ClientId") + .HasColumnName("EFClientStatistics_ClientId"); + + b.Property("HitCount"); + + b.Property("HitOffsetAverage"); + + b.Property("Location"); + + b.Property("MaxAngleDistance"); + + b.Property("ServerId") + .HasColumnName("EFClientStatistics_ServerId"); + + b.HasKey("HitLocationCountId"); + + b.HasIndex("ServerId"); + + b.HasIndex("ClientId", "ServerId"); + + b.ToTable("EFHitLocationCounts"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b => + { + b.Property("ServerId"); + + b.Property("Active"); + + b.Property("Port"); + + b.HasKey("ServerId"); + + b.ToTable("EFServers"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => + { + b.Property("StatisticId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("ServerId"); + + b.Property("TotalKills"); + + b.Property("TotalPlayTime"); + + b.HasKey("StatisticId"); + + b.HasIndex("ServerId"); + + b.ToTable("EFServerStatistics"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b => + { + b.Property("AliasId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("DateAdded"); + + b.Property("IPAddress"); + + b.Property("LinkId"); + + b.Property("Name") + .IsRequired(); + + b.HasKey("AliasId"); + + b.HasIndex("LinkId"); + + b.ToTable("EFAlias"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b => + { + b.Property("AliasLinkId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.HasKey("AliasLinkId"); + + b.ToTable("EFAliasLinks"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b => + { + b.Property("ClientId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("AliasLinkId"); + + b.Property("Connections"); + + b.Property("CurrentAliasId"); + + b.Property("FirstConnection"); + + b.Property("LastConnection"); + + b.Property("Level"); + + b.Property("Masked"); + + b.Property("NetworkId"); + + b.Property("Password"); + + b.Property("PasswordSalt"); + + b.Property("TotalConnectionTime"); + + b.HasKey("ClientId"); + + b.HasIndex("AliasLinkId"); + + b.HasIndex("CurrentAliasId"); + + b.HasIndex("NetworkId") + .IsUnique(); + + b.ToTable("EFClients"); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b => + { + b.Property("PenaltyId") + .ValueGeneratedOnAdd(); + + b.Property("Active"); + + b.Property("Expires"); + + b.Property("LinkId"); + + b.Property("OffenderId"); + + b.Property("Offense") + .IsRequired(); + + b.Property("PunisherId"); + + b.Property("Type"); + + b.Property("When"); + + b.HasKey("PenaltyId"); + + b.HasIndex("LinkId"); + + b.HasIndex("OffenderId"); + + b.HasIndex("PunisherId"); + + b.ToTable("EFPenalties"); + }); + + modelBuilder.Entity("SharedLibraryCore.Helpers.Vector3", b => + { + b.Property("Vector3Id") + .ValueGeneratedOnAdd(); + + b.Property("X"); + + b.Property("Y"); + + b.Property("Z"); + + b.HasKey("Vector3Id"); + + b.ToTable("Vector3"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker") + .WithMany() + .HasForeignKey("AttackerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "DeathOrigin") + .WithMany() + .HasForeignKey("DeathOriginVector3Id"); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "KillOrigin") + .WithMany() + .HasForeignKey("KillOriginVector3Id"); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim") + .WithMany() + .HasForeignKey("VictimId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Helpers.Vector3", "ViewAngles") + .WithMany() + .HasForeignKey("ViewAnglesVector3Id"); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientMessage", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client") + .WithMany() + .HasForeignKey("ClientId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics") + .WithMany("HitLocations") + .HasForeignKey("ClientId", "ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b => + { + b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server") + .WithMany() + .HasForeignKey("ServerId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link") + .WithMany("Children") + .HasForeignKey("LinkId") + .OnDelete(DeleteBehavior.Restrict); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink") + .WithMany() + .HasForeignKey("AliasLinkId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias") + .WithMany() + .HasForeignKey("CurrentAliasId") + .OnDelete(DeleteBehavior.Cascade); + }); + + modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b => + { + b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link") + .WithMany("ReceivedPenalties") + .HasForeignKey("LinkId") + .OnDelete(DeleteBehavior.Cascade); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender") + .WithMany("ReceivedPenalties") + .HasForeignKey("OffenderId") + .OnDelete(DeleteBehavior.Restrict); + + b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher") + .WithMany("AdministeredPenalties") + .HasForeignKey("PunisherId") + .OnDelete(DeleteBehavior.Restrict); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.cs b/SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.cs new file mode 100644 index 00000000..8c3a6c81 --- /dev/null +++ b/SharedLibraryCore/Migrations/20180517223349_AddRollingKDR.cs @@ -0,0 +1,25 @@ +using Microsoft.EntityFrameworkCore.Migrations; +using System; +using System.Collections.Generic; + +namespace SharedLibraryCore.Migrations +{ + public partial class AddRollingKDR : Migration + { + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "RollingWeightedKDR", + table: "EFClientStatistics", + nullable: false, + defaultValue: 0.0); + } + + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "RollingWeightedKDR", + table: "EFClientStatistics"); + } + } +} diff --git a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs index 4007141c..2c3d30d2 100644 --- a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs +++ b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs @@ -108,6 +108,8 @@ namespace SharedLibraryCore.Migrations b.Property("MaxStrain"); + b.Property("RollingWeightedKDR"); + b.Property("SPM"); b.Property("Skill");