diff --git a/Application/IW4MServer.cs b/Application/IW4MServer.cs
index 6c9a5aef4..b9551a5be 100644
--- a/Application/IW4MServer.cs
+++ b/Application/IW4MServer.cs
@@ -1028,12 +1028,19 @@ namespace IW4MAdmin
{
var maxItems = Math.Ceiling(appConfig.MaxClientHistoryTime.TotalMinutes /
appConfig.ServerDataCollectionInterval.TotalMinutes);
- while ( ClientHistory.Count > maxItems)
+
+ while (ClientHistory.ClientCounts.Count > maxItems)
{
- ClientHistory.Dequeue();
+ ClientHistory.ClientCounts.RemoveAt(0);
}
- ClientHistory.Enqueue(new PlayerHistory(ClientNum));
+ ClientHistory.ClientCounts.Add(new ClientCountSnapshot
+ {
+ ClientCount = ClientNum,
+ ConnectionInterrupted = Throttled,
+ Time = DateTime.UtcNow,
+ Map = CurrentMap.Name
+ });
playerCountStart = DateTime.Now;
}
diff --git a/Application/Misc/ServerDataCollector.cs b/Application/Misc/ServerDataCollector.cs
index 46b93150e..ebe118982 100644
--- a/Application/Misc/ServerDataCollector.cs
+++ b/Application/Misc/ServerDataCollector.cs
@@ -94,7 +94,8 @@ namespace IW4MAdmin.Application.Misc
PeriodBlock = (int) (DateTimeOffset.UtcNow - DateTimeOffset.UnixEpoch).TotalMinutes,
ServerId = await server.GetIdForServer(),
MapId = await GetOrCreateMap(server.CurrentMap.Name, (Reference.Game) server.GameName, token),
- ClientCount = server.ClientNum
+ ClientCount = server.ClientNum,
+ ConnectionInterrupted = server.Throttled,
}));
return data;
@@ -144,4 +145,4 @@ namespace IW4MAdmin.Application.Misc
context.SaveChanges();
}
}
-}
\ No newline at end of file
+}
diff --git a/Application/Misc/ServerDataViewer.cs b/Application/Misc/ServerDataViewer.cs
index 5205cfbe1..395d745da 100644
--- a/Application/Misc/ServerDataViewer.cs
+++ b/Application/Misc/ServerDataViewer.cs
@@ -135,7 +135,9 @@ namespace IW4MAdmin.Application.Misc
{
snapshot.ServerId,
snapshot.CapturedAt,
- snapshot.ClientCount
+ snapshot.ClientCount,
+ snapshot.ConnectionInterrupted,
+ MapName = snapshot.Map.Name,
})
.OrderBy(snapshot => snapshot.CapturedAt)
.ToListAsync(cancellationToken);
@@ -143,8 +145,8 @@ namespace IW4MAdmin.Application.Misc
return history.GroupBy(snapshot => snapshot.ServerId).Select(byServer => new ClientHistoryInfo
{
ServerId = byServer.Key,
- ClientCounts = byServer.Select(snapshot => new ClientCountSnapshot()
- {Time = snapshot.CapturedAt, ClientCount = snapshot.ClientCount}).ToList()
+ ClientCounts = byServer.Select(snapshot => new ClientCountSnapshot
+ { Time = snapshot.CapturedAt, ClientCount = snapshot.ClientCount, ConnectionInterrupted = snapshot.ConnectionInterrupted ?? false, Map = snapshot.MapName}).ToList()
}).ToList();
}, nameof(_clientHistoryCache), TimeSpan.MaxValue);
@@ -159,4 +161,4 @@ namespace IW4MAdmin.Application.Misc
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Data/Migrations/MySql/20220329213440_AddConnectionInterruptedToEFServerSnapshot.Designer.cs b/Data/Migrations/MySql/20220329213440_AddConnectionInterruptedToEFServerSnapshot.Designer.cs
new file mode 100644
index 000000000..183513019
--- /dev/null
+++ b/Data/Migrations/MySql/20220329213440_AddConnectionInterruptedToEFServerSnapshot.Designer.cs
@@ -0,0 +1,1626 @@
+//
+using System;
+using Data.MigrationContext;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+#nullable disable
+
+namespace Data.Migrations.MySql
+{
+ [DbContext(typeof(MySqlDatabaseContext))]
+ [Migration("20220329213440_AddConnectionInterruptedToEFServerSnapshot")]
+ partial class AddConnectionInterruptedToEFServerSnapshot
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "6.0.1")
+ .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+ modelBuilder.Entity("Data.Models.Client.EFACSnapshotVector3", b =>
+ {
+ b.Property("ACSnapshotVector3Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("SnapshotId")
+ .HasColumnType("int");
+
+ b.Property("Vector3Id")
+ .HasColumnType("int");
+
+ b.HasKey("ACSnapshotVector3Id");
+
+ b.HasIndex("SnapshotId");
+
+ b.HasIndex("Vector3Id");
+
+ b.ToTable("EFACSnapshotVector3", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClient", b =>
+ {
+ b.Property("ClientId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AliasLinkId")
+ .HasColumnType("int");
+
+ b.Property("Connections")
+ .HasColumnType("int");
+
+ b.Property("CurrentAliasId")
+ .HasColumnType("int");
+
+ b.Property("FirstConnection")
+ .HasColumnType("datetime(6)");
+
+ b.Property("LastConnection")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Level")
+ .HasColumnType("int");
+
+ b.Property("Masked")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("NetworkId")
+ .HasColumnType("bigint");
+
+ b.Property("Password")
+ .HasColumnType("longtext");
+
+ b.Property("PasswordSalt")
+ .HasColumnType("longtext");
+
+ b.Property("TotalConnectionTime")
+ .HasColumnType("int");
+
+ b.HasKey("ClientId");
+
+ b.HasIndex("AliasLinkId");
+
+ b.HasIndex("CurrentAliasId");
+
+ b.HasIndex("NetworkId")
+ .IsUnique();
+
+ b.ToTable("EFClients", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClientConnectionHistory", b =>
+ {
+ b.Property("ClientConnectionId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.Property("ConnectionType")
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("ClientConnectionId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("CreatedDateTime");
+
+ b.HasIndex("ServerId");
+
+ b.ToTable("EFClientConnectionHistory", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClientKill", b =>
+ {
+ b.Property("KillId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AttackerId")
+ .HasColumnType("int");
+
+ b.Property("Damage")
+ .HasColumnType("int");
+
+ b.Property("DeathOriginVector3Id")
+ .HasColumnType("int");
+
+ b.Property("DeathType")
+ .HasColumnType("int");
+
+ b.Property("Fraction")
+ .HasColumnType("double");
+
+ b.Property("HitLoc")
+ .HasColumnType("int");
+
+ b.Property("IsKill")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("KillOriginVector3Id")
+ .HasColumnType("int");
+
+ b.Property("Map")
+ .HasColumnType("int");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("VictimId")
+ .HasColumnType("int");
+
+ b.Property("ViewAnglesVector3Id")
+ .HasColumnType("int");
+
+ b.Property("VisibilityPercentage")
+ .HasColumnType("double");
+
+ b.Property("Weapon")
+ .HasColumnType("int");
+
+ b.Property("WeaponReference")
+ .HasColumnType("longtext");
+
+ b.Property("When")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("KillId");
+
+ b.HasIndex("AttackerId");
+
+ b.HasIndex("DeathOriginVector3Id");
+
+ b.HasIndex("KillOriginVector3Id");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("VictimId");
+
+ b.HasIndex("ViewAnglesVector3Id");
+
+ b.ToTable("EFClientKills", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClientMessage", b =>
+ {
+ b.Property("MessageId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.Property("Message")
+ .HasColumnType("longtext");
+
+ b.Property("SentIngame")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("TimeSent")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("MessageId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("TimeSent");
+
+ b.ToTable("EFClientMessages", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFACSnapshot", b =>
+ {
+ b.Property("SnapshotId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.Property("CurrentSessionLength")
+ .HasColumnType("int");
+
+ b.Property("CurrentStrain")
+ .HasColumnType("double");
+
+ b.Property("CurrentViewAngleId")
+ .HasColumnType("int");
+
+ b.Property("Deaths")
+ .HasColumnType("int");
+
+ b.Property("Distance")
+ .HasColumnType("double");
+
+ b.Property("EloRating")
+ .HasColumnType("double");
+
+ b.Property("HitDestinationId")
+ .HasColumnType("int");
+
+ b.Property("HitLocation")
+ .HasColumnType("int");
+
+ b.Property("HitLocationReference")
+ .HasColumnType("longtext");
+
+ b.Property("HitOriginId")
+ .HasColumnType("int");
+
+ b.Property("HitType")
+ .HasColumnType("int");
+
+ b.Property("Hits")
+ .HasColumnType("int");
+
+ b.Property("Kills")
+ .HasColumnType("int");
+
+ b.Property("LastStrainAngleId")
+ .HasColumnType("int");
+
+ b.Property("RecoilOffset")
+ .HasColumnType("double");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("SessionAngleOffset")
+ .HasColumnType("double");
+
+ b.Property("SessionAverageSnapValue")
+ .HasColumnType("double");
+
+ b.Property("SessionSPM")
+ .HasColumnType("double");
+
+ b.Property("SessionScore")
+ .HasColumnType("int");
+
+ b.Property("SessionSnapHits")
+ .HasColumnType("int");
+
+ b.Property("StrainAngleBetween")
+ .HasColumnType("double");
+
+ b.Property("TimeSinceLastEvent")
+ .HasColumnType("int");
+
+ b.Property("WeaponId")
+ .HasColumnType("int");
+
+ b.Property("WeaponReference")
+ .HasColumnType("longtext");
+
+ b.Property("When")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("SnapshotId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("CurrentViewAngleId");
+
+ b.HasIndex("HitDestinationId");
+
+ b.HasIndex("HitOriginId");
+
+ b.HasIndex("LastStrainAngleId");
+
+ b.HasIndex("ServerId");
+
+ b.ToTable("EFACSnapshot", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientHitStatistic", b =>
+ {
+ b.Property("ClientHitStatisticId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("DamageInflicted")
+ .HasColumnType("int");
+
+ b.Property("DamageReceived")
+ .HasColumnType("int");
+
+ b.Property("DeathCount")
+ .HasColumnType("int");
+
+ b.Property("HitCount")
+ .HasColumnType("int");
+
+ b.Property("HitLocationId")
+ .HasColumnType("int");
+
+ b.Property("KillCount")
+ .HasColumnType("int");
+
+ b.Property("MeansOfDeathId")
+ .HasColumnType("int");
+
+ b.Property("ReceivedHitCount")
+ .HasColumnType("int");
+
+ b.Property("Score")
+ .HasColumnType("int");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("SuicideCount")
+ .HasColumnType("int");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("UsageSeconds")
+ .HasColumnType("int");
+
+ b.Property("WeaponAttachmentComboId")
+ .HasColumnType("int");
+
+ b.Property("WeaponId")
+ .HasColumnType("int");
+
+ b.HasKey("ClientHitStatisticId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("HitLocationId");
+
+ b.HasIndex("MeansOfDeathId");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("WeaponAttachmentComboId");
+
+ b.HasIndex("WeaponId");
+
+ b.ToTable("EFClientHitStatistics", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientRankingHistory", b =>
+ {
+ b.Property("ClientRankingHistoryId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Newest")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("PerformanceMetric")
+ .HasColumnType("double");
+
+ b.Property("Ranking")
+ .HasColumnType("int");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ZScore")
+ .HasColumnType("double");
+
+ b.HasKey("ClientRankingHistoryId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("Ranking");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("UpdatedDateTime");
+
+ b.HasIndex("ZScore");
+
+ b.ToTable("EFClientRankingHistory", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientRatingHistory", b =>
+ {
+ b.Property("RatingHistoryId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.HasKey("RatingHistoryId");
+
+ b.HasIndex("ClientId");
+
+ b.ToTable("EFClientRatingHistory", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientStatistics", b =>
+ {
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AverageSnapValue")
+ .HasColumnType("double");
+
+ b.Property("Deaths")
+ .HasColumnType("int");
+
+ b.Property("EloRating")
+ .HasColumnType("double");
+
+ b.Property("Kills")
+ .HasColumnType("int");
+
+ b.Property("MaxStrain")
+ .HasColumnType("double");
+
+ b.Property("RollingWeightedKDR")
+ .HasColumnType("double");
+
+ b.Property("SPM")
+ .HasColumnType("double");
+
+ b.Property("Skill")
+ .HasColumnType("double");
+
+ b.Property("SnapHitCount")
+ .HasColumnType("int");
+
+ b.Property("TimePlayed")
+ .HasColumnType("int");
+
+ b.Property("UpdatedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ZScore")
+ .HasColumnType("double");
+
+ b.HasKey("ClientId", "ServerId");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("ZScore");
+
+ b.HasIndex("ClientId", "TimePlayed", "ZScore");
+
+ b.ToTable("EFClientStatistics", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFHitLocationCount", b =>
+ {
+ b.Property("HitLocationCountId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("EFClientStatisticsClientId")
+ .HasColumnType("int")
+ .HasColumnName("EFClientStatisticsClientId");
+
+ b.Property("EFClientStatisticsServerId")
+ .HasColumnType("bigint")
+ .HasColumnName("EFClientStatisticsServerId");
+
+ b.Property("HitCount")
+ .HasColumnType("int");
+
+ b.Property("HitOffsetAverage")
+ .HasColumnType("float");
+
+ b.Property("Location")
+ .HasColumnType("int");
+
+ b.Property("MaxAngleDistance")
+ .HasColumnType("float");
+
+ b.HasKey("HitLocationCountId");
+
+ b.HasIndex("EFClientStatisticsServerId");
+
+ b.HasIndex("EFClientStatisticsClientId", "EFClientStatisticsServerId");
+
+ b.ToTable("EFHitLocationCounts", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFRating", b =>
+ {
+ b.Property("RatingId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ActivityAmount")
+ .HasColumnType("int");
+
+ b.Property("Newest")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Performance")
+ .HasColumnType("double");
+
+ b.Property("Ranking")
+ .HasColumnType("int");
+
+ b.Property("RatingHistoryId")
+ .HasColumnType("int");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("When")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("RatingId");
+
+ b.HasIndex("RatingHistoryId");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("Performance", "Ranking", "When");
+
+ b.HasIndex("When", "ServerId", "Performance", "ActivityAmount");
+
+ b.ToTable("EFRating", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.Reference.EFHitLocation", b =>
+ {
+ b.Property("HitLocationId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("HitLocationId");
+
+ b.HasIndex("Name");
+
+ b.ToTable("EFHitLocations", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.Reference.EFMap", b =>
+ {
+ b.Property("MapId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("MapId");
+
+ b.ToTable("EFMaps", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.Reference.EFMeansOfDeath", b =>
+ {
+ b.Property("MeansOfDeathId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("MeansOfDeathId");
+
+ b.ToTable("EFMeansOfDeath", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.Reference.EFWeapon", b =>
+ {
+ b.Property("WeaponId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("varchar(255)");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("WeaponId");
+
+ b.HasIndex("Name");
+
+ b.ToTable("EFWeapons", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.Reference.EFWeaponAttachment", b =>
+ {
+ b.Property("WeaponAttachmentId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("WeaponAttachmentId");
+
+ b.ToTable("EFWeaponAttachments", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.Reference.EFWeaponAttachmentCombo", b =>
+ {
+ b.Property("WeaponAttachmentComboId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Attachment1Id")
+ .HasColumnType("int");
+
+ b.Property("Attachment2Id")
+ .HasColumnType("int");
+
+ b.Property("Attachment3Id")
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Game")
+ .HasColumnType("int");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("WeaponAttachmentComboId");
+
+ b.HasIndex("Attachment1Id");
+
+ b.HasIndex("Attachment2Id");
+
+ b.HasIndex("Attachment3Id");
+
+ b.ToTable("EFWeaponAttachmentCombos", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.EFAlias", b =>
+ {
+ b.Property("AliasId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("DateAdded")
+ .HasColumnType("datetime(6)");
+
+ b.Property("IPAddress")
+ .HasColumnType("int");
+
+ b.Property("LinkId")
+ .HasColumnType("int");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasMaxLength(24)
+ .HasColumnType("varchar(24)");
+
+ b.Property("SearchableName")
+ .HasMaxLength(24)
+ .HasColumnType("varchar(24)");
+
+ b.HasKey("AliasId");
+
+ b.HasIndex("IPAddress");
+
+ b.HasIndex("LinkId");
+
+ b.HasIndex("Name");
+
+ b.HasIndex("SearchableName");
+
+ b.HasIndex("Name", "IPAddress");
+
+ b.ToTable("EFAlias", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.EFAliasLink", b =>
+ {
+ b.Property("AliasLinkId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.HasKey("AliasLinkId");
+
+ b.ToTable("EFAliasLinks", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.EFChangeHistory", b =>
+ {
+ b.Property("ChangeHistoryId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Comment")
+ .HasMaxLength(128)
+ .HasColumnType("varchar(128)");
+
+ b.Property("CurrentValue")
+ .HasColumnType("longtext");
+
+ b.Property("ImpersonationEntityId")
+ .HasColumnType("int");
+
+ b.Property("OriginEntityId")
+ .HasColumnType("int");
+
+ b.Property("PreviousValue")
+ .HasColumnType("longtext");
+
+ b.Property("TargetEntityId")
+ .HasColumnType("int");
+
+ b.Property("TimeChanged")
+ .HasColumnType("datetime(6)");
+
+ b.Property("TypeOfChange")
+ .HasColumnType("int");
+
+ b.HasKey("ChangeHistoryId");
+
+ b.ToTable("EFChangeHistory");
+ });
+
+ modelBuilder.Entity("Data.Models.EFMeta", b =>
+ {
+ b.Property("MetaId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ClientId")
+ .HasColumnType("int");
+
+ b.Property("Created")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Extra")
+ .HasColumnType("longtext");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasMaxLength(32)
+ .HasColumnType("varchar(32)");
+
+ b.Property("LinkedMetaId")
+ .HasColumnType("int");
+
+ b.Property("Updated")
+ .HasColumnType("datetime(6)");
+
+ b.Property("Value")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.HasKey("MetaId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("Key");
+
+ b.HasIndex("LinkedMetaId");
+
+ b.ToTable("EFMeta");
+ });
+
+ modelBuilder.Entity("Data.Models.EFPenalty", b =>
+ {
+ b.Property("PenaltyId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("AutomatedOffense")
+ .HasColumnType("longtext");
+
+ b.Property("Expires")
+ .HasColumnType("datetime(6)");
+
+ b.Property("IsEvadedOffense")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("LinkId")
+ .HasColumnType("int");
+
+ b.Property("OffenderId")
+ .HasColumnType("int");
+
+ b.Property("Offense")
+ .IsRequired()
+ .HasColumnType("longtext");
+
+ b.Property("PunisherId")
+ .HasColumnType("int");
+
+ b.Property("Type")
+ .HasColumnType("int");
+
+ b.Property("When")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("PenaltyId");
+
+ b.HasIndex("LinkId");
+
+ b.HasIndex("OffenderId");
+
+ b.HasIndex("PunisherId");
+
+ b.ToTable("EFPenalties", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.EFPenaltyIdentifier", b =>
+ {
+ b.Property("PenaltyIdentifierId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("IPv4Address")
+ .HasColumnType("int");
+
+ b.Property("NetworkId")
+ .HasColumnType("bigint");
+
+ b.Property("PenaltyId")
+ .HasColumnType("int");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("PenaltyIdentifierId");
+
+ b.HasIndex("IPv4Address");
+
+ b.HasIndex("NetworkId");
+
+ b.HasIndex("PenaltyId");
+
+ b.ToTable("EFPenaltyIdentifiers", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Misc.EFInboxMessage", b =>
+ {
+ b.Property("InboxMessageId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("CreatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.Property("DestinationClientId")
+ .HasColumnType("int");
+
+ b.Property("IsDelivered")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Message")
+ .HasColumnType("longtext");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("SourceClientId")
+ .HasColumnType("int");
+
+ b.Property("UpdatedDateTime")
+ .HasColumnType("datetime(6)");
+
+ b.HasKey("InboxMessageId");
+
+ b.HasIndex("DestinationClientId");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("SourceClientId");
+
+ b.ToTable("InboxMessages");
+ });
+
+ modelBuilder.Entity("Data.Models.Server.EFServer", b =>
+ {
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("EndPoint")
+ .HasColumnType("longtext");
+
+ b.Property("GameName")
+ .HasColumnType("int");
+
+ b.Property("HostName")
+ .HasColumnType("longtext");
+
+ b.Property("IsPasswordProtected")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("Port")
+ .HasColumnType("int");
+
+ b.HasKey("ServerId");
+
+ b.ToTable("EFServers", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Server.EFServerSnapshot", b =>
+ {
+ b.Property("ServerSnapshotId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("bigint");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("CapturedAt")
+ .HasColumnType("datetime(6)");
+
+ b.Property("ClientCount")
+ .HasColumnType("int");
+
+ b.Property("ConnectionInterrupted")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("MapId")
+ .HasColumnType("int");
+
+ b.Property("PeriodBlock")
+ .HasColumnType("int");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.HasKey("ServerSnapshotId");
+
+ b.HasIndex("MapId");
+
+ b.HasIndex("ServerId");
+
+ b.ToTable("EFServerSnapshot", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Server.EFServerStatistics", b =>
+ {
+ b.Property("StatisticId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("Active")
+ .HasColumnType("tinyint(1)");
+
+ b.Property("ServerId")
+ .HasColumnType("bigint");
+
+ b.Property("TotalKills")
+ .HasColumnType("bigint");
+
+ b.Property("TotalPlayTime")
+ .HasColumnType("bigint");
+
+ b.HasKey("StatisticId");
+
+ b.HasIndex("ServerId");
+
+ b.ToTable("EFServerStatistics", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Vector3", b =>
+ {
+ b.Property("Vector3Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("int");
+
+ b.Property("X")
+ .HasColumnType("float");
+
+ b.Property("Y")
+ .HasColumnType("float");
+
+ b.Property("Z")
+ .HasColumnType("float");
+
+ b.HasKey("Vector3Id");
+
+ b.ToTable("Vector3", (string)null);
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFACSnapshotVector3", b =>
+ {
+ b.HasOne("Data.Models.Client.Stats.EFACSnapshot", "Snapshot")
+ .WithMany("PredictedViewAngles")
+ .HasForeignKey("SnapshotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Vector3", "Vector")
+ .WithMany()
+ .HasForeignKey("Vector3Id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Snapshot");
+
+ b.Navigation("Vector");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClient", b =>
+ {
+ b.HasOne("Data.Models.EFAliasLink", "AliasLink")
+ .WithMany()
+ .HasForeignKey("AliasLinkId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.EFAlias", "CurrentAlias")
+ .WithMany()
+ .HasForeignKey("CurrentAliasId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("AliasLink");
+
+ b.Navigation("CurrentAlias");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClientConnectionHistory", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Client");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClientKill", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Attacker")
+ .WithMany()
+ .HasForeignKey("AttackerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Vector3", "DeathOrigin")
+ .WithMany()
+ .HasForeignKey("DeathOriginVector3Id");
+
+ b.HasOne("Data.Models.Vector3", "KillOrigin")
+ .WithMany()
+ .HasForeignKey("KillOriginVector3Id");
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Client.EFClient", "Victim")
+ .WithMany()
+ .HasForeignKey("VictimId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Vector3", "ViewAngles")
+ .WithMany()
+ .HasForeignKey("ViewAnglesVector3Id");
+
+ b.Navigation("Attacker");
+
+ b.Navigation("DeathOrigin");
+
+ b.Navigation("KillOrigin");
+
+ b.Navigation("Server");
+
+ b.Navigation("Victim");
+
+ b.Navigation("ViewAngles");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClientMessage", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Client");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFACSnapshot", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Vector3", "CurrentViewAngle")
+ .WithMany()
+ .HasForeignKey("CurrentViewAngleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Vector3", "HitDestination")
+ .WithMany()
+ .HasForeignKey("HitDestinationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Vector3", "HitOrigin")
+ .WithMany()
+ .HasForeignKey("HitOriginId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Vector3", "LastStrainAngle")
+ .WithMany()
+ .HasForeignKey("LastStrainAngleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId");
+
+ b.Navigation("Client");
+
+ b.Navigation("CurrentViewAngle");
+
+ b.Navigation("HitDestination");
+
+ b.Navigation("HitOrigin");
+
+ b.Navigation("LastStrainAngle");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientHitStatistic", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Client.Stats.Reference.EFHitLocation", "HitLocation")
+ .WithMany()
+ .HasForeignKey("HitLocationId");
+
+ b.HasOne("Data.Models.Client.Stats.Reference.EFMeansOfDeath", "MeansOfDeath")
+ .WithMany()
+ .HasForeignKey("MeansOfDeathId");
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId");
+
+ b.HasOne("Data.Models.Client.Stats.Reference.EFWeaponAttachmentCombo", "WeaponAttachmentCombo")
+ .WithMany()
+ .HasForeignKey("WeaponAttachmentComboId");
+
+ b.HasOne("Data.Models.Client.Stats.Reference.EFWeapon", "Weapon")
+ .WithMany()
+ .HasForeignKey("WeaponId");
+
+ b.Navigation("Client");
+
+ b.Navigation("HitLocation");
+
+ b.Navigation("MeansOfDeath");
+
+ b.Navigation("Server");
+
+ b.Navigation("Weapon");
+
+ b.Navigation("WeaponAttachmentCombo");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientRankingHistory", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId");
+
+ b.Navigation("Client");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientRatingHistory", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Client");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientStatistics", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Client");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFHitLocationCount", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("EFClientStatisticsClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("EFClientStatisticsServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Client.Stats.EFClientStatistics", null)
+ .WithMany("HitLocations")
+ .HasForeignKey("EFClientStatisticsClientId", "EFClientStatisticsServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Client");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFRating", b =>
+ {
+ b.HasOne("Data.Models.Client.Stats.EFClientRatingHistory", "RatingHistory")
+ .WithMany("Ratings")
+ .HasForeignKey("RatingHistoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId");
+
+ b.Navigation("RatingHistory");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.Reference.EFWeaponAttachmentCombo", b =>
+ {
+ b.HasOne("Data.Models.Client.Stats.Reference.EFWeaponAttachment", "Attachment1")
+ .WithMany()
+ .HasForeignKey("Attachment1Id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Client.Stats.Reference.EFWeaponAttachment", "Attachment2")
+ .WithMany()
+ .HasForeignKey("Attachment2Id");
+
+ b.HasOne("Data.Models.Client.Stats.Reference.EFWeaponAttachment", "Attachment3")
+ .WithMany()
+ .HasForeignKey("Attachment3Id");
+
+ b.Navigation("Attachment1");
+
+ b.Navigation("Attachment2");
+
+ b.Navigation("Attachment3");
+ });
+
+ modelBuilder.Entity("Data.Models.EFAlias", b =>
+ {
+ b.HasOne("Data.Models.EFAliasLink", "Link")
+ .WithMany("Children")
+ .HasForeignKey("LinkId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("Link");
+ });
+
+ modelBuilder.Entity("Data.Models.EFMeta", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "Client")
+ .WithMany("Meta")
+ .HasForeignKey("ClientId");
+
+ b.HasOne("Data.Models.EFMeta", "LinkedMeta")
+ .WithMany()
+ .HasForeignKey("LinkedMetaId")
+ .OnDelete(DeleteBehavior.SetNull);
+
+ b.Navigation("Client");
+
+ b.Navigation("LinkedMeta");
+ });
+
+ modelBuilder.Entity("Data.Models.EFPenalty", b =>
+ {
+ b.HasOne("Data.Models.EFAliasLink", "Link")
+ .WithMany("ReceivedPenalties")
+ .HasForeignKey("LinkId");
+
+ b.HasOne("Data.Models.Client.EFClient", "Offender")
+ .WithMany("ReceivedPenalties")
+ .HasForeignKey("OffenderId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Client.EFClient", "Punisher")
+ .WithMany("AdministeredPenalties")
+ .HasForeignKey("PunisherId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.Navigation("Link");
+
+ b.Navigation("Offender");
+
+ b.Navigation("Punisher");
+ });
+
+ modelBuilder.Entity("Data.Models.EFPenaltyIdentifier", b =>
+ {
+ b.HasOne("Data.Models.EFPenalty", "Penalty")
+ .WithMany()
+ .HasForeignKey("PenaltyId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Penalty");
+ });
+
+ modelBuilder.Entity("Data.Models.Misc.EFInboxMessage", b =>
+ {
+ b.HasOne("Data.Models.Client.EFClient", "DestinationClient")
+ .WithMany()
+ .HasForeignKey("DestinationClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId");
+
+ b.HasOne("Data.Models.Client.EFClient", "SourceClient")
+ .WithMany()
+ .HasForeignKey("SourceClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("DestinationClient");
+
+ b.Navigation("Server");
+
+ b.Navigation("SourceClient");
+ });
+
+ modelBuilder.Entity("Data.Models.Server.EFServerSnapshot", b =>
+ {
+ b.HasOne("Data.Models.Client.Stats.Reference.EFMap", "Map")
+ .WithMany()
+ .HasForeignKey("MapId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Map");
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Server.EFServerStatistics", b =>
+ {
+ b.HasOne("Data.Models.Server.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.Navigation("Server");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.EFClient", b =>
+ {
+ b.Navigation("AdministeredPenalties");
+
+ b.Navigation("Meta");
+
+ b.Navigation("ReceivedPenalties");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFACSnapshot", b =>
+ {
+ b.Navigation("PredictedViewAngles");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientRatingHistory", b =>
+ {
+ b.Navigation("Ratings");
+ });
+
+ modelBuilder.Entity("Data.Models.Client.Stats.EFClientStatistics", b =>
+ {
+ b.Navigation("HitLocations");
+ });
+
+ modelBuilder.Entity("Data.Models.EFAliasLink", b =>
+ {
+ b.Navigation("Children");
+
+ b.Navigation("ReceivedPenalties");
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/Data/Migrations/MySql/20220329213440_AddConnectionInterruptedToEFServerSnapshot.cs b/Data/Migrations/MySql/20220329213440_AddConnectionInterruptedToEFServerSnapshot.cs
new file mode 100644
index 000000000..6f7b77031
--- /dev/null
+++ b/Data/Migrations/MySql/20220329213440_AddConnectionInterruptedToEFServerSnapshot.cs
@@ -0,0 +1,25 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+#nullable disable
+
+namespace Data.Migrations.MySql
+{
+ public partial class AddConnectionInterruptedToEFServerSnapshot : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.AddColumn(
+ name: "ConnectionInterrupted",
+ table: "EFServerSnapshot",
+ type: "tinyint(1)",
+ nullable: true);
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+ migrationBuilder.DropColumn(
+ name: "ConnectionInterrupted",
+ table: "EFServerSnapshot");
+ }
+ }
+}
diff --git a/Data/Migrations/MySql/MySqlDatabaseContextModelSnapshot.cs b/Data/Migrations/MySql/MySqlDatabaseContextModelSnapshot.cs
index 1266148e5..9899cbc8b 100644
--- a/Data/Migrations/MySql/MySqlDatabaseContextModelSnapshot.cs
+++ b/Data/Migrations/MySql/MySqlDatabaseContextModelSnapshot.cs
@@ -1081,6 +1081,9 @@ namespace Data.Migrations.MySql
b.Property("ClientCount")
.HasColumnType("int");
+ b.Property("ConnectionInterrupted")
+ .HasColumnType("tinyint(1)");
+
b.Property("MapId")
.HasColumnType("int");
diff --git a/Data/Migrations/Postgresql/20220329213521_AddConnectionInterruptedToEFServerSnapshot.Designer.cs b/Data/Migrations/Postgresql/20220329213521_AddConnectionInterruptedToEFServerSnapshot.Designer.cs
new file mode 100644
index 000000000..d410ec4e8
--- /dev/null
+++ b/Data/Migrations/Postgresql/20220329213521_AddConnectionInterruptedToEFServerSnapshot.Designer.cs
@@ -0,0 +1,1683 @@
+//
+using System;
+using Data.MigrationContext;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
+
+#nullable disable
+
+namespace Data.Migrations.Postgresql
+{
+ [DbContext(typeof(PostgresqlDatabaseContext))]
+ [Migration("20220329213521_AddConnectionInterruptedToEFServerSnapshot")]
+ partial class AddConnectionInterruptedToEFServerSnapshot
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "6.0.1")
+ .HasAnnotation("Relational:MaxIdentifierLength", 63);
+
+ NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
+
+ modelBuilder.Entity("Data.Models.Client.EFACSnapshotVector3", b =>
+ {
+ b.Property("ACSnapshotVector3Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("integer");
+
+ NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ACSnapshotVector3Id"));
+
+ b.Property