diff --git a/src/MysqlMigrations/Migrations/20240625152338_DsUnits0624.cs b/src/MysqlMigrations/Migrations/20240625152338_DsUnits0624.cs index a1b3aab1..bf951624 100644 --- a/src/MysqlMigrations/Migrations/20240625152338_DsUnits0624.cs +++ b/src/MysqlMigrations/Migrations/20240625152338_DsUnits0624.cs @@ -13,8 +13,8 @@ protected override void Up(MigrationBuilder migrationBuilder) var sql1 = @"UPDATE DsUnits SET Cost = 80 WHERE Commander = 10 and Name = 'Vile Roach'; UPDATE DsUnits SET Cost = 425 WHERE Commander = 20 and Name = 'Vanguard'; UPDATE DsUnits SET Cost = 300 WHERE Commander = 20 and Name = 'Ascendant'; -UPDATE DsUnits SET Cost = 1250 WHERE Commander = 80 and Name = 'Tal\'darim Mothership'; -UPDATE DsUnits SET Cost = 295 WHERE Commander = 20 and Name = 'Lurker'; +UPDATE DsUnits SET Cost = 1250 WHERE Commander = 20 and Name = 'Tal\'darim Mothership'; +UPDATE DsUnits SET Cost = 295 WHERE Commander = 80 and Name = 'Lurker'; UPDATE DsUnits SET Cost = 320 WHERE Commander = 80 and Name = 'Brood Lord'; UPDATE DsUnits SET Cost = 350 WHERE Commander = 160 and Name = 'Dark Archon'; UPDATE DsUpgrades SET Cost = 75 WHERE Commander = 80 and Upgrade = 'Seismic Spines'; diff --git a/src/MysqlMigrations/Migrations/20240714155954_ReplayArcadeMatch.Designer.cs b/src/MysqlMigrations/Migrations/20240714155954_ReplayArcadeMatch.Designer.cs new file mode 100644 index 00000000..50d4c364 --- /dev/null +++ b/src/MysqlMigrations/Migrations/20240714155954_ReplayArcadeMatch.Designer.cs @@ -0,0 +1,2400 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using dsstats.db8; + +#nullable disable + +namespace MysqlMigrations.Migrations +{ + [DbContext(typeof(ReplayContext))] + [Migration("20240714155954_ReplayArcadeMatch")] + partial class ReplayArcadeMatch + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("DsAbilityDsUnit", b => + { + b.Property("AbilitiesDsAbilityId") + .HasColumnType("int"); + + b.Property("DsUnitsDsUnitId") + .HasColumnType("int"); + + b.HasKey("AbilitiesDsAbilityId", "DsUnitsDsUnitId"); + + b.HasIndex("DsUnitsDsUnitId"); + + b.ToTable("DsAbilityDsUnit"); + }); + + modelBuilder.Entity("ReplayUploader", b => + { + b.Property("ReplaysReplayId") + .HasColumnType("int"); + + b.Property("UploadersUploaderId") + .HasColumnType("int"); + + b.HasKey("ReplaysReplayId", "UploadersUploaderId"); + + b.HasIndex("UploadersUploaderId"); + + b.ToTable("UploaderReplays", (string)null); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayer", b => + { + b.Property("ArcadePlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadePlayerId")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ProfileId") + .HasColumnType("int"); + + b.Property("RealmId") + .HasColumnType("int"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.HasKey("ArcadePlayerId"); + + b.HasIndex("Name"); + + b.HasIndex("RegionId", "RealmId", "ProfileId") + .IsUnique(); + + b.ToTable("ArcadePlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRating", b => + { + b.Property("ArcadePlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadePlayerRatingId")); + + b.Property("ArcadePlayerId") + .HasColumnType("int"); + + b.Property("Confidence") + .HasColumnType("double"); + + b.Property("Consistency") + .HasColumnType("double"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("IsUploader") + .HasColumnType("tinyint(1)"); + + b.Property("Main") + .HasColumnType("int"); + + b.Property("MainCount") + .HasColumnType("int"); + + b.Property("Mvp") + .HasColumnType("int"); + + b.Property("Pos") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("double"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("TeamGames") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("ArcadePlayerRatingId"); + + b.HasIndex("ArcadePlayerId"); + + b.HasIndex("RatingType"); + + b.ToTable("ArcadePlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRatingChange", b => + { + b.Property("ArcadePlayerRatingChangeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadePlayerRatingChangeId")); + + b.Property("ArcadePlayerRatingId") + .HasColumnType("int"); + + b.Property("Change10d") + .HasColumnType("float"); + + b.Property("Change24h") + .HasColumnType("float"); + + b.Property("Change30d") + .HasColumnType("float"); + + b.HasKey("ArcadePlayerRatingChangeId"); + + b.HasIndex("ArcadePlayerRatingId") + .IsUnique(); + + b.ToTable("ArcadePlayerRatingChanges"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplay", b => + { + b.Property("ArcadeReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayId")); + + b.Property("BnetBucketId") + .HasColumnType("bigint"); + + b.Property("BnetRecordId") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("Imported") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("PlayerCount") + .HasColumnType("int"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("TournamentEdition") + .HasColumnType("tinyint(1)"); + + b.Property("WinnerTeam") + .HasColumnType("int"); + + b.HasKey("ArcadeReplayId"); + + b.HasIndex("ReplayHash"); + + b.HasIndex("GameMode", "CreatedAt"); + + b.HasIndex("RegionId", "BnetBucketId", "BnetRecordId") + .IsUnique(); + + b.HasIndex("RegionId", "GameMode", "CreatedAt"); + + b.ToTable("ArcadeReplays"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayer", b => + { + b.Property("ArcadeReplayPlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayPlayerId")); + + b.Property("ArcadePlayerId") + .HasColumnType("int"); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("Discriminator") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.Property("SlotNumber") + .HasColumnType("int"); + + b.Property("Team") + .HasColumnType("int"); + + b.HasKey("ArcadeReplayPlayerId"); + + b.HasIndex("ArcadePlayerId"); + + b.HasIndex("ArcadeReplayId"); + + b.ToTable("ArcadeReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayerRating", b => + { + b.Property("ArcadeReplayPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayPlayerRatingId")); + + b.Property("ArcadeReplayPlayerId") + .HasColumnType("int"); + + b.Property("ArcadeReplayRatingId") + .HasColumnType("int"); + + b.Property("Confidence") + .HasColumnType("float"); + + b.Property("Consistency") + .HasColumnType("float"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("float"); + + b.Property("RatingChange") + .HasColumnType("float"); + + b.HasKey("ArcadeReplayPlayerRatingId"); + + b.HasIndex("ArcadeReplayPlayerId") + .IsUnique(); + + b.HasIndex("ArcadeReplayRatingId"); + + b.ToTable("ArcadeReplayPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayRating", b => + { + b.Property("ArcadeReplayRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayRatingId")); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("AvgRating") + .HasColumnType("int"); + + b.Property("ExpectationToWin") + .HasColumnType("float"); + + b.Property("LeaverType") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.HasKey("ArcadeReplayRatingId"); + + b.HasIndex("ArcadeReplayId") + .IsUnique(); + + b.ToTable("ArcadeReplayRatings"); + }); + + modelBuilder.Entity("dsstats.db8.BattleNetInfo", b => + { + b.Property("BattleNetInfoId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("BattleNetInfoId")); + + b.Property("BattleNetId") + .HasColumnType("int"); + + b.Property("UploaderId") + .HasColumnType("int"); + + b.HasKey("BattleNetInfoId"); + + b.HasIndex("UploaderId"); + + b.ToTable("BattleNetInfos"); + }); + + modelBuilder.Entity("dsstats.db8.BonusDamage", b => + { + b.Property("BonusDamageId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("BonusDamageId")); + + b.Property("Damage") + .HasColumnType("int"); + + b.Property("DsWeaponId") + .HasColumnType("int"); + + b.Property("PerUpgrade") + .HasColumnType("int"); + + b.Property("UnitType") + .HasColumnType("int"); + + b.HasKey("BonusDamageId"); + + b.HasIndex("DsWeaponId"); + + b.HasIndex("UnitType"); + + b.ToTable("BonusDamages"); + }); + + modelBuilder.Entity("dsstats.db8.ComboPlayerRating", b => + { + b.Property("ComboPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ComboPlayerRatingId")); + + b.Property("Confidence") + .HasColumnType("double"); + + b.Property("Consistency") + .HasColumnType("double"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("Pos") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("double"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("ComboPlayerRatingId"); + + b.HasIndex("PlayerId"); + + b.HasIndex("RatingType"); + + b.ToTable("ComboPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayPlayerRating", b => + { + b.Property("ComboReplayPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ComboReplayPlayerRatingId")); + + b.Property("Change") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("Confidence") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("Consistency") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("int"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.HasKey("ComboReplayPlayerRatingId"); + + b.HasIndex("ReplayPlayerId") + .IsUnique(); + + b.ToTable("ComboReplayPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayRating", b => + { + b.Property("ComboReplayRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ComboReplayRatingId")); + + b.Property("AvgRating") + .HasColumnType("int"); + + b.Property("ExpectationToWin") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("IsPreRating") + .HasColumnType("tinyint(1)"); + + b.Property("LeaverType") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.HasKey("ComboReplayRatingId"); + + b.HasIndex("RatingType"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("ComboReplayRatings"); + }); + + modelBuilder.Entity("dsstats.db8.CommanderMmr", b => + { + b.Property("CommanderMmrId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CommanderMmrId")); + + b.Property("AntiSynergyMmr") + .HasColumnType("double"); + + b.Property("OppRace") + .HasColumnType("int"); + + b.Property("Race") + .HasColumnType("int"); + + b.Property("SynergyMmr") + .HasColumnType("double"); + + b.HasKey("CommanderMmrId"); + + b.HasIndex("Race", "OppRace"); + + b.ToTable("CommanderMmrs"); + }); + + modelBuilder.Entity("dsstats.db8.DsAbility", b => + { + b.Property("DsAbilityId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsAbilityId")); + + b.Property("AbilityTarget") + .HasColumnType("int"); + + b.Property("AoeRadius") + .HasColumnType("float"); + + b.Property("CastRange") + .HasColumnType("int"); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("Cooldown") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(310) + .HasColumnType("varchar(310)"); + + b.Property("EnergyCost") + .HasColumnType("float"); + + b.Property("GlobalTimer") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Requirements") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.HasKey("DsAbilityId"); + + b.HasIndex("Name"); + + b.ToTable("DsAbilities"); + }); + + modelBuilder.Entity("dsstats.db8.DsPickBan", b => + { + b.Property("DsPickBanId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsPickBanId")); + + b.Property("Bans") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PickBanMode") + .HasColumnType("int"); + + b.Property("Picks") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Time") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.HasKey("DsPickBanId"); + + b.ToTable("DsPickBans"); + }); + + modelBuilder.Entity("dsstats.db8.DsUnit", b => + { + b.Property("DsUnitId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsUnitId")); + + b.Property("Armor") + .HasColumnType("int"); + + b.Property("Color") + .HasColumnType("int"); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("Cost") + .HasColumnType("int"); + + b.Property("EnergyRegen") + .HasColumnType("float"); + + b.Property("HealthRegen") + .HasColumnType("float"); + + b.Property("Life") + .HasColumnType("int"); + + b.Property("MaxEnergy") + .HasColumnType("int"); + + b.Property("MovementType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("ShieldArmor") + .HasColumnType("int"); + + b.Property("Shields") + .HasColumnType("int"); + + b.Property("Size") + .HasColumnType("int"); + + b.Property("Speed") + .HasColumnType("float"); + + b.Property("StartingEnergy") + .HasColumnType("int"); + + b.Property("Tier") + .HasColumnType("int"); + + b.Property("UnitId") + .HasColumnType("int"); + + b.Property("UnitType") + .HasColumnType("int"); + + b.HasKey("DsUnitId"); + + b.HasIndex("Commander"); + + b.HasIndex("Name"); + + b.HasIndex("Name", "Commander"); + + b.ToTable("DsUnits"); + }); + + modelBuilder.Entity("dsstats.db8.DsUpdate", b => + { + b.Property("DsUpdateId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsUpdateId")); + + b.Property("Change") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("DiscordId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Time") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.HasKey("DsUpdateId"); + + b.HasIndex("Time"); + + b.ToTable("DsUpdates"); + }); + + modelBuilder.Entity("dsstats.db8.DsUpgrade", b => + { + b.Property("DsUpgradeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsUpgradeId")); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("Cost") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("DsUnitId") + .HasColumnType("int"); + + b.Property("RequiredTier") + .HasColumnType("int"); + + b.Property("Upgrade") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.HasKey("DsUpgradeId"); + + b.HasIndex("DsUnitId"); + + b.HasIndex("Upgrade"); + + b.ToTable("DsUpgrades"); + }); + + modelBuilder.Entity("dsstats.db8.DsWeapon", b => + { + b.Property("DsWeaponId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsWeaponId")); + + b.Property("AttackSpeed") + .HasColumnType("float"); + + b.Property("Attacks") + .HasColumnType("int"); + + b.Property("CanTarget") + .HasColumnType("int"); + + b.Property("Damage") + .HasColumnType("int"); + + b.Property("DamagePerUpgrade") + .HasColumnType("int"); + + b.Property("DsUnitId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Range") + .HasColumnType("float"); + + b.HasKey("DsWeaponId"); + + b.HasIndex("DsUnitId"); + + b.ToTable("DsWeapons"); + }); + + modelBuilder.Entity("dsstats.db8.Event", b => + { + b.Property("EventId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("EventId")); + + b.Property("EventGuid") + .HasColumnType("char(36)"); + + b.Property("EventStart") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("WinnerTeam") + .HasColumnType("longtext"); + + b.HasKey("EventId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("dsstats.db8.Faq", b => + { + b.Property("FaqId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("FaqId")); + + b.Property("Answer") + .IsRequired() + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("CreatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("CreatedBy") + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Question") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("UpdatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Upvotes") + .HasColumnType("int"); + + b.HasKey("FaqId"); + + b.HasIndex("Question"); + + b.ToTable("Faqs"); + }); + + modelBuilder.Entity("dsstats.db8.FaqVote", b => + { + b.Property("FaqVoteId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("FaqVoteId")); + + b.Property("FaqId") + .HasColumnType("int"); + + b.HasKey("FaqVoteId"); + + b.ToTable("FaqVotes"); + }); + + modelBuilder.Entity("dsstats.db8.FunStatsMemory", b => + { + b.Property("FunStatsMemoryId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("FunStatsMemoryId")); + + b.Property("AvgGameDuration") + .HasColumnType("int"); + + b.Property("Created") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("FirstReplay") + .HasColumnType("longtext"); + + b.Property("GreatestArmyReplay") + .HasColumnType("longtext"); + + b.Property("GreatestComebackReplay") + .HasColumnType("longtext"); + + b.Property("MostCompetitiveReplay") + .HasColumnType("longtext"); + + b.Property("MostUpgradesReplay") + .HasColumnType("longtext"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("TimePeriod") + .HasColumnType("int"); + + b.Property("TotalTimePlayed") + .HasColumnType("bigint"); + + b.Property("UnitCountLeast") + .HasColumnType("int"); + + b.Property("UnitCountMost") + .HasColumnType("int"); + + b.Property("UnitNameLeast") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UnitNameMost") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("FunStatsMemoryId"); + + b.ToTable("FunStatMemories"); + }); + + modelBuilder.Entity("dsstats.db8.GroupByHelper", b => + { + b.Property("Count") + .HasColumnType("int"); + + b.Property("Group") + .HasColumnType("tinyint(1)") + .HasColumnName("Name"); + + b.ToTable((string)null); + + b.ToView("GroupByHelper", (string)null); + }); + + modelBuilder.Entity("dsstats.db8.IhSession", b => + { + b.Property("IhSessionId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("IhSessionId")); + + b.Property("Closed") + .HasColumnType("tinyint(1)"); + + b.Property("Created") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("GroupState") + .HasColumnType("longtext"); + + b.Property("GroupStateV2") + .HasColumnType("longtext"); + + b.Property("Players") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.HasKey("IhSessionId"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.ToTable("IhSessions"); + }); + + modelBuilder.Entity("dsstats.db8.IhSessionPlayer", b => + { + b.Property("IhSessionPlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("IhSessionPlayerId")); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("IhSessionId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Obs") + .HasColumnType("int"); + + b.Property("Performance") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("RatingEnd") + .HasColumnType("int"); + + b.Property("RatingStart") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("IhSessionPlayerId"); + + b.HasIndex("IhSessionId"); + + b.HasIndex("PlayerId"); + + b.ToTable("IhSessionPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.MaterializedArcadeReplay", b => + { + b.Property("MaterializedArcadeReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("MaterializedArcadeReplayId")); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("WinnerTeam") + .HasColumnType("int"); + + b.HasKey("MaterializedArcadeReplayId"); + + b.ToTable("MaterializedArcadeReplays"); + }); + + modelBuilder.Entity("dsstats.db8.NoUploadResult", b => + { + b.Property("NoUploadResultId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("NoUploadResultId")); + + b.Property("Created") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestNoUpload") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestReplay") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestUpload") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("NoUploadDefeats") + .HasColumnType("int"); + + b.Property("NoUploadTotal") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("TotalReplays") + .HasColumnType("int"); + + b.HasKey("NoUploadResultId"); + + b.HasIndex("PlayerId"); + + b.ToTable("NoUploadResults"); + }); + + modelBuilder.Entity("dsstats.db8.Player", b => + { + b.Property("PlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerId")); + + b.Property("ArcadeDefeatsSinceLastUpload") + .HasColumnType("int"); + + b.Property("DisconnectCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("NotUploadCount") + .HasColumnType("int"); + + b.Property("RageQuitCount") + .HasColumnType("int"); + + b.Property("RealmId") + .HasColumnType("int"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.Property("ToonId") + .HasColumnType("int"); + + b.Property("UploaderId") + .HasColumnType("int"); + + b.HasKey("PlayerId"); + + b.HasIndex("UploaderId"); + + b.HasIndex("RegionId", "RealmId", "ToonId") + .IsUnique(); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRating", b => + { + b.Property("PlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerRatingId")); + + b.Property("ArcadeDefeatsSinceLastUpload") + .HasColumnType("int"); + + b.Property("Confidence") + .HasColumnType("double"); + + b.Property("Consistency") + .HasColumnType("double"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("IsUploader") + .HasColumnType("tinyint(1)"); + + b.Property("Main") + .HasColumnType("int"); + + b.Property("MainCount") + .HasColumnType("int"); + + b.Property("Mvp") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("Pos") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("double"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("TeamGames") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("PlayerRatingId"); + + b.HasIndex("PlayerId"); + + b.HasIndex("RatingType"); + + b.ToTable("PlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRatingChange", b => + { + b.Property("PlayerRatingChangeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerRatingChangeId")); + + b.Property("Change10d") + .HasColumnType("float"); + + b.Property("Change24h") + .HasColumnType("float"); + + b.Property("Change30d") + .HasColumnType("float"); + + b.Property("PlayerRatingId") + .HasColumnType("int"); + + b.HasKey("PlayerRatingChangeId"); + + b.HasIndex("PlayerRatingId") + .IsUnique(); + + b.ToTable("PlayerRatingChanges"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerUpgrade", b => + { + b.Property("PlayerUpgradeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerUpgradeId")); + + b.Property("Gameloop") + .HasColumnType("int"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.Property("UpgradeId") + .HasColumnType("int"); + + b.HasKey("PlayerUpgradeId"); + + b.HasIndex("ReplayPlayerId"); + + b.HasIndex("UpgradeId"); + + b.ToTable("PlayerUpgrades"); + }); + + modelBuilder.Entity("dsstats.db8.RepPlayerRating", b => + { + b.Property("RepPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("RepPlayerRatingId")); + + b.Property("Confidence") + .HasColumnType("float"); + + b.Property("Consistency") + .HasColumnType("float"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("float"); + + b.Property("RatingChange") + .HasColumnType("float"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.Property("ReplayRatingInfoId") + .HasColumnType("int"); + + b.HasKey("RepPlayerRatingId"); + + b.HasIndex("ReplayPlayerId") + .IsUnique(); + + b.HasIndex("ReplayRatingInfoId"); + + b.ToTable("RepPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.Replay", b => + { + b.Property("ReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayId")); + + b.Property("Bunker") + .HasColumnType("int"); + + b.Property("Cannon") + .HasColumnType("int"); + + b.Property("CommandersTeam1") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommandersTeam2") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DefaultFilter") + .HasColumnType("tinyint(1)"); + + b.Property("Downloads") + .HasColumnType("int"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("varchar(500)"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("GameTime") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Imported") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Maxkillsum") + .HasColumnType("int"); + + b.Property("Maxleaver") + .HasColumnType("int"); + + b.Property("Middle") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("Minarmy") + .HasColumnType("int"); + + b.Property("Minincome") + .HasColumnType("int"); + + b.Property("Minkillsum") + .HasColumnType("int"); + + b.Property("Objective") + .HasColumnType("int"); + + b.Property("PlayerPos") + .HasColumnType("int"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.Property("Playercount") + .HasColumnType("tinyint unsigned"); + + b.Property("ReplayEventId") + .HasColumnType("int"); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("char(64)") + .IsFixedLength(); + + b.Property("ResultCorrected") + .HasColumnType("tinyint(1)"); + + b.Property("TournamentEdition") + .HasColumnType("tinyint(1)"); + + b.Property("Uploaded") + .HasColumnType("tinyint(1)"); + + b.Property("Views") + .HasColumnType("int"); + + b.Property("WinnerTeam") + .HasColumnType("int"); + + b.HasKey("ReplayId"); + + b.HasIndex("FileName"); + + b.HasIndex("GameTime"); + + b.HasIndex("Imported"); + + b.HasIndex("Maxkillsum"); + + b.HasIndex("ReplayEventId"); + + b.HasIndex("ReplayHash") + .IsUnique(); + + b.HasIndex("GameTime", "GameMode"); + + b.HasIndex("GameTime", "GameMode", "DefaultFilter"); + + b.HasIndex("GameTime", "GameMode", "Maxleaver"); + + b.HasIndex("GameTime", "GameMode", "WinnerTeam"); + + b.ToTable("Replays"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayArcadeMatch", b => + { + b.Property("ReplayArcadeMatchId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayArcadeMatchId")); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("MatchTime") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.HasKey("ReplayArcadeMatchId"); + + b.HasIndex("ArcadeReplayId") + .IsUnique(); + + b.HasIndex("MatchTime"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("ReplayArcadeMatches"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayDownloadCount", b => + { + b.Property("ReplayDownloadCountId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayDownloadCountId")); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("ReplayDownloadCountId"); + + b.ToTable("ReplayDownloadCounts"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayEvent", b => + { + b.Property("ReplayEventId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayEventId")); + + b.Property("Ban1") + .HasColumnType("int"); + + b.Property("Ban2") + .HasColumnType("int"); + + b.Property("Ban3") + .HasColumnType("int"); + + b.Property("Ban4") + .HasColumnType("int"); + + b.Property("Ban5") + .HasColumnType("int"); + + b.Property("EventId") + .HasColumnType("int"); + + b.Property("Round") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("RunnerTeam") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("WinnerTeam") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("ReplayEventId"); + + b.HasIndex("EventId"); + + b.ToTable("ReplayEvents"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayPlayer", b => + { + b.Property("ReplayPlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayPlayerId")); + + b.Property("APM") + .HasColumnType("int"); + + b.Property("Army") + .HasColumnType("int"); + + b.Property("Clan") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("DidNotUpload") + .HasColumnType("tinyint(1)"); + + b.Property("Downloads") + .HasColumnType("int"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Income") + .HasColumnType("int"); + + b.Property("IsLeaver") + .HasColumnType("tinyint(1)"); + + b.Property("IsUploader") + .HasColumnType("tinyint(1)"); + + b.Property("Kills") + .HasColumnType("int"); + + b.Property("LastSpawnHash") + .HasMaxLength(64) + .HasColumnType("char(64)") + .IsFixedLength(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OppRace") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.Property("Race") + .HasColumnType("int"); + + b.Property("Refineries") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.Property("Team") + .HasColumnType("int"); + + b.Property("TierUpgrades") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("UpgradeId") + .HasColumnType("int"); + + b.Property("UpgradesSpent") + .HasColumnType("int"); + + b.Property("Views") + .HasColumnType("int"); + + b.HasKey("ReplayPlayerId"); + + b.HasIndex("Kills"); + + b.HasIndex("LastSpawnHash") + .IsUnique(); + + b.HasIndex("Name"); + + b.HasIndex("PlayerId"); + + b.HasIndex("Race"); + + b.HasIndex("ReplayId"); + + b.HasIndex("UpgradeId"); + + b.HasIndex("IsUploader", "Team"); + + b.HasIndex("Race", "OppRace"); + + b.ToTable("ReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayRating", b => + { + b.Property("ReplayRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayRatingId")); + + b.Property("AvgRating") + .HasColumnType("int"); + + b.Property("ExpectationToWin") + .HasColumnType("float"); + + b.Property("IsPreRating") + .HasColumnType("tinyint(1)"); + + b.Property("LeaverType") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.HasKey("ReplayRatingId"); + + b.HasIndex("RatingType"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("ReplayRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayViewCount", b => + { + b.Property("ReplayViewCountId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayViewCountId")); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("ReplayViewCountId"); + + b.ToTable("ReplayViewCounts"); + }); + + modelBuilder.Entity("dsstats.db8.SkipReplay", b => + { + b.Property("SkipReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SkipReplayId")); + + b.Property("Path") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("varchar(500)"); + + b.HasKey("SkipReplayId"); + + b.ToTable("SkipReplays"); + }); + + modelBuilder.Entity("dsstats.db8.Spawn", b => + { + b.Property("SpawnId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SpawnId")); + + b.Property("ArmyValue") + .HasColumnType("int"); + + b.Property("Breakpoint") + .HasColumnType("int"); + + b.Property("Gameloop") + .HasColumnType("int"); + + b.Property("GasCount") + .HasColumnType("int"); + + b.Property("Income") + .HasColumnType("int"); + + b.Property("KilledValue") + .HasColumnType("int"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.Property("UpgradeSpent") + .HasColumnType("int"); + + b.HasKey("SpawnId"); + + b.HasIndex("ReplayPlayerId"); + + b.ToTable("Spawns"); + }); + + modelBuilder.Entity("dsstats.db8.SpawnUnit", b => + { + b.Property("SpawnUnitId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SpawnUnitId")); + + b.Property("Count") + .HasColumnType("tinyint unsigned"); + + b.Property("Poss") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("SpawnId") + .HasColumnType("int"); + + b.Property("UnitId") + .HasColumnType("int"); + + b.HasKey("SpawnUnitId"); + + b.HasIndex("SpawnId"); + + b.HasIndex("UnitId"); + + b.ToTable("SpawnUnits"); + }); + + modelBuilder.Entity("dsstats.db8.StreakInfo", b => + { + b.Property("LongestStreak") + .HasColumnType("double"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.ToTable("StreakInfos"); + }); + + modelBuilder.Entity("dsstats.db8.Unit", b => + { + b.Property("UnitId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UnitId")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("UnitId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Units"); + }); + + modelBuilder.Entity("dsstats.db8.Upgrade", b => + { + b.Property("UpgradeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UpgradeId")); + + b.Property("Cost") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("UpgradeId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Upgrades"); + }); + + modelBuilder.Entity("dsstats.db8.Uploader", b => + { + b.Property("UploaderId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UploaderId")); + + b.Property("AppGuid") + .HasColumnType("char(36)"); + + b.Property("AppVersion") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("LatestReplay") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestUpload") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("MainCommander") + .HasColumnType("int"); + + b.Property("MainCount") + .HasColumnType("int"); + + b.Property("Mvp") + .HasColumnType("int"); + + b.Property("TeamGames") + .HasColumnType("int"); + + b.Property("UploadDisabledCount") + .HasColumnType("int"); + + b.Property("UploadIsDisabled") + .HasColumnType("tinyint(1)"); + + b.Property("UploadLastDisabled") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("UploaderId"); + + b.HasIndex("AppGuid") + .IsUnique(); + + b.ToTable("Uploaders"); + }); + + modelBuilder.Entity("DsAbilityDsUnit", b => + { + b.HasOne("dsstats.db8.DsAbility", null) + .WithMany() + .HasForeignKey("AbilitiesDsAbilityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.DsUnit", null) + .WithMany() + .HasForeignKey("DsUnitsDsUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ReplayUploader", b => + { + b.HasOne("dsstats.db8.Replay", null) + .WithMany() + .HasForeignKey("ReplaysReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Uploader", null) + .WithMany() + .HasForeignKey("UploadersUploaderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRating", b => + { + b.HasOne("dsstats.db8.ArcadePlayer", "ArcadePlayer") + .WithMany("ArcadePlayerRatings") + .HasForeignKey("ArcadePlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadePlayer"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRatingChange", b => + { + b.HasOne("dsstats.db8.ArcadePlayerRating", "ArcadePlayerRating") + .WithOne("ArcadePlayerRatingChange") + .HasForeignKey("dsstats.db8.ArcadePlayerRatingChange", "ArcadePlayerRatingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadePlayerRating"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayer", b => + { + b.HasOne("dsstats.db8.ArcadePlayer", "ArcadePlayer") + .WithMany("ArcadeReplayPlayers") + .HasForeignKey("ArcadePlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.ArcadeReplay", "ArcadeReplay") + .WithMany("ArcadeReplayPlayers") + .HasForeignKey("ArcadeReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadePlayer"); + + b.Navigation("ArcadeReplay"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayerRating", b => + { + b.HasOne("dsstats.db8.ArcadeReplayPlayer", "ReplayPlayer") + .WithOne("ArcadeReplayPlayerRating") + .HasForeignKey("dsstats.db8.ArcadeReplayPlayerRating", "ArcadeReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.ArcadeReplayRating", "ArcadeReplayRating") + .WithMany("ArcadeReplayPlayerRatings") + .HasForeignKey("ArcadeReplayRatingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadeReplayRating"); + + b.Navigation("ReplayPlayer"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayRating", b => + { + b.HasOne("dsstats.db8.ArcadeReplay", "ArcadeReplay") + .WithOne("ArcadeReplayRating") + .HasForeignKey("dsstats.db8.ArcadeReplayRating", "ArcadeReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadeReplay"); + }); + + modelBuilder.Entity("dsstats.db8.BattleNetInfo", b => + { + b.HasOne("dsstats.db8.Uploader", "Uploader") + .WithMany("BattleNetInfos") + .HasForeignKey("UploaderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("dsstats.db8.BonusDamage", b => + { + b.HasOne("dsstats.db8.DsWeapon", "DsWeapon") + .WithMany("BonusDamages") + .HasForeignKey("DsWeaponId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DsWeapon"); + }); + + modelBuilder.Entity("dsstats.db8.ComboPlayerRating", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayPlayerRating", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithOne("ComboReplayPlayerRating") + .HasForeignKey("dsstats.db8.ComboReplayPlayerRating", "ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayRating", b => + { + b.HasOne("dsstats.db8.Replay", "Replay") + .WithOne("ComboReplayRating") + .HasForeignKey("dsstats.db8.ComboReplayRating", "ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("dsstats.db8.DsUpgrade", b => + { + b.HasOne("dsstats.db8.DsUnit", null) + .WithMany("Upgrades") + .HasForeignKey("DsUnitId"); + }); + + modelBuilder.Entity("dsstats.db8.DsWeapon", b => + { + b.HasOne("dsstats.db8.DsUnit", "DsUnit") + .WithMany("Weapons") + .HasForeignKey("DsUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DsUnit"); + }); + + modelBuilder.Entity("dsstats.db8.IhSessionPlayer", b => + { + b.HasOne("dsstats.db8.IhSession", "IhSession") + .WithMany("IhSessionPlayers") + .HasForeignKey("IhSessionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IhSession"); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.NoUploadResult", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.Player", b => + { + b.HasOne("dsstats.db8.Uploader", "Uploader") + .WithMany("Players") + .HasForeignKey("UploaderId"); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRating", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany("PlayerRatings") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRatingChange", b => + { + b.HasOne("dsstats.db8.PlayerRating", "PlayerRating") + .WithOne("PlayerRatingChange") + .HasForeignKey("dsstats.db8.PlayerRatingChange", "PlayerRatingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlayerRating"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerUpgrade", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithMany("Upgrades") + .HasForeignKey("ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Upgrade", "Upgrade") + .WithMany() + .HasForeignKey("UpgradeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + + b.Navigation("Upgrade"); + }); + + modelBuilder.Entity("dsstats.db8.RepPlayerRating", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithOne("ReplayPlayerRatingInfo") + .HasForeignKey("dsstats.db8.RepPlayerRating", "ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.ReplayRating", "ReplayRatingInfo") + .WithMany("RepPlayerRatings") + .HasForeignKey("ReplayRatingInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + + b.Navigation("ReplayRatingInfo"); + }); + + modelBuilder.Entity("dsstats.db8.Replay", b => + { + b.HasOne("dsstats.db8.ReplayEvent", "ReplayEvent") + .WithMany("Replays") + .HasForeignKey("ReplayEventId"); + + b.Navigation("ReplayEvent"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayEvent", b => + { + b.HasOne("dsstats.db8.Event", "Event") + .WithMany("ReplayEvents") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayPlayer", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany("ReplayPlayers") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Replay", "Replay") + .WithMany("ReplayPlayers") + .HasForeignKey("ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Upgrade", null) + .WithMany("ReplayPlayers") + .HasForeignKey("UpgradeId"); + + b.Navigation("Player"); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayRating", b => + { + b.HasOne("dsstats.db8.Replay", "Replay") + .WithOne("ReplayRatingInfo") + .HasForeignKey("dsstats.db8.ReplayRating", "ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("dsstats.db8.Spawn", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithMany("Spawns") + .HasForeignKey("ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + }); + + modelBuilder.Entity("dsstats.db8.SpawnUnit", b => + { + b.HasOne("dsstats.db8.Spawn", "Spawn") + .WithMany("Units") + .HasForeignKey("SpawnId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Unit", "Unit") + .WithMany() + .HasForeignKey("UnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Spawn"); + + b.Navigation("Unit"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayer", b => + { + b.Navigation("ArcadePlayerRatings"); + + b.Navigation("ArcadeReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRating", b => + { + b.Navigation("ArcadePlayerRatingChange"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplay", b => + { + b.Navigation("ArcadeReplayPlayers"); + + b.Navigation("ArcadeReplayRating"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayer", b => + { + b.Navigation("ArcadeReplayPlayerRating"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayRating", b => + { + b.Navigation("ArcadeReplayPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.DsUnit", b => + { + b.Navigation("Upgrades"); + + b.Navigation("Weapons"); + }); + + modelBuilder.Entity("dsstats.db8.DsWeapon", b => + { + b.Navigation("BonusDamages"); + }); + + modelBuilder.Entity("dsstats.db8.Event", b => + { + b.Navigation("ReplayEvents"); + }); + + modelBuilder.Entity("dsstats.db8.IhSession", b => + { + b.Navigation("IhSessionPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.Player", b => + { + b.Navigation("PlayerRatings"); + + b.Navigation("ReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRating", b => + { + b.Navigation("PlayerRatingChange"); + }); + + modelBuilder.Entity("dsstats.db8.Replay", b => + { + b.Navigation("ComboReplayRating"); + + b.Navigation("ReplayPlayers"); + + b.Navigation("ReplayRatingInfo"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayEvent", b => + { + b.Navigation("Replays"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayPlayer", b => + { + b.Navigation("ComboReplayPlayerRating"); + + b.Navigation("ReplayPlayerRatingInfo"); + + b.Navigation("Spawns"); + + b.Navigation("Upgrades"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayRating", b => + { + b.Navigation("RepPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.Spawn", b => + { + b.Navigation("Units"); + }); + + modelBuilder.Entity("dsstats.db8.Upgrade", b => + { + b.Navigation("ReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.Uploader", b => + { + b.Navigation("BattleNetInfos"); + + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MysqlMigrations/Migrations/20240714155954_ReplayArcadeMatch.cs b/src/MysqlMigrations/Migrations/20240714155954_ReplayArcadeMatch.cs new file mode 100644 index 00000000..c7134d3c --- /dev/null +++ b/src/MysqlMigrations/Migrations/20240714155954_ReplayArcadeMatch.cs @@ -0,0 +1,56 @@ +using System; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MysqlMigrations.Migrations +{ + /// + public partial class ReplayArcadeMatch : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "ReplayArcadeMatches", + columns: table => new + { + ReplayArcadeMatchId = table.Column(type: "int", nullable: false) + .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn), + ReplayId = table.Column(type: "int", nullable: false), + ArcadeReplayId = table.Column(type: "int", nullable: false), + MatchTime = table.Column(type: "datetime(0)", precision: 0, nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_ReplayArcadeMatches", x => x.ReplayArcadeMatchId); + }) + .Annotation("MySql:CharSet", "utf8mb4"); + + migrationBuilder.CreateIndex( + name: "IX_ReplayArcadeMatches_ArcadeReplayId", + table: "ReplayArcadeMatches", + column: "ArcadeReplayId", + unique: true); + + migrationBuilder.CreateIndex( + name: "IX_ReplayArcadeMatches_MatchTime", + table: "ReplayArcadeMatches", + column: "MatchTime"); + + migrationBuilder.CreateIndex( + name: "IX_ReplayArcadeMatches_ReplayId", + table: "ReplayArcadeMatches", + column: "ReplayId", + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "ReplayArcadeMatches"); + } + } +} diff --git a/src/MysqlMigrations/Migrations/20240715075452_MaterializedArcadeReplaysIndex.Designer.cs b/src/MysqlMigrations/Migrations/20240715075452_MaterializedArcadeReplaysIndex.Designer.cs new file mode 100644 index 00000000..a737f958 --- /dev/null +++ b/src/MysqlMigrations/Migrations/20240715075452_MaterializedArcadeReplaysIndex.Designer.cs @@ -0,0 +1,2402 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using dsstats.db8; + +#nullable disable + +namespace MysqlMigrations.Migrations +{ + [DbContext(typeof(ReplayContext))] + [Migration("20240715075452_MaterializedArcadeReplaysIndex")] + partial class MaterializedArcadeReplaysIndex + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 64); + + MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); + + modelBuilder.Entity("DsAbilityDsUnit", b => + { + b.Property("AbilitiesDsAbilityId") + .HasColumnType("int"); + + b.Property("DsUnitsDsUnitId") + .HasColumnType("int"); + + b.HasKey("AbilitiesDsAbilityId", "DsUnitsDsUnitId"); + + b.HasIndex("DsUnitsDsUnitId"); + + b.ToTable("DsAbilityDsUnit"); + }); + + modelBuilder.Entity("ReplayUploader", b => + { + b.Property("ReplaysReplayId") + .HasColumnType("int"); + + b.Property("UploadersUploaderId") + .HasColumnType("int"); + + b.HasKey("ReplaysReplayId", "UploadersUploaderId"); + + b.HasIndex("UploadersUploaderId"); + + b.ToTable("UploaderReplays", (string)null); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayer", b => + { + b.Property("ArcadePlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadePlayerId")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("ProfileId") + .HasColumnType("int"); + + b.Property("RealmId") + .HasColumnType("int"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.HasKey("ArcadePlayerId"); + + b.HasIndex("Name"); + + b.HasIndex("RegionId", "RealmId", "ProfileId") + .IsUnique(); + + b.ToTable("ArcadePlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRating", b => + { + b.Property("ArcadePlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadePlayerRatingId")); + + b.Property("ArcadePlayerId") + .HasColumnType("int"); + + b.Property("Confidence") + .HasColumnType("double"); + + b.Property("Consistency") + .HasColumnType("double"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("IsUploader") + .HasColumnType("tinyint(1)"); + + b.Property("Main") + .HasColumnType("int"); + + b.Property("MainCount") + .HasColumnType("int"); + + b.Property("Mvp") + .HasColumnType("int"); + + b.Property("Pos") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("double"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("TeamGames") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("ArcadePlayerRatingId"); + + b.HasIndex("ArcadePlayerId"); + + b.HasIndex("RatingType"); + + b.ToTable("ArcadePlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRatingChange", b => + { + b.Property("ArcadePlayerRatingChangeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadePlayerRatingChangeId")); + + b.Property("ArcadePlayerRatingId") + .HasColumnType("int"); + + b.Property("Change10d") + .HasColumnType("float"); + + b.Property("Change24h") + .HasColumnType("float"); + + b.Property("Change30d") + .HasColumnType("float"); + + b.HasKey("ArcadePlayerRatingChangeId"); + + b.HasIndex("ArcadePlayerRatingId") + .IsUnique(); + + b.ToTable("ArcadePlayerRatingChanges"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplay", b => + { + b.Property("ArcadeReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayId")); + + b.Property("BnetBucketId") + .HasColumnType("bigint"); + + b.Property("BnetRecordId") + .HasColumnType("bigint"); + + b.Property("CreatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("Imported") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("PlayerCount") + .HasColumnType("int"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.Property("TournamentEdition") + .HasColumnType("tinyint(1)"); + + b.Property("WinnerTeam") + .HasColumnType("int"); + + b.HasKey("ArcadeReplayId"); + + b.HasIndex("ReplayHash"); + + b.HasIndex("GameMode", "CreatedAt"); + + b.HasIndex("RegionId", "BnetBucketId", "BnetRecordId") + .IsUnique(); + + b.HasIndex("RegionId", "GameMode", "CreatedAt"); + + b.ToTable("ArcadeReplays"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayer", b => + { + b.Property("ArcadeReplayPlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayPlayerId")); + + b.Property("ArcadePlayerId") + .HasColumnType("int"); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("Discriminator") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.Property("SlotNumber") + .HasColumnType("int"); + + b.Property("Team") + .HasColumnType("int"); + + b.HasKey("ArcadeReplayPlayerId"); + + b.HasIndex("ArcadePlayerId"); + + b.HasIndex("ArcadeReplayId"); + + b.ToTable("ArcadeReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayerRating", b => + { + b.Property("ArcadeReplayPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayPlayerRatingId")); + + b.Property("ArcadeReplayPlayerId") + .HasColumnType("int"); + + b.Property("ArcadeReplayRatingId") + .HasColumnType("int"); + + b.Property("Confidence") + .HasColumnType("float"); + + b.Property("Consistency") + .HasColumnType("float"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("float"); + + b.Property("RatingChange") + .HasColumnType("float"); + + b.HasKey("ArcadeReplayPlayerRatingId"); + + b.HasIndex("ArcadeReplayPlayerId") + .IsUnique(); + + b.HasIndex("ArcadeReplayRatingId"); + + b.ToTable("ArcadeReplayPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayRating", b => + { + b.Property("ArcadeReplayRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ArcadeReplayRatingId")); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("AvgRating") + .HasColumnType("int"); + + b.Property("ExpectationToWin") + .HasColumnType("float"); + + b.Property("LeaverType") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.HasKey("ArcadeReplayRatingId"); + + b.HasIndex("ArcadeReplayId") + .IsUnique(); + + b.ToTable("ArcadeReplayRatings"); + }); + + modelBuilder.Entity("dsstats.db8.BattleNetInfo", b => + { + b.Property("BattleNetInfoId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("BattleNetInfoId")); + + b.Property("BattleNetId") + .HasColumnType("int"); + + b.Property("UploaderId") + .HasColumnType("int"); + + b.HasKey("BattleNetInfoId"); + + b.HasIndex("UploaderId"); + + b.ToTable("BattleNetInfos"); + }); + + modelBuilder.Entity("dsstats.db8.BonusDamage", b => + { + b.Property("BonusDamageId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("BonusDamageId")); + + b.Property("Damage") + .HasColumnType("int"); + + b.Property("DsWeaponId") + .HasColumnType("int"); + + b.Property("PerUpgrade") + .HasColumnType("int"); + + b.Property("UnitType") + .HasColumnType("int"); + + b.HasKey("BonusDamageId"); + + b.HasIndex("DsWeaponId"); + + b.HasIndex("UnitType"); + + b.ToTable("BonusDamages"); + }); + + modelBuilder.Entity("dsstats.db8.ComboPlayerRating", b => + { + b.Property("ComboPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ComboPlayerRatingId")); + + b.Property("Confidence") + .HasColumnType("double"); + + b.Property("Consistency") + .HasColumnType("double"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("Pos") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("double"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("ComboPlayerRatingId"); + + b.HasIndex("PlayerId"); + + b.HasIndex("RatingType"); + + b.ToTable("ComboPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayPlayerRating", b => + { + b.Property("ComboReplayPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ComboReplayPlayerRatingId")); + + b.Property("Change") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("Confidence") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("Consistency") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("int"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.HasKey("ComboReplayPlayerRatingId"); + + b.HasIndex("ReplayPlayerId") + .IsUnique(); + + b.ToTable("ComboReplayPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayRating", b => + { + b.Property("ComboReplayRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ComboReplayRatingId")); + + b.Property("AvgRating") + .HasColumnType("int"); + + b.Property("ExpectationToWin") + .HasPrecision(5, 2) + .HasColumnType("double"); + + b.Property("IsPreRating") + .HasColumnType("tinyint(1)"); + + b.Property("LeaverType") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.HasKey("ComboReplayRatingId"); + + b.HasIndex("RatingType"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("ComboReplayRatings"); + }); + + modelBuilder.Entity("dsstats.db8.CommanderMmr", b => + { + b.Property("CommanderMmrId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("CommanderMmrId")); + + b.Property("AntiSynergyMmr") + .HasColumnType("double"); + + b.Property("OppRace") + .HasColumnType("int"); + + b.Property("Race") + .HasColumnType("int"); + + b.Property("SynergyMmr") + .HasColumnType("double"); + + b.HasKey("CommanderMmrId"); + + b.HasIndex("Race", "OppRace"); + + b.ToTable("CommanderMmrs"); + }); + + modelBuilder.Entity("dsstats.db8.DsAbility", b => + { + b.Property("DsAbilityId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsAbilityId")); + + b.Property("AbilityTarget") + .HasColumnType("int"); + + b.Property("AoeRadius") + .HasColumnType("float"); + + b.Property("CastRange") + .HasColumnType("int"); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("Cooldown") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(310) + .HasColumnType("varchar(310)"); + + b.Property("EnergyCost") + .HasColumnType("float"); + + b.Property("GlobalTimer") + .HasColumnType("tinyint(1)"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Requirements") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.HasKey("DsAbilityId"); + + b.HasIndex("Name"); + + b.ToTable("DsAbilities"); + }); + + modelBuilder.Entity("dsstats.db8.DsPickBan", b => + { + b.Property("DsPickBanId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsPickBanId")); + + b.Property("Bans") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("PickBanMode") + .HasColumnType("int"); + + b.Property("Picks") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Time") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.HasKey("DsPickBanId"); + + b.ToTable("DsPickBans"); + }); + + modelBuilder.Entity("dsstats.db8.DsUnit", b => + { + b.Property("DsUnitId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsUnitId")); + + b.Property("Armor") + .HasColumnType("int"); + + b.Property("Color") + .HasColumnType("int"); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("Cost") + .HasColumnType("int"); + + b.Property("EnergyRegen") + .HasColumnType("float"); + + b.Property("HealthRegen") + .HasColumnType("float"); + + b.Property("Life") + .HasColumnType("int"); + + b.Property("MaxEnergy") + .HasColumnType("int"); + + b.Property("MovementType") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("ShieldArmor") + .HasColumnType("int"); + + b.Property("Shields") + .HasColumnType("int"); + + b.Property("Size") + .HasColumnType("int"); + + b.Property("Speed") + .HasColumnType("float"); + + b.Property("StartingEnergy") + .HasColumnType("int"); + + b.Property("Tier") + .HasColumnType("int"); + + b.Property("UnitId") + .HasColumnType("int"); + + b.Property("UnitType") + .HasColumnType("int"); + + b.HasKey("DsUnitId"); + + b.HasIndex("Commander"); + + b.HasIndex("Name"); + + b.HasIndex("Name", "Commander"); + + b.ToTable("DsUnits"); + }); + + modelBuilder.Entity("dsstats.db8.DsUpdate", b => + { + b.Property("DsUpdateId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsUpdateId")); + + b.Property("Change") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("DiscordId") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Time") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.HasKey("DsUpdateId"); + + b.HasIndex("Time"); + + b.ToTable("DsUpdates"); + }); + + modelBuilder.Entity("dsstats.db8.DsUpgrade", b => + { + b.Property("DsUpgradeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsUpgradeId")); + + b.Property("Commander") + .HasColumnType("int"); + + b.Property("Cost") + .HasColumnType("int"); + + b.Property("Description") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("DsUnitId") + .HasColumnType("int"); + + b.Property("RequiredTier") + .HasColumnType("int"); + + b.Property("Upgrade") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.HasKey("DsUpgradeId"); + + b.HasIndex("DsUnitId"); + + b.HasIndex("Upgrade"); + + b.ToTable("DsUpgrades"); + }); + + modelBuilder.Entity("dsstats.db8.DsWeapon", b => + { + b.Property("DsWeaponId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("DsWeaponId")); + + b.Property("AttackSpeed") + .HasColumnType("float"); + + b.Property("Attacks") + .HasColumnType("int"); + + b.Property("CanTarget") + .HasColumnType("int"); + + b.Property("Damage") + .HasColumnType("int"); + + b.Property("DamagePerUpgrade") + .HasColumnType("int"); + + b.Property("DsUnitId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("Range") + .HasColumnType("float"); + + b.HasKey("DsWeaponId"); + + b.HasIndex("DsUnitId"); + + b.ToTable("DsWeapons"); + }); + + modelBuilder.Entity("dsstats.db8.Event", b => + { + b.Property("EventId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("EventId")); + + b.Property("EventGuid") + .HasColumnType("char(36)"); + + b.Property("EventStart") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("WinnerTeam") + .HasColumnType("longtext"); + + b.HasKey("EventId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Events"); + }); + + modelBuilder.Entity("dsstats.db8.Faq", b => + { + b.Property("FaqId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("FaqId")); + + b.Property("Answer") + .IsRequired() + .HasMaxLength(400) + .HasColumnType("varchar(400)"); + + b.Property("CreatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("CreatedBy") + .HasMaxLength(20) + .HasColumnType("varchar(20)"); + + b.Property("Level") + .HasColumnType("int"); + + b.Property("Question") + .IsRequired() + .HasMaxLength(100) + .HasColumnType("varchar(100)"); + + b.Property("UpdatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Upvotes") + .HasColumnType("int"); + + b.HasKey("FaqId"); + + b.HasIndex("Question"); + + b.ToTable("Faqs"); + }); + + modelBuilder.Entity("dsstats.db8.FaqVote", b => + { + b.Property("FaqVoteId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("FaqVoteId")); + + b.Property("FaqId") + .HasColumnType("int"); + + b.HasKey("FaqVoteId"); + + b.ToTable("FaqVotes"); + }); + + modelBuilder.Entity("dsstats.db8.FunStatsMemory", b => + { + b.Property("FunStatsMemoryId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("FunStatsMemoryId")); + + b.Property("AvgGameDuration") + .HasColumnType("int"); + + b.Property("Created") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("FirstReplay") + .HasColumnType("longtext"); + + b.Property("GreatestArmyReplay") + .HasColumnType("longtext"); + + b.Property("GreatestComebackReplay") + .HasColumnType("longtext"); + + b.Property("MostCompetitiveReplay") + .HasColumnType("longtext"); + + b.Property("MostUpgradesReplay") + .HasColumnType("longtext"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("TimePeriod") + .HasColumnType("int"); + + b.Property("TotalTimePlayed") + .HasColumnType("bigint"); + + b.Property("UnitCountLeast") + .HasColumnType("int"); + + b.Property("UnitCountMost") + .HasColumnType("int"); + + b.Property("UnitNameLeast") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("UnitNameMost") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("FunStatsMemoryId"); + + b.ToTable("FunStatMemories"); + }); + + modelBuilder.Entity("dsstats.db8.GroupByHelper", b => + { + b.Property("Count") + .HasColumnType("int"); + + b.Property("Group") + .HasColumnType("tinyint(1)") + .HasColumnName("Name"); + + b.ToTable((string)null); + + b.ToView("GroupByHelper", (string)null); + }); + + modelBuilder.Entity("dsstats.db8.IhSession", b => + { + b.Property("IhSessionId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("IhSessionId")); + + b.Property("Closed") + .HasColumnType("tinyint(1)"); + + b.Property("Created") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("GroupId") + .HasColumnType("char(36)"); + + b.Property("GroupState") + .HasColumnType("longtext"); + + b.Property("GroupStateV2") + .HasColumnType("longtext"); + + b.Property("Players") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.HasKey("IhSessionId"); + + b.HasIndex("GroupId") + .IsUnique(); + + b.ToTable("IhSessions"); + }); + + modelBuilder.Entity("dsstats.db8.IhSessionPlayer", b => + { + b.Property("IhSessionPlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("IhSessionPlayerId")); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("IhSessionId") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Obs") + .HasColumnType("int"); + + b.Property("Performance") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("RatingEnd") + .HasColumnType("int"); + + b.Property("RatingStart") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("IhSessionPlayerId"); + + b.HasIndex("IhSessionId"); + + b.HasIndex("PlayerId"); + + b.ToTable("IhSessionPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.MaterializedArcadeReplay", b => + { + b.Property("MaterializedArcadeReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("MaterializedArcadeReplayId")); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("CreatedAt") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("WinnerTeam") + .HasColumnType("int"); + + b.HasKey("MaterializedArcadeReplayId"); + + b.HasIndex("CreatedAt"); + + b.ToTable("MaterializedArcadeReplays"); + }); + + modelBuilder.Entity("dsstats.db8.NoUploadResult", b => + { + b.Property("NoUploadResultId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("NoUploadResultId")); + + b.Property("Created") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestNoUpload") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestReplay") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestUpload") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("NoUploadDefeats") + .HasColumnType("int"); + + b.Property("NoUploadTotal") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("TotalReplays") + .HasColumnType("int"); + + b.HasKey("NoUploadResultId"); + + b.HasIndex("PlayerId"); + + b.ToTable("NoUploadResults"); + }); + + modelBuilder.Entity("dsstats.db8.Player", b => + { + b.Property("PlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerId")); + + b.Property("ArcadeDefeatsSinceLastUpload") + .HasColumnType("int"); + + b.Property("DisconnectCount") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("NotUploadCount") + .HasColumnType("int"); + + b.Property("RageQuitCount") + .HasColumnType("int"); + + b.Property("RealmId") + .HasColumnType("int"); + + b.Property("RegionId") + .HasColumnType("int"); + + b.Property("ToonId") + .HasColumnType("int"); + + b.Property("UploaderId") + .HasColumnType("int"); + + b.HasKey("PlayerId"); + + b.HasIndex("UploaderId"); + + b.HasIndex("RegionId", "RealmId", "ToonId") + .IsUnique(); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRating", b => + { + b.Property("PlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerRatingId")); + + b.Property("ArcadeDefeatsSinceLastUpload") + .HasColumnType("int"); + + b.Property("Confidence") + .HasColumnType("double"); + + b.Property("Consistency") + .HasColumnType("double"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("IsUploader") + .HasColumnType("tinyint(1)"); + + b.Property("Main") + .HasColumnType("int"); + + b.Property("MainCount") + .HasColumnType("int"); + + b.Property("Mvp") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("Pos") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("double"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("TeamGames") + .HasColumnType("int"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("PlayerRatingId"); + + b.HasIndex("PlayerId"); + + b.HasIndex("RatingType"); + + b.ToTable("PlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRatingChange", b => + { + b.Property("PlayerRatingChangeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerRatingChangeId")); + + b.Property("Change10d") + .HasColumnType("float"); + + b.Property("Change24h") + .HasColumnType("float"); + + b.Property("Change30d") + .HasColumnType("float"); + + b.Property("PlayerRatingId") + .HasColumnType("int"); + + b.HasKey("PlayerRatingChangeId"); + + b.HasIndex("PlayerRatingId") + .IsUnique(); + + b.ToTable("PlayerRatingChanges"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerUpgrade", b => + { + b.Property("PlayerUpgradeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("PlayerUpgradeId")); + + b.Property("Gameloop") + .HasColumnType("int"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.Property("UpgradeId") + .HasColumnType("int"); + + b.HasKey("PlayerUpgradeId"); + + b.HasIndex("ReplayPlayerId"); + + b.HasIndex("UpgradeId"); + + b.ToTable("PlayerUpgrades"); + }); + + modelBuilder.Entity("dsstats.db8.RepPlayerRating", b => + { + b.Property("RepPlayerRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("RepPlayerRatingId")); + + b.Property("Confidence") + .HasColumnType("float"); + + b.Property("Consistency") + .HasColumnType("float"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Rating") + .HasColumnType("float"); + + b.Property("RatingChange") + .HasColumnType("float"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.Property("ReplayRatingInfoId") + .HasColumnType("int"); + + b.HasKey("RepPlayerRatingId"); + + b.HasIndex("ReplayPlayerId") + .IsUnique(); + + b.HasIndex("ReplayRatingInfoId"); + + b.ToTable("RepPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.Replay", b => + { + b.Property("ReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayId")); + + b.Property("Bunker") + .HasColumnType("int"); + + b.Property("Cannon") + .HasColumnType("int"); + + b.Property("CommandersTeam1") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("CommandersTeam2") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("DefaultFilter") + .HasColumnType("tinyint(1)"); + + b.Property("Downloads") + .HasColumnType("int"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("FileName") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("varchar(500)"); + + b.Property("GameMode") + .HasColumnType("int"); + + b.Property("GameTime") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Imported") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Maxkillsum") + .HasColumnType("int"); + + b.Property("Maxleaver") + .HasColumnType("int"); + + b.Property("Middle") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("Minarmy") + .HasColumnType("int"); + + b.Property("Minincome") + .HasColumnType("int"); + + b.Property("Minkillsum") + .HasColumnType("int"); + + b.Property("Objective") + .HasColumnType("int"); + + b.Property("PlayerPos") + .HasColumnType("int"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.Property("Playercount") + .HasColumnType("tinyint unsigned"); + + b.Property("ReplayEventId") + .HasColumnType("int"); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("char(64)") + .IsFixedLength(); + + b.Property("ResultCorrected") + .HasColumnType("tinyint(1)"); + + b.Property("TournamentEdition") + .HasColumnType("tinyint(1)"); + + b.Property("Uploaded") + .HasColumnType("tinyint(1)"); + + b.Property("Views") + .HasColumnType("int"); + + b.Property("WinnerTeam") + .HasColumnType("int"); + + b.HasKey("ReplayId"); + + b.HasIndex("FileName"); + + b.HasIndex("GameTime"); + + b.HasIndex("Imported"); + + b.HasIndex("Maxkillsum"); + + b.HasIndex("ReplayEventId"); + + b.HasIndex("ReplayHash") + .IsUnique(); + + b.HasIndex("GameTime", "GameMode"); + + b.HasIndex("GameTime", "GameMode", "DefaultFilter"); + + b.HasIndex("GameTime", "GameMode", "Maxleaver"); + + b.HasIndex("GameTime", "GameMode", "WinnerTeam"); + + b.ToTable("Replays"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayArcadeMatch", b => + { + b.Property("ReplayArcadeMatchId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayArcadeMatchId")); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("MatchTime") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.HasKey("ReplayArcadeMatchId"); + + b.HasIndex("ArcadeReplayId") + .IsUnique(); + + b.HasIndex("MatchTime"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("ReplayArcadeMatches"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayDownloadCount", b => + { + b.Property("ReplayDownloadCountId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayDownloadCountId")); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("ReplayDownloadCountId"); + + b.ToTable("ReplayDownloadCounts"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayEvent", b => + { + b.Property("ReplayEventId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayEventId")); + + b.Property("Ban1") + .HasColumnType("int"); + + b.Property("Ban2") + .HasColumnType("int"); + + b.Property("Ban3") + .HasColumnType("int"); + + b.Property("Ban4") + .HasColumnType("int"); + + b.Property("Ban5") + .HasColumnType("int"); + + b.Property("EventId") + .HasColumnType("int"); + + b.Property("Round") + .IsRequired() + .HasMaxLength(200) + .HasColumnType("varchar(200)"); + + b.Property("RunnerTeam") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("WinnerTeam") + .IsRequired() + .HasColumnType("longtext"); + + b.HasKey("ReplayEventId"); + + b.HasIndex("EventId"); + + b.ToTable("ReplayEvents"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayPlayer", b => + { + b.Property("ReplayPlayerId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayPlayerId")); + + b.Property("APM") + .HasColumnType("int"); + + b.Property("Army") + .HasColumnType("int"); + + b.Property("Clan") + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("DidNotUpload") + .HasColumnType("tinyint(1)"); + + b.Property("Downloads") + .HasColumnType("int"); + + b.Property("Duration") + .HasColumnType("int"); + + b.Property("GamePos") + .HasColumnType("int"); + + b.Property("Income") + .HasColumnType("int"); + + b.Property("IsLeaver") + .HasColumnType("tinyint(1)"); + + b.Property("IsUploader") + .HasColumnType("tinyint(1)"); + + b.Property("Kills") + .HasColumnType("int"); + + b.Property("LastSpawnHash") + .HasMaxLength(64) + .HasColumnType("char(64)") + .IsFixedLength(); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.Property("OppRace") + .HasColumnType("int"); + + b.Property("PlayerId") + .HasColumnType("int"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.Property("Race") + .HasColumnType("int"); + + b.Property("Refineries") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.Property("Team") + .HasColumnType("int"); + + b.Property("TierUpgrades") + .IsRequired() + .HasMaxLength(300) + .HasColumnType("varchar(300)"); + + b.Property("UpgradeId") + .HasColumnType("int"); + + b.Property("UpgradesSpent") + .HasColumnType("int"); + + b.Property("Views") + .HasColumnType("int"); + + b.HasKey("ReplayPlayerId"); + + b.HasIndex("Kills"); + + b.HasIndex("LastSpawnHash") + .IsUnique(); + + b.HasIndex("Name"); + + b.HasIndex("PlayerId"); + + b.HasIndex("Race"); + + b.HasIndex("ReplayId"); + + b.HasIndex("UpgradeId"); + + b.HasIndex("IsUploader", "Team"); + + b.HasIndex("Race", "OppRace"); + + b.ToTable("ReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayRating", b => + { + b.Property("ReplayRatingId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayRatingId")); + + b.Property("AvgRating") + .HasColumnType("int"); + + b.Property("ExpectationToWin") + .HasColumnType("float"); + + b.Property("IsPreRating") + .HasColumnType("tinyint(1)"); + + b.Property("LeaverType") + .HasColumnType("int"); + + b.Property("RatingType") + .HasColumnType("int"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.HasKey("ReplayRatingId"); + + b.HasIndex("RatingType"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("ReplayRatings"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayViewCount", b => + { + b.Property("ReplayViewCountId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayViewCountId")); + + b.Property("ReplayHash") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("varchar(64)"); + + b.HasKey("ReplayViewCountId"); + + b.ToTable("ReplayViewCounts"); + }); + + modelBuilder.Entity("dsstats.db8.SkipReplay", b => + { + b.Property("SkipReplayId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SkipReplayId")); + + b.Property("Path") + .IsRequired() + .HasMaxLength(500) + .HasColumnType("varchar(500)"); + + b.HasKey("SkipReplayId"); + + b.ToTable("SkipReplays"); + }); + + modelBuilder.Entity("dsstats.db8.Spawn", b => + { + b.Property("SpawnId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SpawnId")); + + b.Property("ArmyValue") + .HasColumnType("int"); + + b.Property("Breakpoint") + .HasColumnType("int"); + + b.Property("Gameloop") + .HasColumnType("int"); + + b.Property("GasCount") + .HasColumnType("int"); + + b.Property("Income") + .HasColumnType("int"); + + b.Property("KilledValue") + .HasColumnType("int"); + + b.Property("ReplayPlayerId") + .HasColumnType("int"); + + b.Property("UpgradeSpent") + .HasColumnType("int"); + + b.HasKey("SpawnId"); + + b.HasIndex("ReplayPlayerId"); + + b.ToTable("Spawns"); + }); + + modelBuilder.Entity("dsstats.db8.SpawnUnit", b => + { + b.Property("SpawnUnitId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("SpawnUnitId")); + + b.Property("Count") + .HasColumnType("tinyint unsigned"); + + b.Property("Poss") + .IsRequired() + .HasMaxLength(4000) + .HasColumnType("varchar(4000)"); + + b.Property("SpawnId") + .HasColumnType("int"); + + b.Property("UnitId") + .HasColumnType("int"); + + b.HasKey("SpawnUnitId"); + + b.HasIndex("SpawnId"); + + b.HasIndex("UnitId"); + + b.ToTable("SpawnUnits"); + }); + + modelBuilder.Entity("dsstats.db8.StreakInfo", b => + { + b.Property("LongestStreak") + .HasColumnType("double"); + + b.Property("PlayerResult") + .HasColumnType("int"); + + b.ToTable("StreakInfos"); + }); + + modelBuilder.Entity("dsstats.db8.Unit", b => + { + b.Property("UnitId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UnitId")); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("UnitId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Units"); + }); + + modelBuilder.Entity("dsstats.db8.Upgrade", b => + { + b.Property("UpgradeId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UpgradeId")); + + b.Property("Cost") + .HasColumnType("int"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(50) + .HasColumnType("varchar(50)"); + + b.HasKey("UpgradeId"); + + b.HasIndex("Name") + .IsUnique(); + + b.ToTable("Upgrades"); + }); + + modelBuilder.Entity("dsstats.db8.Uploader", b => + { + b.Property("UploaderId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("UploaderId")); + + b.Property("AppGuid") + .HasColumnType("char(36)"); + + b.Property("AppVersion") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("Games") + .HasColumnType("int"); + + b.Property("Identifier") + .IsRequired() + .HasColumnType("longtext"); + + b.Property("IsDeleted") + .HasColumnType("tinyint(1)"); + + b.Property("LatestReplay") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("LatestUpload") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("MainCommander") + .HasColumnType("int"); + + b.Property("MainCount") + .HasColumnType("int"); + + b.Property("Mvp") + .HasColumnType("int"); + + b.Property("TeamGames") + .HasColumnType("int"); + + b.Property("UploadDisabledCount") + .HasColumnType("int"); + + b.Property("UploadIsDisabled") + .HasColumnType("tinyint(1)"); + + b.Property("UploadLastDisabled") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("Wins") + .HasColumnType("int"); + + b.HasKey("UploaderId"); + + b.HasIndex("AppGuid") + .IsUnique(); + + b.ToTable("Uploaders"); + }); + + modelBuilder.Entity("DsAbilityDsUnit", b => + { + b.HasOne("dsstats.db8.DsAbility", null) + .WithMany() + .HasForeignKey("AbilitiesDsAbilityId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.DsUnit", null) + .WithMany() + .HasForeignKey("DsUnitsDsUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("ReplayUploader", b => + { + b.HasOne("dsstats.db8.Replay", null) + .WithMany() + .HasForeignKey("ReplaysReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Uploader", null) + .WithMany() + .HasForeignKey("UploadersUploaderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRating", b => + { + b.HasOne("dsstats.db8.ArcadePlayer", "ArcadePlayer") + .WithMany("ArcadePlayerRatings") + .HasForeignKey("ArcadePlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadePlayer"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRatingChange", b => + { + b.HasOne("dsstats.db8.ArcadePlayerRating", "ArcadePlayerRating") + .WithOne("ArcadePlayerRatingChange") + .HasForeignKey("dsstats.db8.ArcadePlayerRatingChange", "ArcadePlayerRatingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadePlayerRating"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayer", b => + { + b.HasOne("dsstats.db8.ArcadePlayer", "ArcadePlayer") + .WithMany("ArcadeReplayPlayers") + .HasForeignKey("ArcadePlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.ArcadeReplay", "ArcadeReplay") + .WithMany("ArcadeReplayPlayers") + .HasForeignKey("ArcadeReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadePlayer"); + + b.Navigation("ArcadeReplay"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayerRating", b => + { + b.HasOne("dsstats.db8.ArcadeReplayPlayer", "ReplayPlayer") + .WithOne("ArcadeReplayPlayerRating") + .HasForeignKey("dsstats.db8.ArcadeReplayPlayerRating", "ArcadeReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.ArcadeReplayRating", "ArcadeReplayRating") + .WithMany("ArcadeReplayPlayerRatings") + .HasForeignKey("ArcadeReplayRatingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadeReplayRating"); + + b.Navigation("ReplayPlayer"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayRating", b => + { + b.HasOne("dsstats.db8.ArcadeReplay", "ArcadeReplay") + .WithOne("ArcadeReplayRating") + .HasForeignKey("dsstats.db8.ArcadeReplayRating", "ArcadeReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ArcadeReplay"); + }); + + modelBuilder.Entity("dsstats.db8.BattleNetInfo", b => + { + b.HasOne("dsstats.db8.Uploader", "Uploader") + .WithMany("BattleNetInfos") + .HasForeignKey("UploaderId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("dsstats.db8.BonusDamage", b => + { + b.HasOne("dsstats.db8.DsWeapon", "DsWeapon") + .WithMany("BonusDamages") + .HasForeignKey("DsWeaponId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DsWeapon"); + }); + + modelBuilder.Entity("dsstats.db8.ComboPlayerRating", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayPlayerRating", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithOne("ComboReplayPlayerRating") + .HasForeignKey("dsstats.db8.ComboReplayPlayerRating", "ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + }); + + modelBuilder.Entity("dsstats.db8.ComboReplayRating", b => + { + b.HasOne("dsstats.db8.Replay", "Replay") + .WithOne("ComboReplayRating") + .HasForeignKey("dsstats.db8.ComboReplayRating", "ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("dsstats.db8.DsUpgrade", b => + { + b.HasOne("dsstats.db8.DsUnit", null) + .WithMany("Upgrades") + .HasForeignKey("DsUnitId"); + }); + + modelBuilder.Entity("dsstats.db8.DsWeapon", b => + { + b.HasOne("dsstats.db8.DsUnit", "DsUnit") + .WithMany("Weapons") + .HasForeignKey("DsUnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("DsUnit"); + }); + + modelBuilder.Entity("dsstats.db8.IhSessionPlayer", b => + { + b.HasOne("dsstats.db8.IhSession", "IhSession") + .WithMany("IhSessionPlayers") + .HasForeignKey("IhSessionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("IhSession"); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.NoUploadResult", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany() + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.Player", b => + { + b.HasOne("dsstats.db8.Uploader", "Uploader") + .WithMany("Players") + .HasForeignKey("UploaderId"); + + b.Navigation("Uploader"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRating", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany("PlayerRatings") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Player"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRatingChange", b => + { + b.HasOne("dsstats.db8.PlayerRating", "PlayerRating") + .WithOne("PlayerRatingChange") + .HasForeignKey("dsstats.db8.PlayerRatingChange", "PlayerRatingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("PlayerRating"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerUpgrade", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithMany("Upgrades") + .HasForeignKey("ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Upgrade", "Upgrade") + .WithMany() + .HasForeignKey("UpgradeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + + b.Navigation("Upgrade"); + }); + + modelBuilder.Entity("dsstats.db8.RepPlayerRating", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithOne("ReplayPlayerRatingInfo") + .HasForeignKey("dsstats.db8.RepPlayerRating", "ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.ReplayRating", "ReplayRatingInfo") + .WithMany("RepPlayerRatings") + .HasForeignKey("ReplayRatingInfoId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + + b.Navigation("ReplayRatingInfo"); + }); + + modelBuilder.Entity("dsstats.db8.Replay", b => + { + b.HasOne("dsstats.db8.ReplayEvent", "ReplayEvent") + .WithMany("Replays") + .HasForeignKey("ReplayEventId"); + + b.Navigation("ReplayEvent"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayEvent", b => + { + b.HasOne("dsstats.db8.Event", "Event") + .WithMany("ReplayEvents") + .HasForeignKey("EventId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Event"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayPlayer", b => + { + b.HasOne("dsstats.db8.Player", "Player") + .WithMany("ReplayPlayers") + .HasForeignKey("PlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Replay", "Replay") + .WithMany("ReplayPlayers") + .HasForeignKey("ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Upgrade", null) + .WithMany("ReplayPlayers") + .HasForeignKey("UpgradeId"); + + b.Navigation("Player"); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayRating", b => + { + b.HasOne("dsstats.db8.Replay", "Replay") + .WithOne("ReplayRatingInfo") + .HasForeignKey("dsstats.db8.ReplayRating", "ReplayId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Replay"); + }); + + modelBuilder.Entity("dsstats.db8.Spawn", b => + { + b.HasOne("dsstats.db8.ReplayPlayer", "ReplayPlayer") + .WithMany("Spawns") + .HasForeignKey("ReplayPlayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("ReplayPlayer"); + }); + + modelBuilder.Entity("dsstats.db8.SpawnUnit", b => + { + b.HasOne("dsstats.db8.Spawn", "Spawn") + .WithMany("Units") + .HasForeignKey("SpawnId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("dsstats.db8.Unit", "Unit") + .WithMany() + .HasForeignKey("UnitId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Spawn"); + + b.Navigation("Unit"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayer", b => + { + b.Navigation("ArcadePlayerRatings"); + + b.Navigation("ArcadeReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadePlayerRating", b => + { + b.Navigation("ArcadePlayerRatingChange"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplay", b => + { + b.Navigation("ArcadeReplayPlayers"); + + b.Navigation("ArcadeReplayRating"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayPlayer", b => + { + b.Navigation("ArcadeReplayPlayerRating"); + }); + + modelBuilder.Entity("dsstats.db8.ArcadeReplayRating", b => + { + b.Navigation("ArcadeReplayPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.DsUnit", b => + { + b.Navigation("Upgrades"); + + b.Navigation("Weapons"); + }); + + modelBuilder.Entity("dsstats.db8.DsWeapon", b => + { + b.Navigation("BonusDamages"); + }); + + modelBuilder.Entity("dsstats.db8.Event", b => + { + b.Navigation("ReplayEvents"); + }); + + modelBuilder.Entity("dsstats.db8.IhSession", b => + { + b.Navigation("IhSessionPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.Player", b => + { + b.Navigation("PlayerRatings"); + + b.Navigation("ReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.PlayerRating", b => + { + b.Navigation("PlayerRatingChange"); + }); + + modelBuilder.Entity("dsstats.db8.Replay", b => + { + b.Navigation("ComboReplayRating"); + + b.Navigation("ReplayPlayers"); + + b.Navigation("ReplayRatingInfo"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayEvent", b => + { + b.Navigation("Replays"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayPlayer", b => + { + b.Navigation("ComboReplayPlayerRating"); + + b.Navigation("ReplayPlayerRatingInfo"); + + b.Navigation("Spawns"); + + b.Navigation("Upgrades"); + }); + + modelBuilder.Entity("dsstats.db8.ReplayRating", b => + { + b.Navigation("RepPlayerRatings"); + }); + + modelBuilder.Entity("dsstats.db8.Spawn", b => + { + b.Navigation("Units"); + }); + + modelBuilder.Entity("dsstats.db8.Upgrade", b => + { + b.Navigation("ReplayPlayers"); + }); + + modelBuilder.Entity("dsstats.db8.Uploader", b => + { + b.Navigation("BattleNetInfos"); + + b.Navigation("Players"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/MysqlMigrations/Migrations/20240715075452_MaterializedArcadeReplaysIndex.cs b/src/MysqlMigrations/Migrations/20240715075452_MaterializedArcadeReplaysIndex.cs new file mode 100644 index 00000000..ca5d4f64 --- /dev/null +++ b/src/MysqlMigrations/Migrations/20240715075452_MaterializedArcadeReplaysIndex.cs @@ -0,0 +1,29 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace MysqlMigrations.Migrations +{ + /// + public partial class MaterializedArcadeReplaysIndex : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + var sql = "TRUNCATE TABLE MaterializedArcadeReplays;"; + migrationBuilder.Sql(sql); + migrationBuilder.CreateIndex( + name: "IX_MaterializedArcadeReplays_CreatedAt", + table: "MaterializedArcadeReplays", + column: "CreatedAt"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_MaterializedArcadeReplays_CreatedAt", + table: "MaterializedArcadeReplays"); + } + } +} diff --git a/src/MysqlMigrations/Migrations/ReplayContextModelSnapshot.cs b/src/MysqlMigrations/Migrations/ReplayContextModelSnapshot.cs index d7987c61..5aaf6fbf 100644 --- a/src/MysqlMigrations/Migrations/ReplayContextModelSnapshot.cs +++ b/src/MysqlMigrations/Migrations/ReplayContextModelSnapshot.cs @@ -17,7 +17,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "8.0.6") + .HasAnnotation("ProductVersion", "8.0.7") .HasAnnotation("Relational:MaxIdentifierLength", 64); MySqlModelBuilderExtensions.AutoIncrementColumns(modelBuilder); @@ -1076,6 +1076,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.HasKey("MaterializedArcadeReplayId"); + b.HasIndex("CreatedAt"); + b.ToTable("MaterializedArcadeReplays"); }); @@ -1453,6 +1455,37 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("Replays"); }); + modelBuilder.Entity("dsstats.db8.ReplayArcadeMatch", b => + { + b.Property("ReplayArcadeMatchId") + .ValueGeneratedOnAdd() + .HasColumnType("int"); + + MySqlPropertyBuilderExtensions.UseMySqlIdentityColumn(b.Property("ReplayArcadeMatchId")); + + b.Property("ArcadeReplayId") + .HasColumnType("int"); + + b.Property("MatchTime") + .HasPrecision(0) + .HasColumnType("datetime(0)"); + + b.Property("ReplayId") + .HasColumnType("int"); + + b.HasKey("ReplayArcadeMatchId"); + + b.HasIndex("ArcadeReplayId") + .IsUnique(); + + b.HasIndex("MatchTime"); + + b.HasIndex("ReplayId") + .IsUnique(); + + b.ToTable("ReplayArcadeMatches"); + }); + modelBuilder.Entity("dsstats.db8.ReplayDownloadCount", b => { b.Property("ReplayDownloadCountId") diff --git a/src/MysqlMigrations/MysqlMigrations.csproj b/src/MysqlMigrations/MysqlMigrations.csproj index 91f6cb96..04fb2666 100644 --- a/src/MysqlMigrations/MysqlMigrations.csproj +++ b/src/MysqlMigrations/MysqlMigrations.csproj @@ -11,8 +11,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/SC2ArcadeCrawler/Program.cs b/src/SC2ArcadeCrawler/Program.cs index 00f5a03b..a630a7d5 100644 --- a/src/SC2ArcadeCrawler/Program.cs +++ b/src/SC2ArcadeCrawler/Program.cs @@ -33,8 +33,8 @@ static void Main(string[] args) services.AddLogging(options => { options.SetMinimumLevel(LogLevel.Information); - options.AddFilter("System.Net.Http.HttpClient", LogLevel.Information); - options.AddFilter("Microsoft.EntityFrameworkCore", LogLevel.Information); + options.AddFilter("System.Net.Http.HttpClient", LogLevel.Warning); + options.AddFilter("Microsoft.EntityFrameworkCore", LogLevel.Warning); options.AddConsole(); }); diff --git a/src/dsstats.api/Controllers/ReplaysController.cs b/src/dsstats.api/Controllers/ReplaysController.cs index bd94209d..f9c87473 100644 --- a/src/dsstats.api/Controllers/ReplaysController.cs +++ b/src/dsstats.api/Controllers/ReplaysController.cs @@ -66,4 +66,16 @@ public async Task> GetReplays(ReplaysRequest reque } return replay; } + + [HttpGet] + [Route("dsstatsarcadereplay/{hash}")] + public async Task> GetDsstatsArcadeReplay(string hash, CancellationToken token = default) + { + var replay = await replaysService.GetDssstatsArcadeReplay(hash, token); + if (replay is null) + { + return NotFound(); + } + return replay; + } } diff --git a/src/dsstats.api/Program.cs b/src/dsstats.api/Program.cs index d4e59f42..82f2fef0 100644 --- a/src/dsstats.api/Program.cs +++ b/src/dsstats.api/Program.cs @@ -142,6 +142,8 @@ builder.Services.AddScoped(); builder.Services.AddScoped(); +builder.Services.AddScoped(); + //builder.Services.AddScoped(); if (builder.Environment.IsProduction()) @@ -167,6 +169,7 @@ var authContext = scope.ServiceProvider.GetRequiredService(); authContext.Database.Migrate(); + if (app.Environment.IsProduction()) { var uploadSerivce = scope.ServiceProvider.GetRequiredService(); @@ -177,10 +180,8 @@ } else { - //var bestMatchupService = scope.ServiceProvider.GetRequiredService(); - //var request = new MatchupRequest() { TimePeriod = TimePeriod.Last2Years, Commander1 = Commander.Kerrigan, Commander2 = Commander.Nova }; - //var result = bestMatchupService.GetBestTeammateResult(request).GetAwaiter().GetResult(); - //Console.WriteLine("indahouse"); + //var comboRatings = scope.ServiceProvider.GetRequiredService(); + //comboRatings.CombineDsstatsSc2ArcadeReplays().Wait(); } app.UseRateLimiter(); diff --git a/src/dsstats.api/dsstats.api.csproj b/src/dsstats.api/dsstats.api.csproj index 41e5de3c..40cffd35 100644 --- a/src/dsstats.api/dsstats.api.csproj +++ b/src/dsstats.api/dsstats.api.csproj @@ -7,8 +7,8 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/src/dsstats.apiServices/ReplaysService.cs b/src/dsstats.apiServices/ReplaysService.cs index 26f67e55..e1598fc7 100644 --- a/src/dsstats.apiServices/ReplaysService.cs +++ b/src/dsstats.apiServices/ReplaysService.cs @@ -31,6 +31,20 @@ public ReplaysService(HttpClient httpClient, ILogger logger) return null; } + public async Task GetDssstatsArcadeReplay(string replayHash, CancellationToken token = default) + { + try + { + return await httpClient + .GetFromJsonAsync($"{replaysController}/dsstatsarcadereplay/{replayHash}", token); + } + catch (Exception ex) + { + logger.LogError("failed getting arcadereplay {hash}: {error}", replayHash, ex.Message); + } + return null; + } + public async Task GetReplay(string replayHash, bool dry = false, CancellationToken token = default) { try diff --git a/src/dsstats.auth/dsstats.auth.csproj b/src/dsstats.auth/dsstats.auth.csproj index f335fc3a..dee2a418 100644 --- a/src/dsstats.auth/dsstats.auth.csproj +++ b/src/dsstats.auth/dsstats.auth.csproj @@ -7,9 +7,9 @@ - - - + + + diff --git a/src/dsstats.cli/dsstats.cli.csproj b/src/dsstats.cli/dsstats.cli.csproj index a0e1842f..4855024a 100644 --- a/src/dsstats.cli/dsstats.cli.csproj +++ b/src/dsstats.cli/dsstats.cli.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/dsstats.db8/ReplayArcadeMap.cs b/src/dsstats.db8/ReplayArcadeMap.cs new file mode 100644 index 00000000..76a5ae57 --- /dev/null +++ b/src/dsstats.db8/ReplayArcadeMap.cs @@ -0,0 +1,12 @@ +using Microsoft.EntityFrameworkCore; + +namespace dsstats.db8; + +public class ReplayArcadeMatch +{ + public int ReplayArcadeMatchId { get; set; } + public int ReplayId { get; set; } + public int ArcadeReplayId { get; set; } + [Precision(0)] + public DateTime MatchTime { get; set; } +} diff --git a/src/dsstats.db8/ReplayContext.cs b/src/dsstats.db8/ReplayContext.cs index 2eee7e6d..3d6c08de 100644 --- a/src/dsstats.db8/ReplayContext.cs +++ b/src/dsstats.db8/ReplayContext.cs @@ -49,6 +49,7 @@ public class ReplayContext : DbContext public virtual DbSet BonusDamages { get; set; } = null!; public virtual DbSet DsAbilities { get; set; } = null!; public virtual DbSet DsUpgrades { get; set; } = null!; + public virtual DbSet ReplayArcadeMatches { get; set; } = null!; public virtual DbSet ComboPlayerRatings { get; set; } = null!; public virtual DbSet ComboReplayRatings { get; set; } = null!; @@ -233,6 +234,18 @@ protected override void OnModelCreating(ModelBuilder modelBuilder) c => JsonSerializer.Deserialize(c, (JsonSerializerOptions?)null)); }); + modelBuilder.Entity(entity => + { + entity.HasIndex(i => i.ReplayId).IsUnique(); + entity.HasIndex(i => i.ArcadeReplayId).IsUnique(); + entity.HasIndex(i => i.MatchTime); + }); + + modelBuilder.Entity(entity => + { + entity.HasIndex(i => i.CreatedAt); + }); + MethodInfo weekMethodInfo = typeof(ReplayContext) .GetRuntimeMethod(nameof(ReplayContext.Week), new[] { typeof(DateTime) }) ?? throw new ArgumentNullException(); diff --git a/src/dsstats.db8/dsstats.db8.csproj b/src/dsstats.db8/dsstats.db8.csproj index d4335b16..5a023bab 100644 --- a/src/dsstats.db8/dsstats.db8.csproj +++ b/src/dsstats.db8/dsstats.db8.csproj @@ -8,12 +8,12 @@ - - + + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/dsstats.db8cli/Program.cs b/src/dsstats.db8cli/Program.cs index 922ae9cc..c4d0bce8 100644 --- a/src/dsstats.db8cli/Program.cs +++ b/src/dsstats.db8cli/Program.cs @@ -8,6 +8,7 @@ using Microsoft.Extensions.Logging; using System.Diagnostics; using System.Text.Json; +using AutoMapper.Configuration; namespace dsstats.db8cli; diff --git a/src/dsstats.db8cli/dsstats.db8cli.csproj b/src/dsstats.db8cli/dsstats.db8cli.csproj index 83aef1a7..978f0114 100644 --- a/src/dsstats.db8cli/dsstats.db8cli.csproj +++ b/src/dsstats.db8cli/dsstats.db8cli.csproj @@ -7,7 +7,6 @@ - diff --git a/src/dsstats.db8services/ReplaysService.cs b/src/dsstats.db8services/ReplaysService.cs index ddd26221..6fd5a357 100644 --- a/src/dsstats.db8services/ReplaysService.cs +++ b/src/dsstats.db8services/ReplaysService.cs @@ -20,6 +20,19 @@ public ReplaysService(ReplayContext context, IMapper mapper) this.mapper = mapper; } + public async Task GetDssstatsArcadeReplay(string replayHash, CancellationToken token = default) + { + var arcadeReplayDto = await (from r in context.Replays + join ram in context.ReplayArcadeMatches on r.ReplayId equals ram.ReplayId + join ar in context.ArcadeReplays on ram.ArcadeReplayId equals ar.ArcadeReplayId + where r.ReplayHash == replayHash + select ar) + .ProjectTo(mapper.ConfigurationProvider) + .FirstOrDefaultAsync(token); + + return arcadeReplayDto; + } + public async Task GetReplayRating(string replayHash, bool comboRating) { if (comboRating) diff --git a/src/dsstats.db8services/dsstats.db8services.csproj b/src/dsstats.db8services/dsstats.db8services.csproj index c868c9c9..ba809a9e 100644 --- a/src/dsstats.db8services/dsstats.db8services.csproj +++ b/src/dsstats.db8services/dsstats.db8services.csproj @@ -7,12 +7,12 @@ - - + + - + diff --git a/src/dsstats.maui/SqliteMigrations/SqliteMigrations.csproj b/src/dsstats.maui/SqliteMigrations/SqliteMigrations.csproj index e13d0ef3..2aefdd5e 100644 --- a/src/dsstats.maui/SqliteMigrations/SqliteMigrations.csproj +++ b/src/dsstats.maui/SqliteMigrations/SqliteMigrations.csproj @@ -11,11 +11,11 @@ - + runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/dsstats.maui/dsstats.localization/dsstats.localization.csproj b/src/dsstats.maui/dsstats.localization/dsstats.localization.csproj index 4e6e1134..3b77fe14 100644 --- a/src/dsstats.maui/dsstats.localization/dsstats.localization.csproj +++ b/src/dsstats.maui/dsstats.localization/dsstats.localization.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/dsstats.maui/dsstats.maui8/dsstats.maui8.csproj b/src/dsstats.maui/dsstats.maui8/dsstats.maui8.csproj index df79e1af..ce78029c 100644 --- a/src/dsstats.maui/dsstats.maui8/dsstats.maui8.csproj +++ b/src/dsstats.maui/dsstats.maui8/dsstats.maui8.csproj @@ -63,14 +63,14 @@ - - - - + + + + - + diff --git a/src/dsstats.maui/pax.dsstats.parser/TrackerEvents/FixPlayerPos.cs b/src/dsstats.maui/pax.dsstats.parser/TrackerEvents/FixPlayerPos.cs index 31874e9d..5fe1a498 100644 --- a/src/dsstats.maui/pax.dsstats.parser/TrackerEvents/FixPlayerPos.cs +++ b/src/dsstats.maui/pax.dsstats.parser/TrackerEvents/FixPlayerPos.cs @@ -36,6 +36,16 @@ private static void FixPlayerPosNg(DsReplay replay, ICollection f.Pos = f.WorkingsetSlot == 0 ? 1 : f.WorkingsetSlot); return; } + + // 2 player by order + if (playerIds.Count == 2 && playerPos.Count == 2) + { + for (int i = 0; i < setupEvents.Count; i++) + { + replay.Players[i].Pos = setupEvents.ElementAt(i).PlayerId; + } + return; + } throw new ArgumentNullException(nameof(setupEvents)); } diff --git a/src/dsstats.maui/pax.dsstats.parser/pax.dsstats.parser.csproj b/src/dsstats.maui/pax.dsstats.parser/pax.dsstats.parser.csproj index b7bacd5e..cd79426c 100644 --- a/src/dsstats.maui/pax.dsstats.parser/pax.dsstats.parser.csproj +++ b/src/dsstats.maui/pax.dsstats.parser/pax.dsstats.parser.csproj @@ -8,7 +8,7 @@ - + diff --git a/src/dsstats.ratings/ComboRatings.ArcadeRep.cs b/src/dsstats.ratings/ComboRatings.ArcadeRep.cs new file mode 100644 index 00000000..dc2d852c --- /dev/null +++ b/src/dsstats.ratings/ComboRatings.ArcadeRep.cs @@ -0,0 +1,181 @@ +using dsstats.shared.Calc; +using Microsoft.EntityFrameworkCore; + +namespace dsstats.ratings; + +public partial class ComboRatings +{ + private readonly double dateOverflow = 0.5; + private List currentArcadeCalcDtos = []; + private List chunkInfos = []; + private int currentChunkInfoIndex = 0; + + private async Task InitArcadeRep(List dsstatsReplays) + { + var oldestReplayDate = dsstatsReplays.First().GameTime.AddDays(-dateOverflow); + var latestReplayDate = dsstatsReplays.Last().GameTime.AddDays(dateOverflow); + + var startId = await GetStartIdAsync(oldestReplayDate); + var endId = await GetEndIdAsync(latestReplayDate); + + chunkInfos.Clear(); + if (endId - startId > 150_000) + { + await CreateChunks(oldestReplayDate, latestReplayDate, startId, endId); + } + else + { + var chunkInfo = new ArcadeChunkInfo() + { + StartTime = oldestReplayDate, + EndTime = latestReplayDate, + StartId = startId, + EndId = endId, + }; + chunkInfos.Add(chunkInfo); + } + currentChunkInfoIndex = 0; + await LoadCurrentChunkInfoArcadeReplays(); + } + + private async Task CreateChunks(DateTime oldestReplayDate, DateTime latestReplayDate, int startId, int endId) + { + var stepDate = oldestReplayDate; + var stepStartId = startId; + while (stepDate < latestReplayDate) + { + var stepChunkInfo = new ArcadeChunkInfo + { + StartTime = stepDate, + StartId = stepStartId + }; + stepDate = stepDate.AddDays(10); + int stepEndId; + if (stepDate > latestReplayDate) + { + stepDate = latestReplayDate; + stepEndId = endId; + } + else + { + stepEndId = await GetEndIdAsync(stepDate); + } + stepChunkInfo.EndTime = stepDate; + stepChunkInfo.EndId = stepEndId; + chunkInfos.Add(stepChunkInfo); + stepStartId = stepEndId + 1; + } + } + + private async Task GetStartIdAsync(DateTime date) + { + return await context.MaterializedArcadeReplays + .Where(x => x.CreatedAt > date) + .OrderBy(o => o.MaterializedArcadeReplayId) + .Select(s => s.MaterializedArcadeReplayId) + .FirstOrDefaultAsync(); + } + + private async Task GetEndIdAsync(DateTime date) + { + return await context.MaterializedArcadeReplays + .Where(x => x.CreatedAt < date) + .OrderBy(o => o.MaterializedArcadeReplayId) + .Select(s => s.MaterializedArcadeReplayId) + .LastOrDefaultAsync(); + } + + private async Task LoadCurrentChunkInfoArcadeReplays() + { + int preserveCount = 10_000; + List preserveCalcDtos = []; + if (currentArcadeCalcDtos.Count > 0) + { + if (currentArcadeCalcDtos.Count <= preserveCount) + { + preserveCalcDtos = new(currentArcadeCalcDtos); + } + else + { + var skip = currentArcadeCalcDtos.Count - preserveCount; + preserveCalcDtos = currentArcadeCalcDtos.Skip(skip).ToList(); + } + } + + currentArcadeCalcDtos = await GetComboArcadeCalcDtos(chunkInfos[currentChunkInfoIndex]); + currentArcadeCalcDtos = currentArcadeCalcDtos + .Where(x => !matchesInfo.ArcadeDict.ContainsKey(x.ReplayId)) + .ToList(); + if (preserveCalcDtos.Count > 0) + { + currentArcadeCalcDtos = preserveCalcDtos.Concat(currentArcadeCalcDtos).ToList(); + } + } + + private async Task UpdateArcadeReplays(CalcDto dsstasReplay) + { + var currentChunkInfo = chunkInfos[currentChunkInfoIndex]; + if (dsstasReplay.GameTime > currentChunkInfo.EndTime.AddDays(-0.5)) + { + if (chunkInfos.Count > currentChunkInfoIndex + 1) + { + currentChunkInfoIndex++; + currentChunkInfo = chunkInfos[currentChunkInfoIndex]; + await LoadCurrentChunkInfoArcadeReplays(); + } + } + } + + // every call does get a dsstatsReplay with increase GameTime (orderby r.GameTime, r.ReplayId) + private async Task> GetReasonableReplays(CalcDto dsstatsReplay, HashSet matchedArcadeIds) + { + await UpdateArcadeReplays(dsstatsReplay); + return currentArcadeCalcDtos + .Where(x => x.GameTime > dsstatsReplay.GameTime.AddDays(-dateOverflow) + && x.GameTime < dsstatsReplay.GameTime.AddDays(dateOverflow) + && x.GameMode == dsstatsReplay.GameMode + && GetReplayRegionId(x) == GetReplayRegionId(dsstatsReplay) + && !matchedArcadeIds.Contains(x.ReplayId) + ).ToList(); + } + + private async Task> GetComboArcadeCalcDtos(ArcadeChunkInfo chunkInfo) + { + var query = from r in context.MaterializedArcadeReplays + orderby r.MaterializedArcadeReplayId + where r.MaterializedArcadeReplayId >= chunkInfo.StartId + && r.MaterializedArcadeReplayId <= chunkInfo.EndId + select new CalcDto() + { + ReplayId = r.ArcadeReplayId, + GameTime = r.CreatedAt, + Duration = r.Duration, + GameMode = (int)r.GameMode, + WinnerTeam = r.WinnerTeam, + TournamentEdition = false, + IsArcade = true, + Players = context.ArcadeReplayPlayers + .Where(x => x.ArcadeReplayId == r.ArcadeReplayId) + .Select(t => new PlayerCalcDto() + { + ReplayPlayerId = t.ArcadeReplayPlayerId, + GamePos = t.SlotNumber, + PlayerResult = (int)t.PlayerResult, + Team = t.Team, + PlayerId = new(t.ArcadePlayer.ProfileId, t.ArcadePlayer.RealmId, t.ArcadePlayer.RegionId) + }).ToList() + }; + + return await query + .AsSplitQuery() + .ToListAsync(); + } + + internal record ArcadeChunkInfo + { + public DateTime StartTime { get; set; } + public DateTime EndTime { get; set; } + public int StartId { get; set; } + public int EndId { get; set; } + } +} diff --git a/src/dsstats.ratings/ComboRatings.cs b/src/dsstats.ratings/ComboRatings.cs new file mode 100644 index 00000000..2616180f --- /dev/null +++ b/src/dsstats.ratings/ComboRatings.cs @@ -0,0 +1,269 @@ +using dsstats.db8; +using dsstats.shared.Calc; +using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Logging; +using System.Diagnostics; +using System.Text.Json; + +namespace dsstats.ratings; + +public partial class ComboRatings(ReplayContext context, ILogger logger) +{ + private Dictionary RegionDict = []; + private Dictionary> ToonIdsDict = []; + private ReplayMatchInfo matchesInfo = new(); + + public async Task InitDb() + { + var matches = JsonSerializer.Deserialize>>(File.ReadAllText("/data/ds/replaymatches.json")) ?? []; + var matchTime = DateTime.UtcNow; + + List dbMatches = matches.Select(s => new ReplayArcadeMatch() + { + ReplayId = s.Key, + ArcadeReplayId = s.Value, + MatchTime = matchTime, + }).ToList(); + + context.ReplayArcadeMatches.AddRange(dbMatches); + await context.SaveChangesAsync(); + } + + public async Task CombineDsstatsSc2ArcadeReplays() + { + Stopwatch sw = Stopwatch.StartNew(); + DsstatsCalcRequest dsstatsRequest = new() + { + FromDate = new DateTime(2021, 2, 1), + GameModes = new List() { 3, 4, 7 }, + Skip = 0, + Take = 1000 + }; + HashSet matchedArcadeIds = []; + matchesInfo = await GetProcessedReplayIds(); + dsstatsRequest.Imported = dsstatsRequest.Imported == DateTime.MinValue ? DateTime.MinValue + : matchesInfo.LatestUpdate.AddDays(-0.5); + int matches = 0; + var dsstatsReplays = await GetComboDsstatsCalcDtos(dsstatsRequest, context); + + while (dsstatsReplays.Count > 0) + { + dsstatsReplays = dsstatsReplays.Where(x => !matchesInfo.ReplayDict.ContainsKey(x.ReplayId)) + .ToList(); + await InitArcadeRep(dsstatsReplays); + + + List replayMatches = []; + + foreach (var dsstatsReplay in dsstatsReplays) + { + var arcadeReplay = await FindSc2ArcadeReplay(dsstatsReplay, matchedArcadeIds); + if (arcadeReplay is not null) + { + currentArcadeCalcDtos.Remove(arcadeReplay); + matchedArcadeIds.Add(arcadeReplay.ReplayId); + replayMatches.Add(new() + { + ReplayId = dsstatsReplay.ReplayId, + ArcadeReplayId = arcadeReplay.ReplayId, + MatchTime = DateTime.UtcNow + }); + matches++; + } + } + await StoreReplayMatches(replayMatches); + dsstatsRequest.Skip += dsstatsRequest.Take; + dsstatsReplays = await GetComboDsstatsCalcDtos(dsstatsRequest, context); + RegionDict.Clear(); + ToonIdsDict.Clear(); + } + sw.Stop(); + logger.LogWarning("Matches: {matches} in {elapsed}sec", matches, Math.Round(sw.Elapsed.TotalSeconds, 2)); + } + + + + private async Task StoreReplayMatches(List replayMatches) + { + if (replayMatches.Count == 0) + { + return; + } + + context.ReplayArcadeMatches.AddRange(replayMatches); + await context.SaveChangesAsync(); + } + + private async Task GetProcessedReplayIds() + { + var matches = await context.ReplayArcadeMatches + .ToListAsync(); + + return new() + { + ReplayDict = matches.ToDictionary(k => k.ReplayId, v => true), + ArcadeDict = matches.ToDictionary(k => k.ArcadeReplayId, v => true), + LatestUpdate = matches.OrderByDescending(o => o.MatchTime).FirstOrDefault()?.MatchTime ?? DateTime.MinValue, + }; + } + + private async Task FindSc2ArcadeReplay(CalcDto dsstatsReplay, HashSet matchedArcadeIds) + { + var reasonableReplays = await GetReasonableReplays(dsstatsReplay, matchedArcadeIds); + + if (reasonableReplays.Count == 0) + { + return null; + } + + var dsstatsPlayerIds = GetOrderedToonIds(dsstatsReplay); + CalcDto? bestMatch = null; + int minBestScore = dsstatsPlayerIds.Count; + int bestMatchScore = 0; + + foreach (var arcadeReplay in reasonableReplays) + { + var arcadePlayerIds = GetOrderedToonIds(arcadeReplay); + var key = new ReplayKey(arcadeReplay.ReplayId, arcadeReplay.IsArcade); + int lcsLength = CalculateLCSLength(dsstatsPlayerIds, arcadePlayerIds); + + if (lcsLength > bestMatchScore) + { + bestMatchScore = lcsLength; + bestMatch = arcadeReplay; + } + } + return bestMatchScore >= minBestScore ? bestMatch : null; + } + + private static bool IsDurationWithinThreshold(int dsstatsDuration, int arcadeDuration, double thresholdPercentage) + { + double difference = Math.Abs(dsstatsDuration - arcadeDuration); + double maxAllowedDifference = dsstatsDuration * thresholdPercentage + 300; + return difference <= maxAllowedDifference; + } + + private List GetOrderedToonIds(CalcDto replay) + { + var key = new ReplayKey(replay.ReplayId, replay.IsArcade); + if (!ToonIdsDict.TryGetValue(key, out var ids)) + { + ToonIdsDict[key] = ids = replay.Players + .OrderBy(o => o.Team) + .ThenBy(o => o.GamePos) + .Select(s => s.PlayerId.ToonId) + .ToList(); + } + return ids; + } + + private static int CalculateLCSLength(List a, List b) + { + int[,] dp = new int[a.Count + 1, b.Count + 1]; + + for (int i = 1; i <= a.Count; i++) + { + for (int j = 1; j <= b.Count; j++) + { + if (a[i - 1] == b[j - 1]) + { + dp[i, j] = dp[i - 1, j - 1] + 1; + } + else + { + dp[i, j] = Math.Max(dp[i - 1, j], dp[i, j - 1]); + } + } + } + + return dp[a.Count, b.Count]; + } + + private int GetReplayRegionId(CalcDto replay) + { + var key = new ReplayKey(replay.ReplayId, replay.IsArcade); + if (!RegionDict.TryGetValue(key, out var regionId)) + { + RegionDict[key] = replay.Players + .GroupBy(p => p.PlayerId.RegionId) + .OrderByDescending(g => g.Count()) + .First().Key; + } + return regionId; + } + + private static async Task> GetComboDsstatsCalcDtos(DsstatsCalcRequest request, ReplayContext context) + { + var query = from r in context.Replays + join m in context.ReplayArcadeMatches on r.ReplayId equals m.ReplayId into grouping + from m in grouping.DefaultIfEmpty() + where m == null + && r.Playercount == 6 + && r.Duration >= 300 + && r.WinnerTeam > 0 + && request.GameModes.Contains((int)r.GameMode) + && r.TournamentEdition == false + && r.GameTime >= request.FromDate + && (request.Continue ? r.ReplayRatingInfo == null : true) + && (r.Imported == DateTime.MinValue || r.Imported > request.Imported) + orderby r.GameTime, r.ReplayId + select new RawCalcDto + { + DsstatsReplayId = r.ReplayId, + GameTime = r.GameTime, + Duration = r.Duration, + Maxkillsum = r.Maxkillsum, + GameMode = (int)r.GameMode, + TournamentEdition = false, + Players = r.ReplayPlayers.Select(t => new RawPlayerCalcDto + { + ReplayPlayerId = t.ReplayPlayerId, + GamePos = t.GamePos, + PlayerResult = (int)t.PlayerResult, + Race = t.Race, + Duration = t.Duration, + Kills = t.Kills, + Team = t.Team, + IsUploader = t.Player.UploaderId != null, + PlayerId = new(t.Player.ToonId, t.Player.RealmId, t.Player.RegionId) + }).ToList() + }; + + var rawDtos = await query + .AsSplitQuery() + .Skip(request.Skip) + .Take(request.Take) + .ToListAsync(); + + return rawDtos.Select(s => s.GetCalcDto()).ToList(); + } +} + +internal record ReplayKey +{ + public ReplayKey(int replayId, bool isArcade) + { + ReplayId = replayId; + IsArcade = isArcade; + } + public int ReplayId { get; set; } + public bool IsArcade { get; set; } +} + +internal record ReplayPartKey +{ + public ReplayPartKey(int gameMode, int regionId) + { + GameMode = gameMode; + RegionId = regionId; + } + public int GameMode { get; set; } + public int RegionId { get; set; } +} + +internal record ReplayMatchInfo +{ + public Dictionary ReplayDict { get; set; } = []; + public Dictionary ArcadeDict { get; set; } = []; + public DateTime LatestUpdate { get; set; } +} \ No newline at end of file diff --git a/src/dsstats.ratings/Program.cs b/src/dsstats.ratings/Program.cs index 8c5b875e..140265ce 100644 --- a/src/dsstats.ratings/Program.cs +++ b/src/dsstats.ratings/Program.cs @@ -49,6 +49,7 @@ static void Main(string[] args) }); services.AddAutoMapper(typeof(AutoMapperProfile)); + services.AddScoped(); services.AddSingleton(); services.AddSingleton(); @@ -88,11 +89,6 @@ static void Main(string[] args) logger.LogInformation("producing combo ratings."); ratingService.ProduceRatings(RatingCalcType.Combo, false).Wait(); } - else if (args[0] == "combo2") - { - logger.LogInformation("producing combo2 ratings."); - ratingService.CombineTest().Wait(); - } else if (args[0] == "lsdups") { logger.LogInformation("Checking lastSpawnHashes"); diff --git a/src/dsstats.ratings/RatingService.Combine.cs b/src/dsstats.ratings/RatingService.Combine.cs deleted file mode 100644 index 1b3294c8..00000000 --- a/src/dsstats.ratings/RatingService.Combine.cs +++ /dev/null @@ -1,243 +0,0 @@ -using dsstats.db8; -using dsstats.ratings.lib; -using dsstats.shared; -using dsstats.shared.Calc; -using dsstats.shared.Interfaces; -using Microsoft.EntityFrameworkCore; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.Extensions.Logging; - -namespace dsstats.ratings; - -public partial class RatingService -{ - - public async Task CombineTest() - { - DsstatsCalcRequest request = new() - { - FromDate = new DateTime(2021, 2, 1), - GameModes = new List() { 3, 4, 7 }, - Skip = 0, - Take = 5000 - }; - - var ratingRequest = new CalcRatingRequest() - { - RatingCalcType = RatingCalcType.Dsstats, - MmrIdRatings = new() - { - { 1, new() }, - { 2, new() }, - { 3, new() }, - { 4, new() } - }, - }; - - using var scope = scopeFactory.CreateAsyncScope(); - var context = scope.ServiceProvider.GetRequiredService(); - var ratingSaveService = scope.ServiceProvider.GetRequiredService(); - - var dsReps = await GetCombineDsstatsCalcDtos(request, context); - var acReps = await GetCombineArcadeCalcDtos(dsReps, context); - - var dsDic = new Dictionary>(); - - // ensure non overlapping acrade replays - Dictionary processedArcadeIds = new(6_000_000); - - // ensure non duplicate dsstats overlapping arcade replays - Dictionary> ratings = new(); - - while (dsReps.Count > 0) - { - Dictionary> stepRatings = new(); - List impRatings = new(); - var cbReps = CombineLists(dsReps, acReps, processedArcadeIds); - - foreach (var ent in cbReps) - { - if (!stepRatings.TryGetValue(ent.Key, out var keyRatings)) - { - keyRatings = stepRatings[ent.Key] = new(); - } - - foreach (var rep in ent.Value) - { - var rating = Ratings.ProcessReplay(rep, ratingRequest); - if (rating is not null && !ratings.ContainsKey(ent.Key)) - { - keyRatings.Add(rating); - if (!rep.IsArcade) // dsstats replay infos, only - { - impRatings.Add(rating); - } - } - } - } - - (ratingRequest.ReplayRatingAppendId, ratingRequest.ReplayPlayerRatingAppendId) = - await ratingSaveService.SaveComboStepResult(impRatings, - ratingRequest.ReplayRatingAppendId, - ratingRequest.ReplayPlayerRatingAppendId); - ratings = stepRatings; - request.Skip += request.Take; - dsReps = await GetCombineDsstatsCalcDtos(request, context); - acReps = await GetCombineArcadeCalcDtos(dsReps, context); - } - - await ratingSaveService.SaveComboPlayerRatings(ratingRequest.MmrIdRatings, ratingRequest.SoftBannedPlayers); - } - - private Dictionary> CombineLists(List dsstatsCalcDtos, - List sc2ArcadeCalcDtos, - Dictionary processedArcadeIds) - { - var dsstatsDic = GenerateHashDic(dsstatsCalcDtos); - var sc2arcadeDic = GenerateHashDic(sc2ArcadeCalcDtos); - - var dsMultiHashes = dsstatsDic.Values.Where(x => x.Count > 1).Count(); - var acMutliHashes = sc2arcadeDic.Values.Where(x => x.Count > 1).Count(); - - int hits = 0; - int reasonableHits = 0; - - foreach (var ent in dsstatsDic) - { - foreach (var calcDto in ent.Value.ToArray()) - { - if (sc2arcadeDic.TryGetValue(ent.Key, out var calcDtos)) - { - foreach (var sc2ArcadeCalcDto in calcDtos.ToArray()) - { - if (processedArcadeIds.ContainsKey(sc2ArcadeCalcDto.ReplayId)) - { - continue; - } - hits++; - if (IsMatchReasonable(calcDto, sc2ArcadeCalcDto)) - { - reasonableHits++; - } - else - { - processedArcadeIds.Add(sc2ArcadeCalcDto.ReplayId, true); - ent.Value.Add(sc2ArcadeCalcDto); - } - } - } - } - } - - foreach (var ent in sc2arcadeDic) - { - if (!dsstatsDic.ContainsKey(ent.Key)) - { - dsstatsDic[ent.Key] = ent.Value; - } - } - - // logger.LogWarning("MultiHashes: {dsMultiHashes}|{acMutliHashes}, hits: {hits}|{reasonableHits}", - // dsMultiHashes, acMutliHashes, hits, reasonableHits); - return dsstatsDic; - } - - private async Task> GetCombineArcadeCalcDtos(List dsstatsCalcDtos, ReplayContext context) - { - if (dsstatsCalcDtos.Count == 0) - { - return new(); - } - - var oldestReplayDate = dsstatsCalcDtos.First().GameTime.AddDays(-1); - var latestReplayDate = dsstatsCalcDtos.Last().GameTime.AddDays(1); - - var startId = await context.MaterializedArcadeReplays - .Where(x => x.CreatedAt > oldestReplayDate) - .OrderBy(o => o.MaterializedArcadeReplayId) - .Select(s => s.MaterializedArcadeReplayId) - .FirstOrDefaultAsync(); - - var endId = await context.MaterializedArcadeReplays - .Where(x => x.CreatedAt < latestReplayDate) - .OrderBy(o => o.MaterializedArcadeReplayId) - .Select(s => s.MaterializedArcadeReplayId) - .LastOrDefaultAsync(); - - if (startId == endId || startId > endId) - { - logger.LogWarning("arcade ids missmatch {id1}, {id2}", startId, endId); - return new(); - } - - var query = from r in context.MaterializedArcadeReplays - orderby r.MaterializedArcadeReplayId - where r.MaterializedArcadeReplayId >= startId - && r.MaterializedArcadeReplayId <= endId - select new CalcDto() - { - ReplayId = r.ArcadeReplayId, - GameTime = r.CreatedAt, - Duration = r.Duration, - GameMode = (int)r.GameMode, - TournamentEdition = false, - IsArcade = true, - Players = context.ArcadeReplayPlayers - .Where(x => x.ArcadeReplayId == r.ArcadeReplayId) - .Select(t => new PlayerCalcDto() - { - ReplayPlayerId = t.ArcadeReplayPlayerId, - GamePos = t.SlotNumber, - PlayerResult = (int)t.PlayerResult, - Team = t.Team, - PlayerId = new(t.ArcadePlayer.ProfileId, t.ArcadePlayer.RealmId, t.ArcadePlayer.RegionId) - }).ToList() - }; - - return await query - .AsSplitQuery() - .ToListAsync(); - } - - private async Task> GetCombineDsstatsCalcDtos(DsstatsCalcRequest request, ReplayContext context) - { - var rawDtos = await context.Replays - .Where(x => x.Playercount == 6 - && x.Duration >= 300 - && x.WinnerTeam > 0 - && request.GameModes.Contains((int)x.GameMode) - && x.TournamentEdition == false - && x.GameTime >= request.FromDate - && (request.Continue ? x.ReplayRatingInfo == null : true)) - .OrderBy(o => o.GameTime) - .ThenBy(o => o.ReplayId) - .Select(s => new RawCalcDto() - { - DsstatsReplayId = s.ReplayId, - GameTime = s.GameTime, - Duration = s.Duration, - Maxkillsum = s.Maxkillsum, - GameMode = (int)s.GameMode, - TournamentEdition = false, - Players = s.ReplayPlayers.Select(t => new RawPlayerCalcDto() - { - ReplayPlayerId = t.ReplayPlayerId, - GamePos = t.GamePos, - PlayerResult = (int)t.PlayerResult, - Race = t.Race, - Duration = t.Duration, - Kills = t.Kills, - Team = t.Team, - IsUploader = t.Player.UploaderId != null, - PlayerId = new(t.Player.ToonId, t.Player.RealmId, t.Player.RegionId) - }).ToList() - - }) - .AsSplitQuery() - .Skip(request.Skip) - .Take(request.Take) - .ToListAsync(); - - return rawDtos.Select(s => s.GetCalcDto()).ToList(); - } -} diff --git a/src/dsstats.ratings/RatingService.Combo.cs b/src/dsstats.ratings/RatingService.Combo.cs index 391bcd7c..8179f77f 100644 --- a/src/dsstats.ratings/RatingService.Combo.cs +++ b/src/dsstats.ratings/RatingService.Combo.cs @@ -23,6 +23,8 @@ private async Task ProduceComboRatings(bool recalc) using var scope = scopeFactory.CreateAsyncScope(); var context = scope.ServiceProvider.GetRequiredService(); var ratingSaveService = scope.ServiceProvider.GetRequiredService(); + var comboRatings = scope.ServiceProvider.GetRequiredService(); + await comboRatings.CombineDsstatsSc2ArcadeReplays(); await CleanupComboPreRatings(context); @@ -48,8 +50,7 @@ private async Task ProduceComboRatings(bool recalc) }; - HashSet processedReplayIds = new(); - var comboCalcDtos = await GetComboCalcDtos(dsstatsRequest, processedReplayIds, context); + var comboCalcDtos = await GetComboCalcDtos(dsstatsRequest, context); List replayRatings = new(); @@ -75,140 +76,31 @@ await ratingSaveService.SaveComboStepResult(replayRatings, ratingRequest.ReplayPlayerRatingAppendId); replayRatings = new(); dsstatsRequest.Skip += dsstatsRequest.Take; - comboCalcDtos = await GetComboCalcDtos(dsstatsRequest, processedReplayIds, context); + comboCalcDtos = await GetComboCalcDtos(dsstatsRequest, context); } await ratingSaveService.SaveComboPlayerRatings(ratingRequest.MmrIdRatings, ratingRequest.SoftBannedPlayers); } private async Task> GetComboCalcDtos(DsstatsCalcRequest request, - HashSet processedReplayIds, ReplayContext context) { var dsstatsCalcDtos = await GetComboDsstatsCalcDtos(request, context); - var arcadeCalcDtos = await GetComboArcadeCalcDtos(dsstatsCalcDtos, processedReplayIds, context); - return CombineCalcDtos(dsstatsCalcDtos, arcadeCalcDtos, processedReplayIds); + var arcadeCalcDtos = await GetComboArcadeCalcDtos(dsstatsCalcDtos, context); + return CombineCalcDtos(dsstatsCalcDtos, arcadeCalcDtos); } private List CombineCalcDtos(List dsstatsCalcDtos, - List sc2ArcadeCalcDtos, - HashSet processedReplayIds) + List sc2ArcadeCalcDtos) { - List combinedCalcDtos = new(); - - var dsstatsDic = GenerateHashDic(dsstatsCalcDtos); - var sc2arcadeDic = GenerateHashDic(sc2ArcadeCalcDtos); - - foreach (var ent in dsstatsDic) - { - foreach (var calcDto in ent.Value) - { - if (sc2arcadeDic.TryGetValue(ent.Key, out var calcDtos)) - { - foreach (var sc2ArcadeCalcDto in calcDtos.ToArray()) - { - if (IsMatchReasonable(calcDto, sc2ArcadeCalcDto)) - { - calcDtos.Remove(sc2ArcadeCalcDto); - break; - } - } - } - combinedCalcDtos.Add(calcDto); - } - } - - combinedCalcDtos.AddRange(sc2arcadeDic.SelectMany(s => s.Value)); - processedReplayIds.UnionWith(sc2ArcadeCalcDtos.Select(s => s.ReplayId)); - - return combinedCalcDtos + return dsstatsCalcDtos + .Concat(sc2ArcadeCalcDtos) .OrderBy(o => o.GameTime) - .ThenBy(o => o.ReplayId) + .ThenBy(o => o.ReplayId) .ToList(); } - private static bool IsMatchReasonable(CalcDto dsstatsCalcDto, CalcDto sc2arcadeCalcDto) - { - var gameTimeDiff = Math.Abs((dsstatsCalcDto.GameTime - sc2arcadeCalcDto.GameTime).TotalSeconds); - //var durationDiff = Math.Abs(dsstatsCalcDto.Duration - sc2arcadeCalcDto.Duration); - - //var durationPerDiff = durationDiff / (double)Math.Max(dsstatsCalcDto.Duration, sc2arcadeCalcDto.Duration); - - // if (gameTimeDiff < 86400 && durationPerDiff < 0.2) - if (gameTimeDiff < 86400) - { - return true; - } - else - { - return false; - } - } - - private static Dictionary> GenerateHashDic(List calcDtos) - { - Dictionary> hashDic = new(); - - for (int i = 0; i < calcDtos.Count; i++) - { - var calcDto = calcDtos[i]; - - var key = string.Join('|', calcDto.Players - .OrderBy(o => o.Team) - .ThenBy(o => o.PlayerId.ToonId) - .Select(s => s.PlayerId.ToonId.ToString())); - // .Select(s => $"{s.ProfileId},{s.RegionId},{s.RealmId}")); - - var gameMode = calcDto.GameMode switch - { - 3 => "Cmdr", - 4 => "Cmdr", - 7 => "Std", - _ => "" - }; - - key = gameMode + key; - - if (!hashDic.TryGetValue(key, out var dtos)) - { - hashDic[key] = new(); - } - hashDic[key].Add(calcDto); - } - return hashDic; - } - - private static void AddHashDic(Dictionary> hashDic, List calcDtos) - { - for (int i = 0; i < calcDtos.Count; i++) - { - var calcDto = calcDtos[i]; - - var key = string.Join('|', calcDto.Players - .OrderBy(o => o.Team) - .ThenBy(o => o.PlayerId.ToonId) - .Select(s => s.PlayerId.ToonId.ToString())); - // .Select(s => $"{s.ProfileId},{s.RegionId},{s.RealmId}")); - - var gameMode = calcDto.GameMode switch - { - 3 => "Cmdr", - 4 => "Cmdr", - 7 => "Std", - _ => "" - }; - - key = gameMode + key; - - if (!hashDic.TryGetValue(key, out var dtos)) - { - hashDic[key] = new(); - } - hashDic[key].Add(calcDto); - } - } - - private async Task> GetComboArcadeCalcDtos(List dsstatsCalcDtos, HashSet processedReplayIds, ReplayContext context) + private async Task> GetComboArcadeCalcDtos(List dsstatsCalcDtos, ReplayContext context) { if (dsstatsCalcDtos.Count == 0) { @@ -237,22 +129,22 @@ private async Task> GetComboArcadeCalcDtos(List dsstatsCa } var query = from r in context.MaterializedArcadeReplays + join m in context.ReplayArcadeMatches on r.ArcadeReplayId equals m.ArcadeReplayId into grouping + from m in grouping.DefaultIfEmpty() orderby r.MaterializedArcadeReplayId where r.MaterializedArcadeReplayId >= startId && r.MaterializedArcadeReplayId <= endId - select new + && m == null + select new CalcDto() { - r.ArcadeReplayId, - CalcDto = new CalcDto() - { - ReplayId = r.ArcadeReplayId, - GameTime = r.CreatedAt, - Duration = r.Duration, - GameMode = (int)r.GameMode, - WinnerTeam = r.WinnerTeam, - TournamentEdition = false, - IsArcade = true, - Players = context.ArcadeReplayPlayers + ReplayId = r.ArcadeReplayId, + GameTime = r.CreatedAt, + Duration = r.Duration, + GameMode = (int)r.GameMode, + WinnerTeam = r.WinnerTeam, + TournamentEdition = false, + IsArcade = true, + Players = context.ArcadeReplayPlayers .Where(x => x.ArcadeReplayId == r.ArcadeReplayId) .Select(t => new PlayerCalcDto() { @@ -262,16 +154,11 @@ orderby r.MaterializedArcadeReplayId Team = t.Team, PlayerId = new(t.ArcadePlayer.ProfileId, t.ArcadePlayer.RealmId, t.ArcadePlayer.RegionId) }).ToList() - } }; - var data = await query + return await query .AsSplitQuery() .ToListAsync(); - - return data.Where(x => !processedReplayIds.Contains(x.ArcadeReplayId)) - .Select(s => s.CalcDto) - .ToList(); } private async Task> GetComboDsstatsCalcDtos(DsstatsCalcRequest request, ReplayContext context) diff --git a/src/dsstats.ratings/RatingsSaveService.Csv2Sql.cs b/src/dsstats.ratings/RatingsSaveService.Csv2Sql.cs index 328682a7..86831b11 100644 --- a/src/dsstats.ratings/RatingsSaveService.Csv2Sql.cs +++ b/src/dsstats.ratings/RatingsSaveService.Csv2Sql.cs @@ -26,7 +26,7 @@ private async Task Csv2Mysql(string fileName, await connection.OpenAsync(); var command = connection.CreateCommand(); - command.CommandTimeout = 360; + command.CommandTimeout = 420; command.CommandText = @$" DROP TABLE IF EXISTS {tempTable}; @@ -93,7 +93,7 @@ private async Task FixDsstatsForeignKey(string connectionString) await connection.OpenAsync(); var command = connection.CreateCommand(); - command.CommandTimeout = 360; + command.CommandTimeout = 420; command.CommandText = @$"ALTER TABLE {nameof(ReplayContext.PlayerRatingChanges)} DROP FOREIGN KEY FK_PlayerRatingChanges_PlayerRatings_PlayerRatingId; ALTER TABLE {nameof(ReplayContext.PlayerRatingChanges)} ADD CONSTRAINT FK_PlayerRatingChanges_PlayerRatings_PlayerRatingId @@ -137,7 +137,7 @@ private async Task DropDsstatsIndexes(string connectionString) await connection.OpenAsync(); var command = connection.CreateCommand(); - command.CommandTimeout = 360; + command.CommandTimeout = 420; command.CommandText = @$"ALTER TABLE {nameof(ReplayContext.RepPlayerRatings)} DROP INDEX `IX_RepPlayerRatings_ReplayPlayerId`; ALTER TABLE {nameof(ReplayContext.RepPlayerRatings)} DROP INDEX `IX_RepPlayerRatings_ReplayRatingInfoId`; @@ -159,7 +159,7 @@ private async Task ReCreateDsstatsIndexes(string connectionString) await connection.OpenAsync(); var command = connection.CreateCommand(); - command.CommandTimeout = 360; + command.CommandTimeout = 420; command.CommandText = @$"CREATE UNIQUE INDEX `IX_RepPlayerRatings_ReplayPlayerId` ON {nameof(ReplayContext.RepPlayerRatings)} ({nameof(RepPlayerRating.ReplayPlayerId)}); CREATE INDEX `IX_RepPlayerRatings_ReplayRatingInfoId` ON {nameof(ReplayContext.RepPlayerRatings)} ({nameof(RepPlayerRating.ReplayRatingInfoId)});"; diff --git a/src/dsstats.ratings/dsstats.ratings.csproj b/src/dsstats.ratings/dsstats.ratings.csproj index 04eb89e8..13cbf644 100644 --- a/src/dsstats.ratings/dsstats.ratings.csproj +++ b/src/dsstats.ratings/dsstats.ratings.csproj @@ -7,7 +7,7 @@ - + diff --git a/src/dsstats.razorlib/Players/TopPlayersComponent.razor b/src/dsstats.razorlib/Players/TopPlayersComponent.razor index db69b7f2..d621a228 100644 --- a/src/dsstats.razorlib/Players/TopPlayersComponent.razor +++ b/src/dsstats.razorlib/Players/TopPlayersComponent.razor @@ -103,6 +103,7 @@ Skip = 0, Take = 7, ComboRating = true, + Active = true, Orders = new() { new() diff --git a/src/dsstats.razorlib/Replays/ArcadeReplayComponent.razor b/src/dsstats.razorlib/Replays/ArcadeReplayComponent.razor index 9b48bdfc..18427a04 100644 --- a/src/dsstats.razorlib/Replays/ArcadeReplayComponent.razor +++ b/src/dsstats.razorlib/Replays/ArcadeReplayComponent.razor @@ -88,8 +88,8 @@ + style="max-width: 120px;" data-bs-toggle="tooltip" data-bs-placement="top" + data-bs-title="@HelperService.SanitizePlayerName(player.Name)"> @player.Name @@ -114,7 +114,14 @@ diff --git a/src/dsstats.razorlib/Replays/ReplayComponent.razor b/src/dsstats.razorlib/Replays/ReplayComponent.razor index 2281496a..035539b3 100644 --- a/src/dsstats.razorlib/Replays/ReplayComponent.razor +++ b/src/dsstats.razorlib/Replays/ReplayComponent.razor @@ -220,6 +220,13 @@ Downloads @Replay.Downloads } + @if (LoadArcadeReplayEnabled()) + { +
+ +
+ } + @if (!string.IsNullOrEmpty(Replay.FileName)) {
@@ -253,6 +260,20 @@ OnCloseRequested="ClosePlayerDetails" OnPlayerReplaysRequested="OnPlayerReplaysRequested" /> } +@if (arcadeReplay is not null) +{ +
+ +
+} +else if (noArcadeReplayFound) +{ +
+ No Arcade Replay found. +
+} @code { [Parameter, EditorRequired] @@ -266,9 +287,13 @@ [Parameter] public bool IsScrollable { get; set; } + [Parameter] public EventCallback OnScrollRequest { get; set; } + [Parameter] + public bool CanLoadArcadeReplay { get; set; } + [Parameter] public EventCallback OnPlayerReplaysRequested { get; set; } @@ -291,6 +316,9 @@ PlayerId? interestPlayer = null; RatingType ratingType = RatingType.Cmdr; + ArcadeReplayDto? arcadeReplay = null; + bool noArcadeReplayFound; + Dictionary> AvailableBreakpoints = new() { { 0, new() { Breakpoint.All }}, @@ -339,6 +367,8 @@ { comboRating = true; } + arcadeReplay = null; + noArcadeReplayFound = false; interestPlayer = null; showRating = false; showReplayPath = false; @@ -456,4 +486,23 @@ replayPlayersDetailContainer?.SetBreakpoint(breakpoint); } + + private async Task LoadArcadeReplay() + { + arcadeReplay = await replaysService.GetDssstatsArcadeReplay(Replay.ReplayHash); + if (arcadeReplay is null) + { + noArcadeReplayFound = true; + } + await InvokeAsync(() => StateHasChanged()); + } + + private bool LoadArcadeReplayEnabled() + { + return CanLoadArcadeReplay && Replay.ReplayPlayers.Count == 6 + && Replay.TournamentEdition == false + && (Replay.GameMode == GameMode.Commanders + || Replay.GameMode == GameMode.Standard + || Replay.GameMode == GameMode.CommandersHeroic); + } } \ No newline at end of file diff --git a/src/dsstats.razorlib/Replays/ReplaysComponent.razor b/src/dsstats.razorlib/Replays/ReplaysComponent.razor index 70d863d8..8e532631 100644 --- a/src/dsstats.razorlib/Replays/ReplaysComponent.razor +++ b/src/dsstats.razorlib/Replays/ReplaysComponent.razor @@ -48,7 +48,8 @@ { + OnPlayerReplaysRequested="PlayerReplaysRequest" + CanLoadArcadeReplay="true"/> } @if (interestArcadeReplay is not null) @@ -413,7 +414,7 @@ { if (Request.Arcade) { - lastestInterestReplayHash = interestArcadeReplay?.ReplayHash; + lastestInterestReplayHash = interestArcadeReplay?.GetBnetHash(); } else { diff --git a/src/dsstats.razorlib/dsstats.razorlib.csproj b/src/dsstats.razorlib/dsstats.razorlib.csproj index 35353d48..2577f6ea 100644 --- a/src/dsstats.razorlib/dsstats.razorlib.csproj +++ b/src/dsstats.razorlib/dsstats.razorlib.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/src/dsstats.shared/ArcadeReplayDto.cs b/src/dsstats.shared/ArcadeReplayDto.cs index bb29d2cd..9d341957 100644 --- a/src/dsstats.shared/ArcadeReplayDto.cs +++ b/src/dsstats.shared/ArcadeReplayDto.cs @@ -45,14 +45,19 @@ public record ArcadeReplayListDto public record ArcadeReplayDto { - public string ReplayHash { get; set; } = string.Empty; public DateTime CreatedAt { get; set; } public GameMode GameMode { get; set; } public int RegionId { get; set; } + public long BnetBucketId { get; set; } + public long BnetRecordId { get; set; } public int WinnerTeam { get; set; } public int Duration { get; set; } public ArcadeReplayRatingDto? ArcadeReplayRating { get; set; } public List ArcadeReplayPlayers { get; set; } = new(); + public string GetBnetHash() + { + return $"{RegionId}|{BnetBucketId}|{BnetRecordId}"; + } } public record ArcadeReplayPlayerDto diff --git a/src/dsstats.shared/Calc/CalcDtos.cs b/src/dsstats.shared/Calc/CalcDtos.cs index 87fe6db3..67588094 100644 --- a/src/dsstats.shared/Calc/CalcDtos.cs +++ b/src/dsstats.shared/Calc/CalcDtos.cs @@ -42,6 +42,7 @@ public record DsstatsCalcRequest public bool Continue { get; set; } public int Skip { get; set; } public int Take { get; set; } + public DateTime Imported { get; set; } } public record Sc2ArcadeRequest diff --git a/src/dsstats.shared/Interfaces/IRatingService.cs b/src/dsstats.shared/Interfaces/IRatingService.cs index 46820cd6..159511c4 100644 --- a/src/dsstats.shared/Interfaces/IRatingService.cs +++ b/src/dsstats.shared/Interfaces/IRatingService.cs @@ -6,5 +6,4 @@ public interface IRatingService { Task> GetDsstatsCalcDtos(DsstatsCalcRequest request); Task ProduceRatings(RatingCalcType ratingCalcType, bool recalc = false); - Task CombineTest(); } \ No newline at end of file diff --git a/src/dsstats.shared/Interfaces/IReplaysService.cs b/src/dsstats.shared/Interfaces/IReplaysService.cs index ce7ba36c..ec01d1e9 100644 --- a/src/dsstats.shared/Interfaces/IReplaysService.cs +++ b/src/dsstats.shared/Interfaces/IReplaysService.cs @@ -8,4 +8,5 @@ public interface IReplaysService Task GetReplay(string replayHash, bool dry = false, CancellationToken token = default); Task GetReplayRating(string replayHash, bool comboRating); Task GetArcadeReplay(string hash, CancellationToken token = default); + Task GetDssstatsArcadeReplay(string replayHash, CancellationToken token = default); } \ No newline at end of file diff --git a/src/dsstats.web/dsstats.authclient/dsstats.authclient.csproj b/src/dsstats.web/dsstats.authclient/dsstats.authclient.csproj index 97445c94..7efa8ae0 100644 --- a/src/dsstats.web/dsstats.authclient/dsstats.authclient.csproj +++ b/src/dsstats.web/dsstats.authclient/dsstats.authclient.csproj @@ -13,8 +13,8 @@ - - + + diff --git a/src/dsstats.web/dsstats.web.Client/dsstats.web.Client.csproj b/src/dsstats.web/dsstats.web.Client/dsstats.web.Client.csproj index 07b79331..0eda63d7 100644 --- a/src/dsstats.web/dsstats.web.Client/dsstats.web.Client.csproj +++ b/src/dsstats.web/dsstats.web.Client/dsstats.web.Client.csproj @@ -10,10 +10,10 @@ - - + + - + diff --git a/src/dsstats.web/dsstats.web/dsstats.web.csproj b/src/dsstats.web/dsstats.web/dsstats.web.csproj index 80998f5d..63485d23 100644 --- a/src/dsstats.web/dsstats.web/dsstats.web.csproj +++ b/src/dsstats.web/dsstats.web/dsstats.web.csproj @@ -12,7 +12,7 @@ - + diff --git a/src/tests/dsstats.pickban.tests/dsstats.pickban.tests.csproj b/src/tests/dsstats.pickban.tests/dsstats.pickban.tests.csproj index 67f6d459..e17c1573 100644 --- a/src/tests/dsstats.pickban.tests/dsstats.pickban.tests.csproj +++ b/src/tests/dsstats.pickban.tests/dsstats.pickban.tests.csproj @@ -10,10 +10,13 @@ - - - - + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + diff --git a/src/tests/dsstats.ratings.tests/ComboRatingTests.cs b/src/tests/dsstats.ratings.tests/ComboRatingTests.cs index b3fc82b1..85fe26d9 100644 --- a/src/tests/dsstats.ratings.tests/ComboRatingTests.cs +++ b/src/tests/dsstats.ratings.tests/ComboRatingTests.cs @@ -58,7 +58,7 @@ public ComboRatingsTests() services.AddLogging(); services.AddMemoryCache(); services.AddAutoMapper(typeof(AutoMapperProfile)); - + services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/tests/dsstats.ratings.tests/RatingsTests.cs b/src/tests/dsstats.ratings.tests/RatingsTests.cs index b179e9ee..dcf17731 100644 --- a/src/tests/dsstats.ratings.tests/RatingsTests.cs +++ b/src/tests/dsstats.ratings.tests/RatingsTests.cs @@ -58,7 +58,7 @@ public RatingsTests() services.AddLogging(); services.AddMemoryCache(); services.AddAutoMapper(typeof(AutoMapperProfile)); - + services.AddScoped(); services.AddSingleton(); services.AddSingleton(); services.AddSingleton();