diff --git a/SharedLibraryCore/Migrations/20191225202141_SetCaseSensitiveCoallationForAliasNameMySQL.Designer.cs b/SharedLibraryCore/Migrations/20191225202141_SetCaseSensitiveCoallationForAliasNameMySQL.Designer.cs
new file mode 100644
index 000000000..57d939fc4
--- /dev/null
+++ b/SharedLibraryCore/Migrations/20191225202141_SetCaseSensitiveCoallationForAliasNameMySQL.Designer.cs
@@ -0,0 +1,916 @@
+//
+using System;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+using SharedLibraryCore.Database;
+
+namespace SharedLibraryCore.Migrations
+{
+ [DbContext(typeof(DatabaseContext))]
+ [Migration("20191225202141_SetCaseSensitiveCoallationForAliasNameMySQL")]
+ partial class SetCaseSensitiveCoallationForAliasNameMySQL
+ {
+ protected override void BuildTargetModel(ModelBuilder modelBuilder)
+ {
+#pragma warning disable 612, 618
+ modelBuilder
+ .HasAnnotation("ProductVersion", "3.1.0");
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
+ {
+ b.Property("SnapshotId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("ClientId")
+ .HasColumnType("INTEGER");
+
+ b.Property("CurrentSessionLength")
+ .HasColumnType("INTEGER");
+
+ b.Property("CurrentStrain")
+ .HasColumnType("REAL");
+
+ b.Property("CurrentViewAngleId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Deaths")
+ .HasColumnType("INTEGER");
+
+ b.Property("Distance")
+ .HasColumnType("REAL");
+
+ b.Property("EloRating")
+ .HasColumnType("REAL");
+
+ b.Property("HitDestinationId")
+ .HasColumnType("INTEGER");
+
+ b.Property("HitLocation")
+ .HasColumnType("INTEGER");
+
+ b.Property("HitOriginId")
+ .HasColumnType("INTEGER");
+
+ b.Property("HitType")
+ .HasColumnType("INTEGER");
+
+ b.Property("Hits")
+ .HasColumnType("INTEGER");
+
+ b.Property("Kills")
+ .HasColumnType("INTEGER");
+
+ b.Property("LastStrainAngleId")
+ .HasColumnType("INTEGER");
+
+ b.Property("RecoilOffset")
+ .HasColumnType("REAL");
+
+ b.Property("SessionAngleOffset")
+ .HasColumnType("REAL");
+
+ b.Property("SessionAverageSnapValue")
+ .HasColumnType("REAL");
+
+ b.Property("SessionSPM")
+ .HasColumnType("REAL");
+
+ b.Property("SessionScore")
+ .HasColumnType("INTEGER");
+
+ b.Property("SessionSnapHits")
+ .HasColumnType("INTEGER");
+
+ b.Property("StrainAngleBetween")
+ .HasColumnType("REAL");
+
+ b.Property("TimeSinceLastEvent")
+ .HasColumnType("INTEGER");
+
+ b.Property("WeaponId")
+ .HasColumnType("INTEGER");
+
+ b.Property("When")
+ .HasColumnType("TEXT");
+
+ b.HasKey("SnapshotId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("CurrentViewAngleId");
+
+ b.HasIndex("HitDestinationId");
+
+ b.HasIndex("HitOriginId");
+
+ b.HasIndex("LastStrainAngleId");
+
+ b.ToTable("EFACSnapshot");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
+ {
+ b.Property("ACSnapshotVector3Id")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("SnapshotId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Vector3Id")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("ACSnapshotVector3Id");
+
+ b.HasIndex("SnapshotId");
+
+ b.HasIndex("Vector3Id");
+
+ b.ToTable("EFACSnapshotVector3");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
+ {
+ b.Property("KillId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("AttackerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Damage")
+ .HasColumnType("INTEGER");
+
+ b.Property("DeathOriginVector3Id")
+ .HasColumnType("INTEGER");
+
+ b.Property("DeathType")
+ .HasColumnType("INTEGER");
+
+ b.Property("Fraction")
+ .HasColumnType("REAL");
+
+ b.Property("HitLoc")
+ .HasColumnType("INTEGER");
+
+ b.Property("IsKill")
+ .HasColumnType("INTEGER");
+
+ b.Property("KillOriginVector3Id")
+ .HasColumnType("INTEGER");
+
+ b.Property("Map")
+ .HasColumnType("INTEGER");
+
+ b.Property("ServerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("VictimId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ViewAnglesVector3Id")
+ .HasColumnType("INTEGER");
+
+ b.Property("VisibilityPercentage")
+ .HasColumnType("REAL");
+
+ b.Property("Weapon")
+ .HasColumnType("INTEGER");
+
+ b.Property("When")
+ .HasColumnType("TEXT");
+
+ 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()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("ClientId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Message")
+ .HasColumnType("TEXT");
+
+ b.Property("ServerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("TimeSent")
+ .HasColumnType("TEXT");
+
+ b.HasKey("MessageId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("TimeSent");
+
+ b.ToTable("EFClientMessages");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
+ {
+ b.Property("RatingHistoryId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("ClientId")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("RatingHistoryId");
+
+ b.HasIndex("ClientId");
+
+ b.ToTable("EFClientRatingHistory");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
+ {
+ b.Property("ClientId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ServerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("AverageRecoilOffset")
+ .HasColumnType("REAL");
+
+ b.Property("AverageSnapValue")
+ .HasColumnType("REAL");
+
+ b.Property("Deaths")
+ .HasColumnType("INTEGER");
+
+ b.Property("EloRating")
+ .HasColumnType("REAL");
+
+ b.Property("Kills")
+ .HasColumnType("INTEGER");
+
+ b.Property("MaxStrain")
+ .HasColumnType("REAL");
+
+ b.Property("RollingWeightedKDR")
+ .HasColumnType("REAL");
+
+ b.Property("SPM")
+ .HasColumnType("REAL");
+
+ b.Property("Skill")
+ .HasColumnType("REAL");
+
+ b.Property("SnapHitCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("TimePlayed")
+ .HasColumnType("INTEGER");
+
+ b.Property("VisionAverage")
+ .HasColumnType("REAL");
+
+ b.HasKey("ClientId", "ServerId");
+
+ b.HasIndex("ServerId");
+
+ b.ToTable("EFClientStatistics");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
+ {
+ b.Property("HitLocationCountId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("EFClientStatisticsClientId")
+ .HasColumnName("EFClientStatisticsClientId")
+ .HasColumnType("INTEGER");
+
+ b.Property("EFClientStatisticsServerId")
+ .HasColumnName("EFClientStatisticsServerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("HitCount")
+ .HasColumnType("INTEGER");
+
+ b.Property("HitOffsetAverage")
+ .HasColumnType("REAL");
+
+ b.Property("Location")
+ .HasColumnType("INTEGER");
+
+ b.Property("MaxAngleDistance")
+ .HasColumnType("REAL");
+
+ b.HasKey("HitLocationCountId");
+
+ b.HasIndex("EFClientStatisticsServerId");
+
+ b.HasIndex("EFClientStatisticsClientId", "EFClientStatisticsServerId");
+
+ b.ToTable("EFHitLocationCounts");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
+ {
+ b.Property("RatingId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("ActivityAmount")
+ .HasColumnType("INTEGER");
+
+ b.Property("Newest")
+ .HasColumnType("INTEGER");
+
+ b.Property("Performance")
+ .HasColumnType("REAL");
+
+ b.Property("Ranking")
+ .HasColumnType("INTEGER");
+
+ b.Property("RatingHistoryId")
+ .HasColumnType("INTEGER");
+
+ b.Property("ServerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("When")
+ .HasColumnType("TEXT");
+
+ b.HasKey("RatingId");
+
+ b.HasIndex("RatingHistoryId");
+
+ b.HasIndex("ServerId");
+
+ b.HasIndex("Performance", "Ranking", "When");
+
+ b.ToTable("EFRating");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServer", b =>
+ {
+ b.Property("ServerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("EndPoint")
+ .HasColumnType("TEXT");
+
+ b.Property("GameName")
+ .HasColumnType("INTEGER");
+
+ b.Property("Port")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("ServerId");
+
+ b.ToTable("EFServers");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
+ {
+ b.Property("StatisticId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("ServerId")
+ .HasColumnType("INTEGER");
+
+ b.Property("TotalKills")
+ .HasColumnType("INTEGER");
+
+ b.Property("TotalPlayTime")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("StatisticId");
+
+ b.HasIndex("ServerId");
+
+ b.ToTable("EFServerStatistics");
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
+ {
+ b.Property("AliasId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("DateAdded")
+ .HasColumnType("TEXT");
+
+ b.Property("IPAddress")
+ .HasColumnType("INTEGER");
+
+ b.Property("LinkId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Name")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(24);
+
+ b.Property("SearchableName")
+ .HasColumnType("TEXT")
+ .HasMaxLength(24);
+
+ b.HasKey("AliasId");
+
+ b.HasIndex("IPAddress");
+
+ b.HasIndex("LinkId");
+
+ b.HasIndex("Name");
+
+ b.HasIndex("SearchableName");
+
+ b.HasIndex("Name", "IPAddress")
+ .IsUnique();
+
+ b.ToTable("EFAlias");
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAliasLink", b =>
+ {
+ b.Property("AliasLinkId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("AliasLinkId");
+
+ b.ToTable("EFAliasLinks");
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFChangeHistory", b =>
+ {
+ b.Property("ChangeHistoryId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("Comment")
+ .HasColumnType("TEXT")
+ .HasMaxLength(128);
+
+ b.Property("CurrentValue")
+ .HasColumnType("TEXT");
+
+ b.Property("OriginEntityId")
+ .HasColumnType("INTEGER");
+
+ b.Property("PreviousValue")
+ .HasColumnType("TEXT");
+
+ b.Property("TargetEntityId")
+ .HasColumnType("INTEGER");
+
+ b.Property("TimeChanged")
+ .HasColumnType("TEXT");
+
+ b.Property("TypeOfChange")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("ChangeHistoryId");
+
+ b.ToTable("EFChangeHistory");
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
+ {
+ b.Property("ClientId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("AliasLinkId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Connections")
+ .HasColumnType("INTEGER");
+
+ b.Property("CurrentAliasId")
+ .HasColumnType("INTEGER");
+
+ b.Property("FirstConnection")
+ .HasColumnType("TEXT");
+
+ b.Property("LastConnection")
+ .HasColumnType("TEXT");
+
+ b.Property("Level")
+ .HasColumnType("INTEGER");
+
+ b.Property("Masked")
+ .HasColumnType("INTEGER");
+
+ b.Property("NetworkId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Password")
+ .HasColumnType("TEXT");
+
+ b.Property("PasswordSalt")
+ .HasColumnType("TEXT");
+
+ b.Property("TotalConnectionTime")
+ .HasColumnType("INTEGER");
+
+ b.HasKey("ClientId");
+
+ b.HasIndex("AliasLinkId");
+
+ b.HasIndex("CurrentAliasId");
+
+ b.HasIndex("NetworkId")
+ .IsUnique();
+
+ b.ToTable("EFClients");
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
+ {
+ b.Property("MetaId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("ClientId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Created")
+ .HasColumnType("TEXT");
+
+ b.Property("Extra")
+ .HasColumnType("TEXT");
+
+ b.Property("Key")
+ .IsRequired()
+ .HasColumnType("TEXT")
+ .HasMaxLength(32);
+
+ b.Property("Updated")
+ .HasColumnType("TEXT");
+
+ b.Property("Value")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.HasKey("MetaId");
+
+ b.HasIndex("ClientId");
+
+ b.HasIndex("Key");
+
+ b.ToTable("EFMeta");
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
+ {
+ b.Property("PenaltyId")
+ .ValueGeneratedOnAdd()
+ .HasColumnType("INTEGER");
+
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
+ b.Property("AutomatedOffense")
+ .HasColumnType("TEXT");
+
+ b.Property("Expires")
+ .HasColumnType("TEXT");
+
+ b.Property("IsEvadedOffense")
+ .HasColumnType("INTEGER");
+
+ b.Property("LinkId")
+ .HasColumnType("INTEGER");
+
+ b.Property("OffenderId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Offense")
+ .IsRequired()
+ .HasColumnType("TEXT");
+
+ b.Property("PunisherId")
+ .HasColumnType("INTEGER");
+
+ b.Property("Type")
+ .HasColumnType("INTEGER");
+
+ b.Property("When")
+ .HasColumnType("TEXT");
+
+ 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()
+ .HasColumnType("INTEGER");
+
+ b.Property("X")
+ .HasColumnType("REAL");
+
+ b.Property("Y")
+ .HasColumnType("REAL");
+
+ b.Property("Z")
+ .HasColumnType("REAL");
+
+ b.HasKey("Vector3Id");
+
+ b.ToTable("Vector3");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Helpers.Vector3", "CurrentViewAngle")
+ .WithMany()
+ .HasForeignKey("CurrentViewAngleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitDestination")
+ .WithMany()
+ .HasForeignKey("HitDestinationId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Helpers.Vector3", "HitOrigin")
+ .WithMany()
+ .HasForeignKey("HitOriginId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Helpers.Vector3", "LastStrainAngle")
+ .WithMany()
+ .HasForeignKey("LastStrainAngleId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshotVector3", b =>
+ {
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", "Snapshot")
+ .WithMany("PredictedViewAngles")
+ .HasForeignKey("SnapshotId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Helpers.Vector3", "Vector")
+ .WithMany()
+ .HasForeignKey("Vector3Id")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientKill", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Attacker")
+ .WithMany()
+ .HasForeignKey("AttackerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ 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)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Victim")
+ .WithMany()
+ .HasForeignKey("VictimId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ 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)
+ .IsRequired();
+
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFHitLocationCount", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
+ .WithMany()
+ .HasForeignKey("EFClientStatisticsClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("EFClientStatisticsServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientStatistics", null)
+ .WithMany("HitLocations")
+ .HasForeignKey("EFClientStatisticsClientId", "EFClientStatisticsServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFRating", b =>
+ {
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFClientRatingHistory", "RatingHistory")
+ .WithMany("Ratings")
+ .HasForeignKey("RatingHistoryId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId");
+ });
+
+ modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFServerStatistics", b =>
+ {
+ b.HasOne("IW4MAdmin.Plugins.Stats.Models.EFServer", "Server")
+ .WithMany()
+ .HasForeignKey("ServerId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFAlias", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
+ .WithMany("Children")
+ .HasForeignKey("LinkId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFClient", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "AliasLink")
+ .WithMany()
+ .HasForeignKey("AliasLinkId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Database.Models.EFAlias", "CurrentAlias")
+ .WithMany()
+ .HasForeignKey("CurrentAliasId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFMeta", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Client")
+ .WithMany("Meta")
+ .HasForeignKey("ClientId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+ });
+
+ modelBuilder.Entity("SharedLibraryCore.Database.Models.EFPenalty", b =>
+ {
+ b.HasOne("SharedLibraryCore.Database.Models.EFAliasLink", "Link")
+ .WithMany("ReceivedPenalties")
+ .HasForeignKey("LinkId")
+ .OnDelete(DeleteBehavior.Cascade)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Offender")
+ .WithMany("ReceivedPenalties")
+ .HasForeignKey("OffenderId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+
+ b.HasOne("SharedLibraryCore.Database.Models.EFClient", "Punisher")
+ .WithMany("AdministeredPenalties")
+ .HasForeignKey("PunisherId")
+ .OnDelete(DeleteBehavior.Restrict)
+ .IsRequired();
+ });
+#pragma warning restore 612, 618
+ }
+ }
+}
diff --git a/SharedLibraryCore/Migrations/20191225202141_SetCaseSensitiveCoallationForAliasNameMySQL.cs b/SharedLibraryCore/Migrations/20191225202141_SetCaseSensitiveCoallationForAliasNameMySQL.cs
new file mode 100644
index 000000000..a72e27569
--- /dev/null
+++ b/SharedLibraryCore/Migrations/20191225202141_SetCaseSensitiveCoallationForAliasNameMySQL.cs
@@ -0,0 +1,24 @@
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace SharedLibraryCore.Migrations
+{
+ public partial class SetCaseSensitiveCoallationForAliasNameMySQL : Migration
+ {
+ protected override void Up(MigrationBuilder migrationBuilder)
+ {
+ if (migrationBuilder.ActiveProvider == "Pomelo.EntityFrameworkCore.MySql")
+ {
+ // this prevents duplicate aliases from being added by changing it to case sensitive collation
+ migrationBuilder.Sql(@"ALTER TABLE `EFAlias` MODIFY
+ `Name` VARCHAR(24)
+ CHARACTER SET utf8
+ COLLATE utf8_bin;");
+ };
+ }
+
+ protected override void Down(MigrationBuilder migrationBuilder)
+ {
+
+ }
+ }
+}
diff --git a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs
index 6350362c7..c36dee7f6 100644
--- a/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs
+++ b/SharedLibraryCore/Migrations/DatabaseContextModelSnapshot.cs
@@ -14,7 +14,7 @@ namespace SharedLibraryCore.Migrations
{
#pragma warning disable 612, 618
modelBuilder
- .HasAnnotation("ProductVersion", "3.0.0");
+ .HasAnnotation("ProductVersion", "3.1.0");
modelBuilder.Entity("IW4MAdmin.Plugins.Stats.Models.EFACSnapshot", b =>
{
@@ -118,6 +118,9 @@ namespace SharedLibraryCore.Migrations
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
+ b.Property("Active")
+ .HasColumnType("INTEGER");
+
b.Property("SnapshotId")
.HasColumnType("INTEGER");
@@ -464,8 +467,12 @@ namespace SharedLibraryCore.Migrations
b.HasKey("AliasId");
+ b.HasIndex("IPAddress");
+
b.HasIndex("LinkId");
+ b.HasIndex("Name");
+
b.HasIndex("SearchableName");
b.HasIndex("Name", "IPAddress")
diff --git a/SharedLibraryCore/ScriptPlugin.cs b/SharedLibraryCore/ScriptPlugin.cs
index 92cd83ef0..b59b94898 100644
--- a/SharedLibraryCore/ScriptPlugin.cs
+++ b/SharedLibraryCore/ScriptPlugin.cs
@@ -1,9 +1,11 @@
-using SharedLibraryCore.Database.Models;
+using Jint;
+using SharedLibraryCore.Database.Models;
using SharedLibraryCore.Interfaces;
using System;
using System.IO;
using System.Linq;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
namespace SharedLibraryCore
@@ -16,14 +18,17 @@ namespace SharedLibraryCore
public string Author { get; set; }
- private Jint.Engine ScriptEngine;
+ private Engine ScriptEngine;
private readonly string FileName;
private IManager Manager;
private readonly FileSystemWatcher _watcher;
+ private readonly SemaphoreSlim _fileChanging;
+ private bool successfullyLoaded;
public ScriptPlugin(string fileName)
{
FileName = fileName;
+ _fileChanging = new SemaphoreSlim(1, 1);
_watcher = new FileSystemWatcher()
{
Path = $"{Utilities.OperatingDirectory}Plugins{Path.DirectorySeparatorChar}",
@@ -38,30 +43,51 @@ namespace SharedLibraryCore
~ScriptPlugin()
{
_watcher.Dispose();
+ _fileChanging.Dispose();
}
private async void Watcher_Changed(object sender, FileSystemEventArgs e)
{
try
{
+ await _fileChanging.WaitAsync();
await Initialize(Manager);
}
+
catch (Exception ex)
{
Manager.GetLogger(0).WriteError(Utilities.CurrentLocalization.LocalizationIndex["PLUGIN_IMPORTER_ERROR"].FormatExt(Name));
Manager.GetLogger(0).WriteDebug(ex.Message);
}
+
+ finally
+ {
+ if (_fileChanging.CurrentCount == 0)
+ {
+ _fileChanging.Release(1);
+ }
+ }
}
public async Task Initialize(IManager mgr)
{
+ // for some reason we get an event trigger when the file is not finished being modified.
+ // this must have been a change in .NET CORE 3.x
+ // so if the new file is empty we can't process it yet
+ if (new FileInfo(FileName).Length == 0L)
+ {
+ return;
+ }
+
bool firstRun = ScriptEngine == null;
+
// it's been loaded before so we need to call the unload event
if (!firstRun)
{
await OnUnloadAsync();
}
+ successfullyLoaded = false;
Manager = mgr;
string script;
@@ -73,7 +99,7 @@ namespace SharedLibraryCore
}
}
- ScriptEngine = new Jint.Engine(cfg =>
+ ScriptEngine = new Engine(cfg =>
cfg.AllowClr(new[]
{
typeof(System.Net.Http.HttpClient).Assembly,
@@ -85,14 +111,13 @@ namespace SharedLibraryCore
ScriptEngine.SetValue("_localization", Utilities.CurrentLocalization);
dynamic pluginObject = ScriptEngine.GetValue("plugin").ToObject();
- this.Author = pluginObject.author;
- this.Name = pluginObject.name;
- this.Version = (float)pluginObject.version;
-
+ Author = pluginObject.author;
+ Name = pluginObject.name;
+ Version = (float)pluginObject.version;
try
{
- if (pluginObject.isParser)
+ if(pluginObject.isParser)
{
await OnLoadAsync(mgr);
IEventParser eventParser = (IEventParser)ScriptEngine.GetValue("eventParser").ToObject();
@@ -108,21 +133,38 @@ namespace SharedLibraryCore
{
await OnLoadAsync(mgr);
}
+
+ successfullyLoaded = true;
}
- public Task OnEventAsync(GameEvent E, Server S)
+ public async Task OnEventAsync(GameEvent E, Server S)
{
- lock (ScriptEngine)
+ if (successfullyLoaded)
{
- ScriptEngine.SetValue("_gameEvent", E);
- ScriptEngine.SetValue("_server", S);
- ScriptEngine.SetValue("_IW4MAdminClient", Utilities.IW4MAdminClient(S));
- return Task.FromResult(ScriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue());
+ try
+ {
+ await _fileChanging.WaitAsync();
+ ScriptEngine.SetValue("_gameEvent", E);
+ ScriptEngine.SetValue("_server", S);
+ ScriptEngine.SetValue("_IW4MAdminClient", Utilities.IW4MAdminClient(S));
+ ScriptEngine.Execute("plugin.onEventAsync(_gameEvent, _server)").GetCompletionValue();
+ }
+
+ catch { }
+
+ finally
+ {
+ if (_fileChanging.CurrentCount == 0)
+ {
+ _fileChanging.Release(1);
+ }
+ }
}
}
public Task OnLoadAsync(IManager manager)
{
+ Manager.GetLogger(0).WriteDebug($"OnLoad executing for {Name}");
ScriptEngine.SetValue("_manager", manager);
return Task.FromResult(ScriptEngine.Execute("plugin.onLoadAsync(_manager)").GetCompletionValue());
}
@@ -133,9 +175,13 @@ namespace SharedLibraryCore
return Task.FromResult(ScriptEngine.Execute("plugin.onTickAsync(_server)").GetCompletionValue());
}
- public Task OnUnloadAsync()
+ public async Task OnUnloadAsync()
{
- return Task.FromResult(ScriptEngine.Execute("plugin.onUnloadAsync()").GetCompletionValue());
+ if (successfullyLoaded)
+ {
+ Manager.GetLogger(0).WriteDebug($"OnUnLoad executing for {Name}");
+ await Task.FromResult(ScriptEngine.Execute("plugin.onUnloadAsync()").GetCompletionValue());
+ }
}
}
}