From 61176d81f683a2a4a69d2abe9877f7351ba33f38 Mon Sep 17 00:00:00 2001 From: Jay Malhotra <5047192+SapiensAnatis@users.noreply.github.com> Date: Sun, 16 Jul 2023 16:54:32 +0100 Subject: [PATCH] Add 'preferred team' feature (#307) Implements: - /quest/get_quest_clear_party - /quest/get_quest_clear_party_multi - /quest/set_quest_clear_party - /quest/set_quest_clear_party_multi Includes a new database table for saved clear units, and also logic to detect when entities from saved parties are missing. Saved clear parties are exempted from the save import deletion process, as they are not contained in a save, so wiping them on every import seemed harsh. As a result, they may contain entities which the user no longer owns. Fortunately, the game provides a mechanism to handle this in the form of "lost_unit_list", which shows a pop-up indicating what entities cannot be retrieved from the clear party. This is probably intended for entities which can normally be lost, like dragons or portrait prints, but seems to work sort of okay with weapons and wyrmprints: There is however no entity type for missing shared skills, and missing characters will cause the button to be disabled entirely. --- DragaliaAPI.Database/ApiContext.cs | 2 + .../Entities/Abstract/DbPartyUnitBase.cs | 17 + .../Entities/Abstract/DbUnitBase.cs | 31 + DragaliaAPI.Database/Entities/DbPartyUnit.cs | 33 +- .../Entities/DbQuestClearPartyUnit.cs | 53 + DragaliaAPI.Database/Entities/DbSetUnit.cs | 28 +- .../Entities/Scaffold/DbDetailedPartyUnit.cs | 6 +- ...0715142823_quest-clear-parties.Designer.cs | 1772 ++++++++++++++++ .../20230715142823_quest-clear-parties.cs | 56 + ...15171619_quest-clear-parties-2.Designer.cs | 1778 +++++++++++++++++ .../20230715171619_quest-clear-parties-2.cs | 40 + .../Migrations/ApiContextModelSnapshot.cs | 92 +- .../CustomWebApplicationFactory.cs | 3 +- .../Dragalia/QuestClearPartyTest.cs | 474 +++++ .../{QuestTest.cs => QuestReadStoryTest.cs} | 12 +- DragaliaAPI.Integration.Test/TestFixture.cs | 2 + .../Definitions/Enums/AbilityCrests.cs | 1 + .../Definitions/Enums/Dragons.cs | 1 + .../Definitions/Enums/Talismans.cs | 1 + .../Controllers/QuestControllerTest.cs | 5 + .../AutoMapper/Profiles/UnitMapProfile.cs | 7 + .../Profiles/UnitReverseMapProfile.cs | 7 + .../Dragalia/MatchingController.cs | 3 +- .../Controllers/Dragalia/QuestController.cs | 205 -- .../Controllers/Dragalia/SummonController.cs | 2 +- .../Extensions/IEnumerableExtensions.cs | 5 +- .../ClearParty/ClearPartyRepository.cs | 45 + .../Features/ClearParty/ClearPartyService.cs | 352 ++++ .../ClearParty/IClearPartyRepository.cs | 11 + .../Features/ClearParty/IClearPartyService.cs | 12 + .../Features/Dungeon/DungeonRepository.cs | 140 +- .../Features/Dungeon/IDungeonRepository.cs | 3 + DragaliaAPI/Features/Quest/QuestController.cs | 162 ++ DragaliaAPI/Models/Generated/Components.cs | 66 +- DragaliaAPI/Program.cs | 6 +- .../Services/Photon/HeroParamService.cs | 4 - 36 files changed, 5119 insertions(+), 318 deletions(-) create mode 100644 DragaliaAPI.Database/Entities/Abstract/DbPartyUnitBase.cs create mode 100644 DragaliaAPI.Database/Entities/Abstract/DbUnitBase.cs create mode 100644 DragaliaAPI.Database/Entities/DbQuestClearPartyUnit.cs create mode 100644 DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.Designer.cs create mode 100644 DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.cs create mode 100644 DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.Designer.cs create mode 100644 DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.cs create mode 100644 DragaliaAPI.Integration.Test/Dragalia/QuestClearPartyTest.cs rename DragaliaAPI.Integration.Test/Dragalia/{QuestTest.cs => QuestReadStoryTest.cs} (87%) delete mode 100644 DragaliaAPI/Controllers/Dragalia/QuestController.cs create mode 100644 DragaliaAPI/Features/ClearParty/ClearPartyRepository.cs create mode 100644 DragaliaAPI/Features/ClearParty/ClearPartyService.cs create mode 100644 DragaliaAPI/Features/ClearParty/IClearPartyRepository.cs create mode 100644 DragaliaAPI/Features/ClearParty/IClearPartyService.cs create mode 100644 DragaliaAPI/Features/Quest/QuestController.cs diff --git a/DragaliaAPI.Database/ApiContext.cs b/DragaliaAPI.Database/ApiContext.cs index 0ac319b6a..e9d600703 100644 --- a/DragaliaAPI.Database/ApiContext.cs +++ b/DragaliaAPI.Database/ApiContext.cs @@ -155,4 +155,6 @@ but EF Core doesn't like this and the client probably stops you anyway? public DbSet PlayerPurchases { get; set; } public DbSet PlayerTrades { get; set; } + + public DbSet QuestClearPartyUnits { get; set; } } diff --git a/DragaliaAPI.Database/Entities/Abstract/DbPartyUnitBase.cs b/DragaliaAPI.Database/Entities/Abstract/DbPartyUnitBase.cs new file mode 100644 index 000000000..bbd16ae3f --- /dev/null +++ b/DragaliaAPI.Database/Entities/Abstract/DbPartyUnitBase.cs @@ -0,0 +1,17 @@ +using DragaliaAPI.Shared.Definitions.Enums; + +namespace DragaliaAPI.Database.Entities.Abstract; + +/// +/// Base class for party units with edit skills / weapon skins equipped. +/// +public abstract class DbPartyUnitBase : DbUnitBase +{ + public int EquipWeaponSkinId { get; set; } + + public Charas EditSkill1CharaId { get; set; } + + public Charas EditSkill2CharaId { get; set; } + + public required int UnitNo { get; set; } +} diff --git a/DragaliaAPI.Database/Entities/Abstract/DbUnitBase.cs b/DragaliaAPI.Database/Entities/Abstract/DbUnitBase.cs new file mode 100644 index 000000000..130aa2645 --- /dev/null +++ b/DragaliaAPI.Database/Entities/Abstract/DbUnitBase.cs @@ -0,0 +1,31 @@ +using DragaliaAPI.Shared.Definitions.Enums; + +namespace DragaliaAPI.Database.Entities.Abstract; + +/// +/// Base class for party units and unit equipment set entries. +/// +public abstract class DbUnitBase +{ + public Charas CharaId { get; set; } + + public long EquipDragonKeyId { get; set; } + + public WeaponBodies EquipWeaponBodyId { get; set; } + + public AbilityCrests EquipCrestSlotType1CrestId1 { get; set; } + + public AbilityCrests EquipCrestSlotType1CrestId2 { get; set; } + + public AbilityCrests EquipCrestSlotType1CrestId3 { get; set; } + + public AbilityCrests EquipCrestSlotType2CrestId1 { get; set; } + + public AbilityCrests EquipCrestSlotType2CrestId2 { get; set; } + + public AbilityCrests EquipCrestSlotType3CrestId1 { get; set; } + + public AbilityCrests EquipCrestSlotType3CrestId2 { get; set; } + + public long EquipTalismanKeyId { get; set; } +} diff --git a/DragaliaAPI.Database/Entities/DbPartyUnit.cs b/DragaliaAPI.Database/Entities/DbPartyUnit.cs index ea6dc73d3..a5366877b 100644 --- a/DragaliaAPI.Database/Entities/DbPartyUnit.cs +++ b/DragaliaAPI.Database/Entities/DbPartyUnit.cs @@ -1,12 +1,13 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using DragaliaAPI.Database.Entities.Abstract; using DragaliaAPI.Shared.Definitions.Enums; using Microsoft.EntityFrameworkCore; namespace DragaliaAPI.Database.Entities; [Index(nameof(DeviceAccountId))] -public class DbPartyUnit +public class DbPartyUnit : DbPartyUnitBase { // In theory, a composite primary key of [Party, UnitNo] would work great. // However, EF Core doesn't like navigation properties being used as keys. @@ -19,34 +20,4 @@ public class DbPartyUnit public string DeviceAccountId { get; set; } = string.Empty; public int PartyNo { get; set; } - - public required int UnitNo { get; set; } - - public required Charas CharaId { get; set; } - - public long EquipDragonKeyId { get; set; } = 0; - - public WeaponBodies EquipWeaponBodyId { get; set; } - - public int EquipWeaponSkinId { get; set; } - - public AbilityCrests EquipCrestSlotType1CrestId1 { get; set; } - - public AbilityCrests EquipCrestSlotType1CrestId2 { get; set; } - - public AbilityCrests EquipCrestSlotType1CrestId3 { get; set; } - - public AbilityCrests EquipCrestSlotType2CrestId1 { get; set; } - - public AbilityCrests EquipCrestSlotType2CrestId2 { get; set; } - - public AbilityCrests EquipCrestSlotType3CrestId1 { get; set; } - - public AbilityCrests EquipCrestSlotType3CrestId2 { get; set; } - - public long EquipTalismanKeyId { get; set; } - - public Charas EditSkill1CharaId { get; set; } - - public Charas EditSkill2CharaId { get; set; } } diff --git a/DragaliaAPI.Database/Entities/DbQuestClearPartyUnit.cs b/DragaliaAPI.Database/Entities/DbQuestClearPartyUnit.cs new file mode 100644 index 000000000..72efc319c --- /dev/null +++ b/DragaliaAPI.Database/Entities/DbQuestClearPartyUnit.cs @@ -0,0 +1,53 @@ +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using DragaliaAPI.Database.Entities.Abstract; +using DragaliaAPI.Shared.Definitions.Enums; +using Microsoft.EntityFrameworkCore; + +namespace DragaliaAPI.Database.Entities; + +[PrimaryKey(nameof(DeviceAccountId), nameof(QuestId), nameof(IsMulti), nameof(UnitNo))] +public class DbQuestClearPartyUnit : DbPartyUnitBase, IDbHasAccountId +{ + public virtual DbPlayer? Owner { get; set; } + + [ForeignKey(nameof(Owner))] + public required string DeviceAccountId { get; set; } + + public required int QuestId { get; set; } + + public required bool IsMulti { get; set; } + + public Dragons EquippedDragonEntityId { get; set; } + + public Talismans EquippedTalismanEntityId { get; set; } + + /// + /// Reset this entity back to a state representing an empty slot. + /// + public void Clear() + { + this.CharaId = Charas.Empty; + + this.EquipWeaponBodyId = WeaponBodies.Empty; + this.EquipWeaponSkinId = 0; + + this.EquipDragonKeyId = 0; + this.EquipTalismanKeyId = 0; + this.EquippedDragonEntityId = Dragons.Empty; + this.EquippedTalismanEntityId = Talismans.Empty; + + this.EquipCrestSlotType1CrestId1 = AbilityCrests.Empty; + this.EquipCrestSlotType1CrestId2 = AbilityCrests.Empty; + this.EquipCrestSlotType1CrestId3 = AbilityCrests.Empty; + + this.EquipCrestSlotType2CrestId1 = AbilityCrests.Empty; + this.EquipCrestSlotType2CrestId2 = AbilityCrests.Empty; + + this.EquipCrestSlotType3CrestId1 = AbilityCrests.Empty; + this.EquipCrestSlotType3CrestId2 = AbilityCrests.Empty; + + this.EditSkill1CharaId = Charas.Empty; + this.EditSkill2CharaId = Charas.Empty; + } +} diff --git a/DragaliaAPI.Database/Entities/DbSetUnit.cs b/DragaliaAPI.Database/Entities/DbSetUnit.cs index 250a7b072..7819f8049 100644 --- a/DragaliaAPI.Database/Entities/DbSetUnit.cs +++ b/DragaliaAPI.Database/Entities/DbSetUnit.cs @@ -1,47 +1,23 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; +using DragaliaAPI.Database.Entities.Abstract; using DragaliaAPI.Shared.Definitions.Enums; using Microsoft.EntityFrameworkCore; namespace DragaliaAPI.Database.Entities; -//TODO: This and PartyUnit share a lot of properties, maybe extract those and make these into subclasses which inherit them [Table("PlayerSetUnit")] [Index(nameof(DeviceAccountId))] -public class DbSetUnit : IDbHasAccountId +public class DbSetUnit : DbUnitBase, IDbHasAccountId { /// public virtual DbPlayer? Owner { get; set; } - /// [ForeignKey(nameof(Owner))] public required string DeviceAccountId { get; set; } - [Required] - public Charas CharaId { get; set; } - [Required] public int UnitSetNo { get; set; } public required string UnitSetName { get; set; } - - public long EquipDragonKeyId { get; set; } - - public int EquipWeaponBodyId { get; set; } - - public int EquipCrestSlotType1CrestId1 { get; set; } - - public int EquipCrestSlotType1CrestId2 { get; set; } - - public int EquipCrestSlotType1CrestId3 { get; set; } - - public int EquipCrestSlotType2CrestId1 { get; set; } - - public int EquipCrestSlotType2CrestId2 { get; set; } - - public int EquipCrestSlotType3CrestId1 { get; set; } - - public int EquipCrestSlotType3CrestId2 { get; set; } - - public long EquipTalismanKeyId { get; set; } } diff --git a/DragaliaAPI.Database/Entities/Scaffold/DbDetailedPartyUnit.cs b/DragaliaAPI.Database/Entities/Scaffold/DbDetailedPartyUnit.cs index 3366c9406..0f748f02c 100644 --- a/DragaliaAPI.Database/Entities/Scaffold/DbDetailedPartyUnit.cs +++ b/DragaliaAPI.Database/Entities/Scaffold/DbDetailedPartyUnit.cs @@ -8,6 +8,8 @@ public class DbDetailedPartyUnit { public required string DeviceAccountId { get; set; } + public int PartyNo { get; set; } + public int Position { get; set; } public required DbPlayerCharaData CharaData { get; set; } @@ -21,10 +23,10 @@ public class DbDetailedPartyUnit public IEnumerable CrestSlotType1CrestList { get; set; } = Enumerable.Empty(); - public IEnumerable CrestSlotType2CrestList { get; set; } = + public IEnumerable CrestSlotType2CrestList { get; set; } = Enumerable.Empty(); - public IEnumerable CrestSlotType3CrestList { get; set; } = + public IEnumerable CrestSlotType3CrestList { get; set; } = Enumerable.Empty(); public DbWeaponSkin? WeaponSkinData { get; set; } = null; diff --git a/DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.Designer.cs b/DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.Designer.cs new file mode 100644 index 000000000..9b66c1ad6 --- /dev/null +++ b/DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.Designer.cs @@ -0,0 +1,1772 @@ +// +using System; +using DragaliaAPI.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DragaliaAPI.Database.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20230715142823_quest-clear-parties")] + partial class questclearparties + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrest", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("AbilityCrestId") + .HasColumnType("integer"); + + b.Property("AttackPlusCount") + .HasColumnType("integer"); + + b.Property("BuildupCount") + .HasColumnType("integer"); + + b.Property("EquipableCount") + .HasColumnType("integer"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("HpPlusCount") + .HasColumnType("integer"); + + b.Property("IsFavorite") + .HasColumnType("boolean"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("LimitBreakCount") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "AbilityCrestId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerAbilityCrests"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrestSet", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("AbilityCrestSetNo") + .HasColumnType("integer"); + + b.Property("AbilityCrestSetName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("CrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("CrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("CrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("CrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("CrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("CrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("TalismanKeyId") + .HasColumnType("numeric(20,0)"); + + b.HasKey("DeviceAccountId", "AbilityCrestSetNo"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerAbilityCrestSets"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbDeviceAccount", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("HashedPassword") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DeviceAccounts"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbEquippedStamp", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("Slot") + .HasColumnType("integer"); + + b.Property("StampId") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "Slot"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("EquippedStamps"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortBuild", b => + { + b.Property("BuildId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BuildId")); + + b.Property("BuildEndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("BuildStartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("LastIncomeDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("PlantId") + .HasColumnType("integer"); + + b.Property("PositionX") + .HasColumnType("integer"); + + b.Property("PositionZ") + .HasColumnType("integer"); + + b.HasKey("BuildId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerFortBuilds"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortDetail", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CarpenterNum") + .HasColumnType("integer") + .HasColumnName("CarpenterNum"); + + b.HasKey("DeviceAccountId"); + + b.HasIndex("DeviceAccountId") + .IsUnique(); + + b.ToTable("PlayerFortDetail"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbParty", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("PartyNo") + .HasColumnType("integer"); + + b.Property("PartyName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("DeviceAccountId", "PartyNo"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PartyData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPartyUnit", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EditSkill1CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill2CharaId") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("EquipDragonKeyId") + .HasColumnType("bigint"); + + b.Property("EquipTalismanKeyId") + .HasColumnType("bigint"); + + b.Property("EquipWeaponBodyId") + .HasColumnType("integer"); + + b.Property("EquipWeaponSkinId") + .HasColumnType("integer"); + + b.Property("PartyNo") + .HasColumnType("integer"); + + b.Property("UnitNo") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DeviceAccountId"); + + b.HasIndex("DeviceAccountId", "PartyNo"); + + b.ToTable("PlayerPartyUnits"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayer", b => + { + b.Property("AccountId") + .HasColumnType("text"); + + b.Property("SavefileVersion") + .HasColumnType("integer"); + + b.HasKey("AccountId"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerBannerData", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("SummonBannerId") + .HasColumnType("integer") + .HasColumnName("SummonBannerId"); + + b.Property("ConsecutionSummonPoints") + .HasColumnType("integer") + .HasColumnName("CsSummonPoints"); + + b.Property("ConsecutionSummonPointsMaxDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("CsSummonPointsMaxDate"); + + b.Property("ConsecutionSummonPointsMinDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("CsSummonPointsMinDate"); + + b.Property("DailyLimitedSummonCount") + .HasColumnType("integer") + .HasColumnName("DailyLimitedSummons"); + + b.Property("IsBeginnerFreeSummonAvailable") + .HasColumnType("integer") + .HasColumnName("BeginnerSummonAvailable"); + + b.Property("IsConsecutionFreeSummonAvailable") + .HasColumnType("integer") + .HasColumnName("CsSummonAvailable"); + + b.Property("IsFreeSummonAvailable") + .HasColumnType("integer") + .HasColumnName("FreeSummonAvailable"); + + b.Property("PityRate") + .HasColumnType("smallint") + .HasColumnName("Pity"); + + b.Property("SummonCount") + .HasColumnType("integer") + .HasColumnName("SummonCount"); + + b.Property("SummonPoints") + .HasColumnType("integer") + .HasColumnName("SummonPoints"); + + b.HasKey("DeviceAccountId", "SummonBannerId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerBannerData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCharaData", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer") + .HasColumnName("CharaId"); + + b.Property("Ability1Level") + .HasColumnType("smallint") + .HasColumnName("Abil1Lvl"); + + b.Property("Ability2Level") + .HasColumnType("smallint") + .HasColumnName("Abil2Lvl"); + + b.Property("Ability3Level") + .HasColumnType("smallint") + .HasColumnName("Abil3Lvl"); + + b.Property("AttackBase") + .HasColumnType("integer") + .HasColumnName("AtkBase"); + + b.Property("AttackNode") + .HasColumnType("integer") + .HasColumnName("AtkNode"); + + b.Property("AttackPlusCount") + .HasColumnType("smallint") + .HasColumnName("AtkPlusCount"); + + b.Property("BurstAttackLevel") + .HasColumnType("smallint") + .HasColumnName("BurstAtkLvl"); + + b.Property("ComboBuildupCount") + .HasColumnType("integer") + .HasColumnName("ComboBuildupCount"); + + b.Property("ExAbility2Level") + .HasColumnType("smallint") + .HasColumnName("ExAbility2Lvl"); + + b.Property("ExAbilityLevel") + .HasColumnType("smallint") + .HasColumnName("ExAbility1Lvl"); + + b.Property("Exp") + .HasColumnType("integer") + .HasColumnName("Exp"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("GetTime"); + + b.Property("HpBase") + .HasColumnType("integer") + .HasColumnName("HpBase"); + + b.Property("HpNode") + .HasColumnType("integer") + .HasColumnName("HpNode"); + + b.Property("HpPlusCount") + .HasColumnType("smallint") + .HasColumnName("HpPlusCount"); + + b.Property("IsNew") + .HasColumnType("boolean") + .HasColumnName("IsNew"); + + b.Property("IsTemporary") + .HasColumnType("boolean") + .HasColumnName("IsTemp"); + + b.Property("IsUnlockEditSkill") + .HasColumnType("boolean") + .HasColumnName("IsUnlockEditSkill"); + + b.Property("Level") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.Property("ListViewFlag") + .HasColumnType("boolean") + .HasColumnName("ListViewFlag"); + + b.Property("ManaNodeUnlockCount") + .HasColumnType("integer") + .HasColumnName("ManaNodeUnlockCount"); + + b.Property("Rarity") + .HasColumnType("smallint") + .HasColumnName("Rarity"); + + b.Property("Skill1Level") + .HasColumnType("smallint") + .HasColumnName("Skill1Lvl"); + + b.Property("Skill2Level") + .HasColumnType("smallint") + .HasColumnName("Skill2Lvl"); + + b.HasKey("DeviceAccountId", "CharaId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerCharaData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCurrency", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CurrencyType") + .HasColumnType("integer") + .HasColumnName("CurrencyType"); + + b.Property("Quantity") + .HasColumnType("bigint") + .HasColumnName("Quantity"); + + b.HasKey("DeviceAccountId", "CurrencyType"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerCurrency"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonData", b => + { + b.Property("DragonKeyId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("DragonKeyId"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("DragonKeyId")); + + b.Property("Ability1Level") + .HasColumnType("smallint") + .HasColumnName("Abil1Level"); + + b.Property("Ability2Level") + .HasColumnType("smallint") + .HasColumnName("Abil2Level"); + + b.Property("AttackPlusCount") + .HasColumnType("smallint") + .HasColumnName("AttackPlusCount"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("DragonId") + .HasColumnType("integer") + .HasColumnName("DragonId"); + + b.Property("Exp") + .HasColumnType("integer") + .HasColumnName("Exp"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("GetTime"); + + b.Property("HpPlusCount") + .HasColumnType("smallint") + .HasColumnName("HpPlusCount"); + + b.Property("IsLock") + .HasColumnType("boolean") + .HasColumnName("IsLocked"); + + b.Property("IsNew") + .HasColumnType("boolean") + .HasColumnName("IsNew"); + + b.Property("Level") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.Property("LimitBreakCount") + .HasColumnType("smallint") + .HasColumnName("LimitBreakCount"); + + b.Property("Skill1Level") + .HasColumnType("smallint") + .HasColumnName("Skill1Level"); + + b.HasKey("DragonKeyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerDragonData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonGift", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text") + .HasColumnName("DeviceAccountId"); + + b.Property("DragonGiftId") + .HasColumnType("integer") + .HasColumnName("DragonGiftId"); + + b.Property("Quantity") + .HasColumnType("integer") + .HasColumnName("Quantity"); + + b.HasKey("DeviceAccountId", "DragonGiftId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerDragonGift"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonReliability", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("DragonId") + .HasColumnType("integer") + .HasColumnName("DragonId"); + + b.Property("Exp") + .HasColumnType("integer") + .HasColumnName("TotalExp"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastContactTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastContactTime"); + + b.Property("Level") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.HasKey("DeviceAccountId", "DragonId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerDragonReliability"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMaterial", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("MaterialId") + .HasColumnType("integer") + .HasColumnName("MaterialId"); + + b.Property("Quantity") + .HasColumnType("integer") + .HasColumnName("Quantity"); + + b.HasKey("DeviceAccountId", "MaterialId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerMaterial"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMission", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("MissionId"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("Type"); + + b.Property("End") + .HasColumnType("timestamp with time zone") + .HasColumnName("EndDate"); + + b.Property("GroupId") + .HasColumnType("integer") + .HasColumnName("GroupId"); + + b.Property("Pickup") + .HasColumnType("boolean") + .HasColumnName("Pickup"); + + b.Property("Progress") + .HasColumnType("integer") + .HasColumnName("Progress"); + + b.Property("Start") + .HasColumnType("timestamp with time zone") + .HasColumnName("StartDate"); + + b.Property("State") + .HasColumnType("integer") + .HasColumnName("State"); + + b.HasKey("DeviceAccountId", "Id", "Type"); + + b.ToTable("PlayerMissions"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresent", b => + { + b.Property("PresentId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("PresentId"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("PresentId")); + + b.Property("CreateTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreateTime"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityId") + .HasColumnType("integer") + .HasColumnName("EntityId"); + + b.Property("EntityLevel") + .HasColumnType("integer") + .HasColumnName("EntityLevel"); + + b.Property("EntityLimitBreakCount") + .HasColumnType("integer") + .HasColumnName("EntityLimitBreakCount"); + + b.Property("EntityQuantity") + .HasColumnType("integer") + .HasColumnName("EntityQuantity"); + + b.Property("EntityStatusPlusCount") + .HasColumnType("integer") + .HasColumnName("EntityStatusPlusCount"); + + b.Property("EntityType") + .HasColumnType("integer") + .HasColumnName("EntityType"); + + b.Property("MasterId") + .HasColumnType("bigint") + .HasColumnName("MasterId"); + + b.Property("MessageId") + .HasColumnType("integer") + .HasColumnName("MessageId"); + + b.Property("MessageParamValue1") + .HasColumnType("integer") + .HasColumnName("MessageParamValue1"); + + b.Property("MessageParamValue2") + .HasColumnType("integer") + .HasColumnName("MessageParamValue2"); + + b.Property("MessageParamValue3") + .HasColumnType("integer") + .HasColumnName("MessageParamValue3"); + + b.Property("MessageParamValue4") + .HasColumnType("integer") + .HasColumnName("MessageParamValue4"); + + b.Property("ReceiveLimitTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("ReceiveLimitTime"); + + b.Property("State") + .HasColumnType("bigint") + .HasColumnName("State"); + + b.HasKey("PresentId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPresent"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresentHistory", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CreateTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreateTime"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityId") + .HasColumnType("integer") + .HasColumnName("EntityId"); + + b.Property("EntityLevel") + .HasColumnType("integer") + .HasColumnName("EntityLevel"); + + b.Property("EntityLimitBreakCount") + .HasColumnType("integer") + .HasColumnName("EntityLimitBreakCount"); + + b.Property("EntityQuantity") + .HasColumnType("integer") + .HasColumnName("EntityQuantity"); + + b.Property("EntityStatusPlusCount") + .HasColumnType("integer") + .HasColumnName("EntityStatusPlusCount"); + + b.Property("EntityType") + .HasColumnType("integer") + .HasColumnName("EntityType"); + + b.Property("MessageId") + .HasColumnType("integer") + .HasColumnName("MessageId"); + + b.Property("MessageParamValue1") + .HasColumnType("integer") + .HasColumnName("MessageParamValue1"); + + b.Property("MessageParamValue2") + .HasColumnType("integer") + .HasColumnName("MessageParamValue2"); + + b.Property("MessageParamValue3") + .HasColumnType("integer") + .HasColumnName("MessageParamValue3"); + + b.Property("MessageParamValue4") + .HasColumnType("integer") + .HasColumnName("MessageParamValue4"); + + b.HasKey("Id"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPresentHistory"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopInfo", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("DailySummonCount") + .HasColumnType("integer"); + + b.Property("LastSummonTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("DeviceAccountId"); + + b.ToTable("PlayerShopInfos"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopPurchase", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("GoodsId") + .HasColumnType("integer"); + + b.Property("BuyCount") + .HasColumnType("integer"); + + b.Property("EffectEndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("EffectStartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastBuyTime") + .HasColumnType("timestamp with time zone"); + + b.Property("ShopType") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "GoodsId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPurchases"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerStoryState", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("StoryType") + .HasColumnType("integer") + .HasColumnName("StoryType"); + + b.Property("StoryId") + .HasColumnType("integer") + .HasColumnName("StoryId"); + + b.Property("State") + .HasColumnType("integer") + .HasColumnName("State"); + + b.HasKey("DeviceAccountId", "StoryType", "StoryId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerStoryState"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerSummonHistory", b => + { + b.Property("KeyId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("KeyId")); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityAttackPlusCount") + .HasColumnType("integer") + .HasColumnName("AtkPlusCount"); + + b.Property("EntityHpPlusCount") + .HasColumnType("integer") + .HasColumnName("HpPlusCount"); + + b.Property("EntityId") + .HasColumnType("integer") + .HasColumnName("EntityId"); + + b.Property("EntityLevel") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.Property("EntityLimitBreakCount") + .HasColumnType("smallint") + .HasColumnName("LimitBreakCount"); + + b.Property("EntityQuantity") + .HasColumnType("integer") + .HasColumnName("Quantity"); + + b.Property("EntityRarity") + .HasColumnType("smallint") + .HasColumnName("Rarity"); + + b.Property("EntityType") + .HasColumnType("integer") + .HasColumnName("EntityType"); + + b.Property("ExecDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("SummonDate"); + + b.Property("GetDewPointQuantity") + .HasColumnType("integer") + .HasColumnName("DewPointGet"); + + b.Property("PaymentType") + .HasColumnType("integer") + .HasColumnName("PaymentType"); + + b.Property("SummonExecType") + .HasColumnType("smallint") + .HasColumnName("SummonExecType"); + + b.Property("SummonId") + .HasColumnType("integer") + .HasColumnName("BannerId"); + + b.Property("SummonPoint") + .HasColumnType("integer") + .HasColumnName("SummonPointGet"); + + b.Property("SummonPrizeRank") + .HasColumnType("integer") + .HasColumnName("SummonPrizeRank"); + + b.HasKey("KeyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerSummonHistory"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerTrade", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("TradeId"); + + b.Property("Count") + .HasColumnType("integer") + .HasColumnName("TradeCount"); + + b.Property("LastTradeTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastTrade"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("TradeType"); + + b.HasKey("DeviceAccountId", "Id"); + + b.HasIndex("DeviceAccountId"); + + b.HasIndex("DeviceAccountId", "Type"); + + b.ToTable("PlayerTrades"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerUserData", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("ActiveMemoryEventId") + .HasColumnType("integer"); + + b.Property("BuildTimePoint") + .HasColumnType("integer"); + + b.Property("Coin") + .HasColumnType("bigint"); + + b.Property("CreateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Crystal") + .HasColumnType("integer"); + + b.Property("DewPoint") + .HasColumnType("integer"); + + b.Property("EmblemId") + .HasColumnType("integer"); + + b.Property("Exp") + .HasColumnType("integer"); + + b.Property("FortOpenTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastLoginTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSaveImportTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastStaminaMultiUpdateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastStaminaSingleUpdateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("MainPartyNo") + .HasColumnType("integer"); + + b.Property("ManaPoint") + .HasColumnType("integer"); + + b.Property("MaxDragonQuantity") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("QuestSkipPoint") + .HasColumnType("integer"); + + b.Property("StaminaMulti") + .HasColumnType("integer"); + + b.Property("StaminaMultiSurplusSecond") + .HasColumnType("integer"); + + b.Property("StaminaSingle") + .HasColumnType("integer"); + + b.Property("StaminaSingleSurplusSecond") + .HasColumnType("integer"); + + b.Property("TutorialFlag") + .HasColumnType("integer"); + + b.Property("TutorialStatus") + .HasColumnType("integer"); + + b.Property("ViewerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ViewerId")); + + b.HasKey("DeviceAccountId"); + + b.HasIndex("DeviceAccountId") + .IsUnique(); + + b.ToTable("PlayerUserData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuest", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("QuestId") + .HasColumnType("integer"); + + b.Property("BestClearTime") + .HasColumnType("real"); + + b.Property("DailyPlayCount") + .HasColumnType("integer"); + + b.Property("IsAppear") + .HasColumnType("boolean"); + + b.Property("IsMissionClear1") + .HasColumnType("boolean"); + + b.Property("IsMissionClear2") + .HasColumnType("boolean"); + + b.Property("IsMissionClear3") + .HasColumnType("boolean"); + + b.Property("LastDailyResetTime") + .HasColumnType("integer"); + + b.Property("LastWeeklyResetTime") + .HasColumnType("integer"); + + b.Property("PlayCount") + .HasColumnType("integer"); + + b.Property("State") + .HasColumnType("smallint"); + + b.Property("WeeklyPlayCount") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "QuestId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerQuests"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuestClearPartyUnit", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("QuestId") + .HasColumnType("integer"); + + b.Property("IsMulti") + .HasColumnType("boolean"); + + b.Property("UnitNo") + .HasColumnType("integer"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill1CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill2CharaId") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("EquipDragonKeyId") + .HasColumnType("bigint"); + + b.Property("EquipTalismanKeyId") + .HasColumnType("bigint"); + + b.Property("EquipWeaponBodyId") + .HasColumnType("integer"); + + b.Property("EquipWeaponSkinId") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "QuestId", "IsMulti", "UnitNo"); + + b.ToTable("QuestClearPartyUnits"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbSetUnit", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("UnitSetNo") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("EquipDragonKeyId") + .HasColumnType("bigint"); + + b.Property("EquipTalismanKeyId") + .HasColumnType("bigint"); + + b.Property("EquipWeaponBodyId") + .HasColumnType("integer"); + + b.Property("UnitSetName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("DeviceAccountId", "CharaId", "UnitSetNo"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerSetUnit"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbTalisman", b => + { + b.Property("TalismanKeyId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("TalismanKeyId")); + + b.Property("AdditionalAttack") + .HasColumnType("integer"); + + b.Property("AdditionalHp") + .HasColumnType("integer"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsLock") + .HasColumnType("boolean"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("TalismanAbilityId1") + .HasColumnType("integer"); + + b.Property("TalismanAbilityId2") + .HasColumnType("integer"); + + b.Property("TalismanAbilityId3") + .HasColumnType("integer"); + + b.Property("TalismanId") + .HasColumnType("integer"); + + b.HasKey("TalismanKeyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerTalismans"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponBody", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("WeaponBodyId") + .HasColumnType("integer"); + + b.Property("AdditionalCrestSlotType1Count") + .HasColumnType("integer"); + + b.Property("AdditionalCrestSlotType2Count") + .HasColumnType("integer"); + + b.Property("AdditionalCrestSlotType3Count") + .HasColumnType("integer"); + + b.Property("BuildupCount") + .HasColumnType("integer"); + + b.Property("EquipableCount") + .HasColumnType("integer"); + + b.Property("FortPassiveCharaWeaponBuildupCount") + .HasColumnType("integer"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("LimitBreakCount") + .HasColumnType("integer"); + + b.Property("LimitOverCount") + .HasColumnType("integer"); + + b.Property("UnlockWeaponPassiveAbilityNoString") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("DeviceAccountId", "WeaponBodyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerWeapons"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponPassiveAbility", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("WeaponPassiveAbilityId") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "WeaponPassiveAbilityId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPassiveAbilities"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponSkin", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("WeaponSkinId") + .HasColumnType("integer"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.HasKey("DeviceAccountId", "WeaponSkinId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerWeaponSkins"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrest", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("AbilityCrestList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrestSet", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("AbilityCrestSetList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbEquippedStamp", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("EquippedStampList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortBuild", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("BuildList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortDetail", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithOne("FortDetail") + .HasForeignKey("DragaliaAPI.Database.Entities.DbFortDetail", "DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbParty", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("PartyList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPartyUnit", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbParty", "Party") + .WithMany("Units") + .HasForeignKey("DeviceAccountId", "PartyNo") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerBannerData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("UserSummonList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCharaData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("CharaList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCurrency", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("Currencies") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("DragonList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonGift", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("DragonGiftList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonReliability", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("DragonReliabilityList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMaterial", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("MaterialList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMission", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresent", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("Presents") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresentHistory", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("PresentHistory") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopInfo", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithOne("ShopInfo") + .HasForeignKey("DragaliaAPI.Database.Entities.DbPlayerShopInfo", "DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopPurchase", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerStoryState", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("StoryStates") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerSummonHistory", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("SummonHistory") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerTrade", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerUserData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithOne("UserData") + .HasForeignKey("DragaliaAPI.Database.Entities.DbPlayerUserData", "DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuest", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("QuestList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuestClearPartyUnit", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbSetUnit", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("UnitSets") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbTalisman", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("TalismanList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponBody", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("WeaponBodyList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponPassiveAbility", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("WeaponPassiveAbilityList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponSkin", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("WeaponSkinList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbParty", b => + { + b.Navigation("Units"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayer", b => + { + b.Navigation("AbilityCrestList"); + + b.Navigation("AbilityCrestSetList"); + + b.Navigation("BuildList"); + + b.Navigation("CharaList"); + + b.Navigation("Currencies"); + + b.Navigation("DragonGiftList"); + + b.Navigation("DragonList"); + + b.Navigation("DragonReliabilityList"); + + b.Navigation("EquippedStampList"); + + b.Navigation("FortDetail"); + + b.Navigation("MaterialList"); + + b.Navigation("PartyList"); + + b.Navigation("PresentHistory"); + + b.Navigation("Presents"); + + b.Navigation("QuestList"); + + b.Navigation("ShopInfo"); + + b.Navigation("StoryStates"); + + b.Navigation("SummonHistory"); + + b.Navigation("TalismanList"); + + b.Navigation("UnitSets"); + + b.Navigation("UserData"); + + b.Navigation("UserSummonList"); + + b.Navigation("WeaponBodyList"); + + b.Navigation("WeaponPassiveAbilityList"); + + b.Navigation("WeaponSkinList"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.cs b/DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.cs new file mode 100644 index 000000000..2713f1cb0 --- /dev/null +++ b/DragaliaAPI.Database/Migrations/20230715142823_quest-clear-parties.cs @@ -0,0 +1,56 @@ +// +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DragaliaAPI.Database.Migrations +{ + /// + public partial class questclearparties : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.CreateTable( + name: "QuestClearPartyUnits", + columns: table => new + { + DeviceAccountId = table.Column(type: "text", nullable: false), + QuestId = table.Column(type: "integer", nullable: false), + IsMulti = table.Column(type: "boolean", nullable: false), + UnitNo = table.Column(type: "integer", nullable: false), + CharaId = table.Column(type: "integer", nullable: false), + EquipDragonKeyId = table.Column(type: "bigint", nullable: false), + EquipWeaponBodyId = table.Column(type: "integer", nullable: false), + EquipCrestSlotType1CrestId1 = table.Column(type: "integer", nullable: false), + EquipCrestSlotType1CrestId2 = table.Column(type: "integer", nullable: false), + EquipCrestSlotType1CrestId3 = table.Column(type: "integer", nullable: false), + EquipCrestSlotType2CrestId1 = table.Column(type: "integer", nullable: false), + EquipCrestSlotType2CrestId2 = table.Column(type: "integer", nullable: false), + EquipCrestSlotType3CrestId1 = table.Column(type: "integer", nullable: false), + EquipCrestSlotType3CrestId2 = table.Column(type: "integer", nullable: false), + EquipTalismanKeyId = table.Column(type: "bigint", nullable: false), + EquipWeaponSkinId = table.Column(type: "integer", nullable: false), + EditSkill1CharaId = table.Column(type: "integer", nullable: false), + EditSkill2CharaId = table.Column(type: "integer", nullable: false) + }, + constraints: table => + { + table.PrimaryKey("PK_QuestClearPartyUnits", x => new { x.DeviceAccountId, x.QuestId, x.IsMulti, x.UnitNo }); + table.ForeignKey( + name: "FK_QuestClearPartyUnits_Players_DeviceAccountId", + column: x => x.DeviceAccountId, + principalTable: "Players", + principalColumn: "AccountId", + onDelete: ReferentialAction.Cascade); + }); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropTable( + name: "QuestClearPartyUnits"); + } + } +} diff --git a/DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.Designer.cs b/DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.Designer.cs new file mode 100644 index 000000000..cc2d15ff1 --- /dev/null +++ b/DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.Designer.cs @@ -0,0 +1,1778 @@ +// +using System; +using DragaliaAPI.Database; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace DragaliaAPI.Database.Migrations +{ + [DbContext(typeof(ApiContext))] + [Migration("20230715171619_quest-clear-parties-2")] + partial class questclearparties2 + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "7.0.5") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrest", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("AbilityCrestId") + .HasColumnType("integer"); + + b.Property("AttackPlusCount") + .HasColumnType("integer"); + + b.Property("BuildupCount") + .HasColumnType("integer"); + + b.Property("EquipableCount") + .HasColumnType("integer"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("HpPlusCount") + .HasColumnType("integer"); + + b.Property("IsFavorite") + .HasColumnType("boolean"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("LimitBreakCount") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "AbilityCrestId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerAbilityCrests"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrestSet", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("AbilityCrestSetNo") + .HasColumnType("integer"); + + b.Property("AbilityCrestSetName") + .IsRequired() + .HasColumnType("text"); + + b.Property("CrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("CrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("CrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("CrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("CrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("CrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("CrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("TalismanKeyId") + .HasColumnType("numeric(20,0)"); + + b.HasKey("DeviceAccountId", "AbilityCrestSetNo"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerAbilityCrestSets"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbDeviceAccount", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("HashedPassword") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("Id"); + + b.ToTable("DeviceAccounts"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbEquippedStamp", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("Slot") + .HasColumnType("integer"); + + b.Property("StampId") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "Slot"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("EquippedStamps"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortBuild", b => + { + b.Property("BuildId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("BuildId")); + + b.Property("BuildEndDate") + .HasColumnType("timestamp with time zone"); + + b.Property("BuildStartDate") + .HasColumnType("timestamp with time zone"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("LastIncomeDate") + .HasColumnType("timestamp with time zone"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("PlantId") + .HasColumnType("integer"); + + b.Property("PositionX") + .HasColumnType("integer"); + + b.Property("PositionZ") + .HasColumnType("integer"); + + b.HasKey("BuildId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerFortBuilds"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortDetail", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CarpenterNum") + .HasColumnType("integer") + .HasColumnName("CarpenterNum"); + + b.HasKey("DeviceAccountId"); + + b.HasIndex("DeviceAccountId") + .IsUnique(); + + b.ToTable("PlayerFortDetail"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbParty", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("PartyNo") + .HasColumnType("integer"); + + b.Property("PartyName") + .IsRequired() + .HasMaxLength(20) + .HasColumnType("character varying(20)"); + + b.HasKey("DeviceAccountId", "PartyNo"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PartyData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPartyUnit", b => + { + b.Property("Id") + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EditSkill1CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill2CharaId") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("EquipDragonKeyId") + .HasColumnType("bigint"); + + b.Property("EquipTalismanKeyId") + .HasColumnType("bigint"); + + b.Property("EquipWeaponBodyId") + .HasColumnType("integer"); + + b.Property("EquipWeaponSkinId") + .HasColumnType("integer"); + + b.Property("PartyNo") + .HasColumnType("integer"); + + b.Property("UnitNo") + .HasColumnType("integer"); + + b.HasKey("Id"); + + b.HasIndex("DeviceAccountId"); + + b.HasIndex("DeviceAccountId", "PartyNo"); + + b.ToTable("PlayerPartyUnits"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayer", b => + { + b.Property("AccountId") + .HasColumnType("text"); + + b.Property("SavefileVersion") + .HasColumnType("integer"); + + b.HasKey("AccountId"); + + b.ToTable("Players"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerBannerData", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("SummonBannerId") + .HasColumnType("integer") + .HasColumnName("SummonBannerId"); + + b.Property("ConsecutionSummonPoints") + .HasColumnType("integer") + .HasColumnName("CsSummonPoints"); + + b.Property("ConsecutionSummonPointsMaxDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("CsSummonPointsMaxDate"); + + b.Property("ConsecutionSummonPointsMinDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("CsSummonPointsMinDate"); + + b.Property("DailyLimitedSummonCount") + .HasColumnType("integer") + .HasColumnName("DailyLimitedSummons"); + + b.Property("IsBeginnerFreeSummonAvailable") + .HasColumnType("integer") + .HasColumnName("BeginnerSummonAvailable"); + + b.Property("IsConsecutionFreeSummonAvailable") + .HasColumnType("integer") + .HasColumnName("CsSummonAvailable"); + + b.Property("IsFreeSummonAvailable") + .HasColumnType("integer") + .HasColumnName("FreeSummonAvailable"); + + b.Property("PityRate") + .HasColumnType("smallint") + .HasColumnName("Pity"); + + b.Property("SummonCount") + .HasColumnType("integer") + .HasColumnName("SummonCount"); + + b.Property("SummonPoints") + .HasColumnType("integer") + .HasColumnName("SummonPoints"); + + b.HasKey("DeviceAccountId", "SummonBannerId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerBannerData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCharaData", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer") + .HasColumnName("CharaId"); + + b.Property("Ability1Level") + .HasColumnType("smallint") + .HasColumnName("Abil1Lvl"); + + b.Property("Ability2Level") + .HasColumnType("smallint") + .HasColumnName("Abil2Lvl"); + + b.Property("Ability3Level") + .HasColumnType("smallint") + .HasColumnName("Abil3Lvl"); + + b.Property("AttackBase") + .HasColumnType("integer") + .HasColumnName("AtkBase"); + + b.Property("AttackNode") + .HasColumnType("integer") + .HasColumnName("AtkNode"); + + b.Property("AttackPlusCount") + .HasColumnType("smallint") + .HasColumnName("AtkPlusCount"); + + b.Property("BurstAttackLevel") + .HasColumnType("smallint") + .HasColumnName("BurstAtkLvl"); + + b.Property("ComboBuildupCount") + .HasColumnType("integer") + .HasColumnName("ComboBuildupCount"); + + b.Property("ExAbility2Level") + .HasColumnType("smallint") + .HasColumnName("ExAbility2Lvl"); + + b.Property("ExAbilityLevel") + .HasColumnType("smallint") + .HasColumnName("ExAbility1Lvl"); + + b.Property("Exp") + .HasColumnType("integer") + .HasColumnName("Exp"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("GetTime"); + + b.Property("HpBase") + .HasColumnType("integer") + .HasColumnName("HpBase"); + + b.Property("HpNode") + .HasColumnType("integer") + .HasColumnName("HpNode"); + + b.Property("HpPlusCount") + .HasColumnType("smallint") + .HasColumnName("HpPlusCount"); + + b.Property("IsNew") + .HasColumnType("boolean") + .HasColumnName("IsNew"); + + b.Property("IsTemporary") + .HasColumnType("boolean") + .HasColumnName("IsTemp"); + + b.Property("IsUnlockEditSkill") + .HasColumnType("boolean") + .HasColumnName("IsUnlockEditSkill"); + + b.Property("Level") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.Property("ListViewFlag") + .HasColumnType("boolean") + .HasColumnName("ListViewFlag"); + + b.Property("ManaNodeUnlockCount") + .HasColumnType("integer") + .HasColumnName("ManaNodeUnlockCount"); + + b.Property("Rarity") + .HasColumnType("smallint") + .HasColumnName("Rarity"); + + b.Property("Skill1Level") + .HasColumnType("smallint") + .HasColumnName("Skill1Lvl"); + + b.Property("Skill2Level") + .HasColumnType("smallint") + .HasColumnName("Skill2Lvl"); + + b.HasKey("DeviceAccountId", "CharaId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerCharaData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCurrency", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CurrencyType") + .HasColumnType("integer") + .HasColumnName("CurrencyType"); + + b.Property("Quantity") + .HasColumnType("bigint") + .HasColumnName("Quantity"); + + b.HasKey("DeviceAccountId", "CurrencyType"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerCurrency"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonData", b => + { + b.Property("DragonKeyId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("DragonKeyId"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("DragonKeyId")); + + b.Property("Ability1Level") + .HasColumnType("smallint") + .HasColumnName("Abil1Level"); + + b.Property("Ability2Level") + .HasColumnType("smallint") + .HasColumnName("Abil2Level"); + + b.Property("AttackPlusCount") + .HasColumnType("smallint") + .HasColumnName("AttackPlusCount"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("DragonId") + .HasColumnType("integer") + .HasColumnName("DragonId"); + + b.Property("Exp") + .HasColumnType("integer") + .HasColumnName("Exp"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("GetTime"); + + b.Property("HpPlusCount") + .HasColumnType("smallint") + .HasColumnName("HpPlusCount"); + + b.Property("IsLock") + .HasColumnType("boolean") + .HasColumnName("IsLocked"); + + b.Property("IsNew") + .HasColumnType("boolean") + .HasColumnName("IsNew"); + + b.Property("Level") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.Property("LimitBreakCount") + .HasColumnType("smallint") + .HasColumnName("LimitBreakCount"); + + b.Property("Skill1Level") + .HasColumnType("smallint") + .HasColumnName("Skill1Level"); + + b.HasKey("DragonKeyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerDragonData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonGift", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text") + .HasColumnName("DeviceAccountId"); + + b.Property("DragonGiftId") + .HasColumnType("integer") + .HasColumnName("DragonGiftId"); + + b.Property("Quantity") + .HasColumnType("integer") + .HasColumnName("Quantity"); + + b.HasKey("DeviceAccountId", "DragonGiftId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerDragonGift"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonReliability", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("DragonId") + .HasColumnType("integer") + .HasColumnName("DragonId"); + + b.Property("Exp") + .HasColumnType("integer") + .HasColumnName("TotalExp"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastContactTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastContactTime"); + + b.Property("Level") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.HasKey("DeviceAccountId", "DragonId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerDragonReliability"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMaterial", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("MaterialId") + .HasColumnType("integer") + .HasColumnName("MaterialId"); + + b.Property("Quantity") + .HasColumnType("integer") + .HasColumnName("Quantity"); + + b.HasKey("DeviceAccountId", "MaterialId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerMaterial"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMission", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("MissionId"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("Type"); + + b.Property("End") + .HasColumnType("timestamp with time zone") + .HasColumnName("EndDate"); + + b.Property("GroupId") + .HasColumnType("integer") + .HasColumnName("GroupId"); + + b.Property("Pickup") + .HasColumnType("boolean") + .HasColumnName("Pickup"); + + b.Property("Progress") + .HasColumnType("integer") + .HasColumnName("Progress"); + + b.Property("Start") + .HasColumnType("timestamp with time zone") + .HasColumnName("StartDate"); + + b.Property("State") + .HasColumnType("integer") + .HasColumnName("State"); + + b.HasKey("DeviceAccountId", "Id", "Type"); + + b.ToTable("PlayerMissions"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresent", b => + { + b.Property("PresentId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint") + .HasColumnName("PresentId"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("PresentId")); + + b.Property("CreateTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreateTime"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityId") + .HasColumnType("integer") + .HasColumnName("EntityId"); + + b.Property("EntityLevel") + .HasColumnType("integer") + .HasColumnName("EntityLevel"); + + b.Property("EntityLimitBreakCount") + .HasColumnType("integer") + .HasColumnName("EntityLimitBreakCount"); + + b.Property("EntityQuantity") + .HasColumnType("integer") + .HasColumnName("EntityQuantity"); + + b.Property("EntityStatusPlusCount") + .HasColumnType("integer") + .HasColumnName("EntityStatusPlusCount"); + + b.Property("EntityType") + .HasColumnType("integer") + .HasColumnName("EntityType"); + + b.Property("MasterId") + .HasColumnType("bigint") + .HasColumnName("MasterId"); + + b.Property("MessageId") + .HasColumnType("integer") + .HasColumnName("MessageId"); + + b.Property("MessageParamValue1") + .HasColumnType("integer") + .HasColumnName("MessageParamValue1"); + + b.Property("MessageParamValue2") + .HasColumnType("integer") + .HasColumnName("MessageParamValue2"); + + b.Property("MessageParamValue3") + .HasColumnType("integer") + .HasColumnName("MessageParamValue3"); + + b.Property("MessageParamValue4") + .HasColumnType("integer") + .HasColumnName("MessageParamValue4"); + + b.Property("ReceiveLimitTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("ReceiveLimitTime"); + + b.Property("State") + .HasColumnType("bigint") + .HasColumnName("State"); + + b.HasKey("PresentId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPresent"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresentHistory", b => + { + b.Property("Id") + .HasColumnType("bigint"); + + b.Property("CreateTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("CreateTime"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityId") + .HasColumnType("integer") + .HasColumnName("EntityId"); + + b.Property("EntityLevel") + .HasColumnType("integer") + .HasColumnName("EntityLevel"); + + b.Property("EntityLimitBreakCount") + .HasColumnType("integer") + .HasColumnName("EntityLimitBreakCount"); + + b.Property("EntityQuantity") + .HasColumnType("integer") + .HasColumnName("EntityQuantity"); + + b.Property("EntityStatusPlusCount") + .HasColumnType("integer") + .HasColumnName("EntityStatusPlusCount"); + + b.Property("EntityType") + .HasColumnType("integer") + .HasColumnName("EntityType"); + + b.Property("MessageId") + .HasColumnType("integer") + .HasColumnName("MessageId"); + + b.Property("MessageParamValue1") + .HasColumnType("integer") + .HasColumnName("MessageParamValue1"); + + b.Property("MessageParamValue2") + .HasColumnType("integer") + .HasColumnName("MessageParamValue2"); + + b.Property("MessageParamValue3") + .HasColumnType("integer") + .HasColumnName("MessageParamValue3"); + + b.Property("MessageParamValue4") + .HasColumnType("integer") + .HasColumnName("MessageParamValue4"); + + b.HasKey("Id"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPresentHistory"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopInfo", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("DailySummonCount") + .HasColumnType("integer"); + + b.Property("LastSummonTime") + .HasColumnType("timestamp with time zone"); + + b.HasKey("DeviceAccountId"); + + b.ToTable("PlayerShopInfos"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopPurchase", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("GoodsId") + .HasColumnType("integer"); + + b.Property("BuyCount") + .HasColumnType("integer"); + + b.Property("EffectEndTime") + .HasColumnType("timestamp with time zone"); + + b.Property("EffectStartTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastBuyTime") + .HasColumnType("timestamp with time zone"); + + b.Property("ShopType") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "GoodsId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPurchases"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerStoryState", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("StoryType") + .HasColumnType("integer") + .HasColumnName("StoryType"); + + b.Property("StoryId") + .HasColumnType("integer") + .HasColumnName("StoryId"); + + b.Property("State") + .HasColumnType("integer") + .HasColumnName("State"); + + b.HasKey("DeviceAccountId", "StoryType", "StoryId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerStoryState"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerSummonHistory", b => + { + b.Property("KeyId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("KeyId")); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("EntityAttackPlusCount") + .HasColumnType("integer") + .HasColumnName("AtkPlusCount"); + + b.Property("EntityHpPlusCount") + .HasColumnType("integer") + .HasColumnName("HpPlusCount"); + + b.Property("EntityId") + .HasColumnType("integer") + .HasColumnName("EntityId"); + + b.Property("EntityLevel") + .HasColumnType("smallint") + .HasColumnName("Level"); + + b.Property("EntityLimitBreakCount") + .HasColumnType("smallint") + .HasColumnName("LimitBreakCount"); + + b.Property("EntityQuantity") + .HasColumnType("integer") + .HasColumnName("Quantity"); + + b.Property("EntityRarity") + .HasColumnType("smallint") + .HasColumnName("Rarity"); + + b.Property("EntityType") + .HasColumnType("integer") + .HasColumnName("EntityType"); + + b.Property("ExecDate") + .HasColumnType("timestamp with time zone") + .HasColumnName("SummonDate"); + + b.Property("GetDewPointQuantity") + .HasColumnType("integer") + .HasColumnName("DewPointGet"); + + b.Property("PaymentType") + .HasColumnType("integer") + .HasColumnName("PaymentType"); + + b.Property("SummonExecType") + .HasColumnType("smallint") + .HasColumnName("SummonExecType"); + + b.Property("SummonId") + .HasColumnType("integer") + .HasColumnName("BannerId"); + + b.Property("SummonPoint") + .HasColumnType("integer") + .HasColumnName("SummonPointGet"); + + b.Property("SummonPrizeRank") + .HasColumnType("integer") + .HasColumnName("SummonPrizeRank"); + + b.HasKey("KeyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerSummonHistory"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerTrade", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("Id") + .HasColumnType("integer") + .HasColumnName("TradeId"); + + b.Property("Count") + .HasColumnType("integer") + .HasColumnName("TradeCount"); + + b.Property("LastTradeTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("LastTrade"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("TradeType"); + + b.HasKey("DeviceAccountId", "Id"); + + b.HasIndex("DeviceAccountId"); + + b.HasIndex("DeviceAccountId", "Type"); + + b.ToTable("PlayerTrades"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerUserData", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("ActiveMemoryEventId") + .HasColumnType("integer"); + + b.Property("BuildTimePoint") + .HasColumnType("integer"); + + b.Property("Coin") + .HasColumnType("bigint"); + + b.Property("CreateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Crystal") + .HasColumnType("integer"); + + b.Property("DewPoint") + .HasColumnType("integer"); + + b.Property("EmblemId") + .HasColumnType("integer"); + + b.Property("Exp") + .HasColumnType("integer"); + + b.Property("FortOpenTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastLoginTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastSaveImportTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastStaminaMultiUpdateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("LastStaminaSingleUpdateTime") + .HasColumnType("timestamp with time zone"); + + b.Property("Level") + .HasColumnType("integer"); + + b.Property("MainPartyNo") + .HasColumnType("integer"); + + b.Property("ManaPoint") + .HasColumnType("integer"); + + b.Property("MaxDragonQuantity") + .HasColumnType("integer"); + + b.Property("Name") + .IsRequired() + .HasMaxLength(10) + .HasColumnType("character varying(10)"); + + b.Property("QuestSkipPoint") + .HasColumnType("integer"); + + b.Property("StaminaMulti") + .HasColumnType("integer"); + + b.Property("StaminaMultiSurplusSecond") + .HasColumnType("integer"); + + b.Property("StaminaSingle") + .HasColumnType("integer"); + + b.Property("StaminaSingleSurplusSecond") + .HasColumnType("integer"); + + b.Property("TutorialFlag") + .HasColumnType("integer"); + + b.Property("TutorialStatus") + .HasColumnType("integer"); + + b.Property("ViewerId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("ViewerId")); + + b.HasKey("DeviceAccountId"); + + b.HasIndex("DeviceAccountId") + .IsUnique(); + + b.ToTable("PlayerUserData"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuest", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("QuestId") + .HasColumnType("integer"); + + b.Property("BestClearTime") + .HasColumnType("real"); + + b.Property("DailyPlayCount") + .HasColumnType("integer"); + + b.Property("IsAppear") + .HasColumnType("boolean"); + + b.Property("IsMissionClear1") + .HasColumnType("boolean"); + + b.Property("IsMissionClear2") + .HasColumnType("boolean"); + + b.Property("IsMissionClear3") + .HasColumnType("boolean"); + + b.Property("LastDailyResetTime") + .HasColumnType("integer"); + + b.Property("LastWeeklyResetTime") + .HasColumnType("integer"); + + b.Property("PlayCount") + .HasColumnType("integer"); + + b.Property("State") + .HasColumnType("smallint"); + + b.Property("WeeklyPlayCount") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "QuestId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerQuests"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuestClearPartyUnit", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("QuestId") + .HasColumnType("integer"); + + b.Property("IsMulti") + .HasColumnType("boolean"); + + b.Property("UnitNo") + .HasColumnType("integer"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill1CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill2CharaId") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("EquipDragonKeyId") + .HasColumnType("bigint"); + + b.Property("EquipTalismanKeyId") + .HasColumnType("bigint"); + + b.Property("EquipWeaponBodyId") + .HasColumnType("integer"); + + b.Property("EquipWeaponSkinId") + .HasColumnType("integer"); + + b.Property("EquippedDragonEntityId") + .HasColumnType("integer"); + + b.Property("EquippedTalismanEntityId") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "QuestId", "IsMulti", "UnitNo"); + + b.ToTable("QuestClearPartyUnits"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbSetUnit", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("UnitSetNo") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("EquipDragonKeyId") + .HasColumnType("bigint"); + + b.Property("EquipTalismanKeyId") + .HasColumnType("bigint"); + + b.Property("EquipWeaponBodyId") + .HasColumnType("integer"); + + b.Property("UnitSetName") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("DeviceAccountId", "CharaId", "UnitSetNo"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerSetUnit"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbTalisman", b => + { + b.Property("TalismanKeyId") + .ValueGeneratedOnAdd() + .HasColumnType("bigint"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("TalismanKeyId")); + + b.Property("AdditionalAttack") + .HasColumnType("integer"); + + b.Property("AdditionalHp") + .HasColumnType("integer"); + + b.Property("DeviceAccountId") + .IsRequired() + .HasColumnType("text"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsLock") + .HasColumnType("boolean"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("TalismanAbilityId1") + .HasColumnType("integer"); + + b.Property("TalismanAbilityId2") + .HasColumnType("integer"); + + b.Property("TalismanAbilityId3") + .HasColumnType("integer"); + + b.Property("TalismanId") + .HasColumnType("integer"); + + b.HasKey("TalismanKeyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerTalismans"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponBody", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("WeaponBodyId") + .HasColumnType("integer"); + + b.Property("AdditionalCrestSlotType1Count") + .HasColumnType("integer"); + + b.Property("AdditionalCrestSlotType2Count") + .HasColumnType("integer"); + + b.Property("AdditionalCrestSlotType3Count") + .HasColumnType("integer"); + + b.Property("BuildupCount") + .HasColumnType("integer"); + + b.Property("EquipableCount") + .HasColumnType("integer"); + + b.Property("FortPassiveCharaWeaponBuildupCount") + .HasColumnType("integer"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.Property("LimitBreakCount") + .HasColumnType("integer"); + + b.Property("LimitOverCount") + .HasColumnType("integer"); + + b.Property("UnlockWeaponPassiveAbilityNoString") + .IsRequired() + .HasColumnType("text"); + + b.HasKey("DeviceAccountId", "WeaponBodyId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerWeapons"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponPassiveAbility", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("WeaponPassiveAbilityId") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "WeaponPassiveAbilityId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerPassiveAbilities"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponSkin", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("WeaponSkinId") + .HasColumnType("integer"); + + b.Property("GetTime") + .HasColumnType("timestamp with time zone"); + + b.Property("IsNew") + .HasColumnType("boolean"); + + b.HasKey("DeviceAccountId", "WeaponSkinId"); + + b.HasIndex("DeviceAccountId"); + + b.ToTable("PlayerWeaponSkins"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrest", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("AbilityCrestList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbAbilityCrestSet", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("AbilityCrestSetList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbEquippedStamp", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("EquippedStampList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortBuild", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("BuildList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbFortDetail", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithOne("FortDetail") + .HasForeignKey("DragaliaAPI.Database.Entities.DbFortDetail", "DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbParty", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("PartyList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPartyUnit", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbParty", "Party") + .WithMany("Units") + .HasForeignKey("DeviceAccountId", "PartyNo") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Party"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerBannerData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("UserSummonList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCharaData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("CharaList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerCurrency", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("Currencies") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("DragonList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonGift", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("DragonGiftList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerDragonReliability", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("DragonReliabilityList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMaterial", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("MaterialList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerMission", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresent", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("Presents") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresentHistory", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("PresentHistory") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopInfo", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithOne("ShopInfo") + .HasForeignKey("DragaliaAPI.Database.Entities.DbPlayerShopInfo", "DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopPurchase", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerStoryState", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("StoryStates") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerSummonHistory", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("SummonHistory") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerTrade", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerUserData", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithOne("UserData") + .HasForeignKey("DragaliaAPI.Database.Entities.DbPlayerUserData", "DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuest", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("QuestList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuestClearPartyUnit", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbSetUnit", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("UnitSets") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbTalisman", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("TalismanList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponBody", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("WeaponBodyList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponPassiveAbility", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("WeaponPassiveAbilityList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbWeaponSkin", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany("WeaponSkinList") + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbParty", b => + { + b.Navigation("Units"); + }); + + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayer", b => + { + b.Navigation("AbilityCrestList"); + + b.Navigation("AbilityCrestSetList"); + + b.Navigation("BuildList"); + + b.Navigation("CharaList"); + + b.Navigation("Currencies"); + + b.Navigation("DragonGiftList"); + + b.Navigation("DragonList"); + + b.Navigation("DragonReliabilityList"); + + b.Navigation("EquippedStampList"); + + b.Navigation("FortDetail"); + + b.Navigation("MaterialList"); + + b.Navigation("PartyList"); + + b.Navigation("PresentHistory"); + + b.Navigation("Presents"); + + b.Navigation("QuestList"); + + b.Navigation("ShopInfo"); + + b.Navigation("StoryStates"); + + b.Navigation("SummonHistory"); + + b.Navigation("TalismanList"); + + b.Navigation("UnitSets"); + + b.Navigation("UserData"); + + b.Navigation("UserSummonList"); + + b.Navigation("WeaponBodyList"); + + b.Navigation("WeaponPassiveAbilityList"); + + b.Navigation("WeaponSkinList"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.cs b/DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.cs new file mode 100644 index 000000000..a8b77cc10 --- /dev/null +++ b/DragaliaAPI.Database/Migrations/20230715171619_quest-clear-parties-2.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace DragaliaAPI.Database.Migrations +{ + /// + public partial class questclearparties2 : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "EquippedDragonEntityId", + table: "QuestClearPartyUnits", + type: "integer", + nullable: false, + defaultValue: 0); + + migrationBuilder.AddColumn( + name: "EquippedTalismanEntityId", + table: "QuestClearPartyUnits", + type: "integer", + nullable: false, + defaultValue: 0); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "EquippedDragonEntityId", + table: "QuestClearPartyUnits"); + + migrationBuilder.DropColumn( + name: "EquippedTalismanEntityId", + table: "QuestClearPartyUnits"); + } + } +} diff --git a/DragaliaAPI.Database/Migrations/ApiContextModelSnapshot.cs b/DragaliaAPI.Database/Migrations/ApiContextModelSnapshot.cs index f5b7c8b31..74f69c51d 100644 --- a/DragaliaAPI.Database/Migrations/ApiContextModelSnapshot.cs +++ b/DragaliaAPI.Database/Migrations/ApiContextModelSnapshot.cs @@ -1132,6 +1132,73 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.ToTable("PlayerQuests"); }); + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuestClearPartyUnit", b => + { + b.Property("DeviceAccountId") + .HasColumnType("text"); + + b.Property("QuestId") + .HasColumnType("integer"); + + b.Property("IsMulti") + .HasColumnType("boolean"); + + b.Property("UnitNo") + .HasColumnType("integer"); + + b.Property("CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill1CharaId") + .HasColumnType("integer"); + + b.Property("EditSkill2CharaId") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType1CrestId3") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType2CrestId2") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId1") + .HasColumnType("integer"); + + b.Property("EquipCrestSlotType3CrestId2") + .HasColumnType("integer"); + + b.Property("EquipDragonKeyId") + .HasColumnType("bigint"); + + b.Property("EquipTalismanKeyId") + .HasColumnType("bigint"); + + b.Property("EquipWeaponBodyId") + .HasColumnType("integer"); + + b.Property("EquipWeaponSkinId") + .HasColumnType("integer"); + + b.Property("EquippedDragonEntityId") + .HasColumnType("integer"); + + b.Property("EquippedTalismanEntityId") + .HasColumnType("integer"); + + b.HasKey("DeviceAccountId", "QuestId", "IsMulti", "UnitNo"); + + b.ToTable("QuestClearPartyUnits"); + }); + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbSetUnit", b => { b.Property("DeviceAccountId") @@ -1483,7 +1550,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresent", b => { b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") - .WithMany() + .WithMany("Presents") .HasForeignKey("DeviceAccountId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -1494,7 +1561,7 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerPresentHistory", b => { b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") - .WithMany() + .WithMany("PresentHistory") .HasForeignKey("DeviceAccountId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -1505,8 +1572,8 @@ protected override void BuildModel(ModelBuilder modelBuilder) modelBuilder.Entity("DragaliaAPI.Database.Entities.DbPlayerShopInfo", b => { b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") - .WithMany() - .HasForeignKey("DeviceAccountId") + .WithOne("ShopInfo") + .HasForeignKey("DragaliaAPI.Database.Entities.DbPlayerShopInfo", "DeviceAccountId") .OnDelete(DeleteBehavior.Cascade) .IsRequired(); @@ -1579,6 +1646,17 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("Owner"); }); + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbQuestClearPartyUnit", b => + { + b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") + .WithMany() + .HasForeignKey("DeviceAccountId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Owner"); + }); + modelBuilder.Entity("DragaliaAPI.Database.Entities.DbSetUnit", b => { b.HasOne("DragaliaAPI.Database.Entities.DbPlayer", "Owner") @@ -1665,8 +1743,14 @@ protected override void BuildModel(ModelBuilder modelBuilder) b.Navigation("PartyList"); + b.Navigation("PresentHistory"); + + b.Navigation("Presents"); + b.Navigation("QuestList"); + b.Navigation("ShopInfo"); + b.Navigation("StoryStates"); b.Navigation("SummonHistory"); diff --git a/DragaliaAPI.Integration.Test/CustomWebApplicationFactory.cs b/DragaliaAPI.Integration.Test/CustomWebApplicationFactory.cs index ee9a47fe5..f3b9b2bbf 100644 --- a/DragaliaAPI.Integration.Test/CustomWebApplicationFactory.cs +++ b/DragaliaAPI.Integration.Test/CustomWebApplicationFactory.cs @@ -45,7 +45,8 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) Host = TestContainers.PostgresHost, Port = TestContainers.PostgresPort, Username = TestContainers.PostgresUser, - Password = TestContainers.PostgresPassword + Password = TestContainers.PostgresPassword, + IncludeErrorDetail = true, }; services.RemoveAll>(); diff --git a/DragaliaAPI.Integration.Test/Dragalia/QuestClearPartyTest.cs b/DragaliaAPI.Integration.Test/Dragalia/QuestClearPartyTest.cs new file mode 100644 index 000000000..1107d711e --- /dev/null +++ b/DragaliaAPI.Integration.Test/Dragalia/QuestClearPartyTest.cs @@ -0,0 +1,474 @@ +using System.Collections.Immutable; +using DragaliaAPI.Database.Entities; +using DragaliaAPI.Features.Quest; +using DragaliaAPI.Models; +using DragaliaAPI.Models.Generated; +using DragaliaAPI.Shared.Definitions.Enums; +using Microsoft.EntityFrameworkCore; + +namespace DragaliaAPI.Integration.Test.Dragalia; + +/// +/// Tests +/// +public class QuestClearPartyTest : TestFixture, IDisposable +{ + public QuestClearPartyTest( + CustomWebApplicationFactory factory, + ITestOutputHelper outputHelper + ) + : base(factory, outputHelper) + { + CommonAssertionOptions.ApplyIgnoreOwnerOptions(); + } + + [Fact] + public async Task GetQuestClearParty_ReturnsSetClearParty() + { + this.ImportSave(); + + await this.AddRangeToDatabase(TestData.SoloDbEntities); + + DragaliaResponse response = + await this.Client.PostMsgpack( + "/quest/get_quest_clear_party", + new QuestGetQuestClearPartyRequest() { quest_id = 1 } + ); + + response.data.quest_clear_party_setting_list + .Should() + .BeEquivalentTo(TestData.SoloPartySettingLists); + response.data.lost_unit_list.Should().BeEmpty(); + } + + [Fact] + public async Task GetQuestClearPartyMulti_ReturnsSetClearParty() + { + this.ImportSave(); + + await this.AddRangeToDatabase(TestData.MultiDbEntities); + + DragaliaResponse response = + await this.Client.PostMsgpack( + "/quest/get_quest_clear_party_multi", + new QuestGetQuestClearPartyRequest() { quest_id = 2 } + ); + + response.data.quest_multi_clear_party_setting_list + .Should() + .BeEquivalentTo(TestData.MultiPartySettingLists); + response.data.lost_unit_list.Should().BeEmpty(); + } + + [Fact] + public async Task GetQuestClearParty_DoesNotRetrieveMultiData() + { + int questId = 5; + + await this.Client.PostMsgpack( + "/quest/set_quest_clear_party_multi", + new QuestSetQuestClearPartyRequest() + { + quest_id = questId, + request_party_setting_list = TestData.MultiPartySettingLists + } + ); + + DragaliaResponse response = + await this.Client.PostMsgpack( + "/quest/get_quest_clear_party", + new QuestGetQuestClearPartyRequest() { quest_id = questId } + ); + + response.data.quest_clear_party_setting_list.Should().BeEmpty(); + } + + [Fact] + public async Task GetQuestClearParty_HandlesMissingEntities() + { + this.ImportSave(); + + int questId = TestData.MissingItemDbEntities[0].QuestId; + + await this.AddRangeToDatabase(TestData.MissingItemDbEntities); + + DragaliaResponse response = + await this.Client.PostMsgpack( + "/quest/get_quest_clear_party", + new QuestGetQuestClearPartyRequest() { quest_id = questId } + ); + + response.data.lost_unit_list + .Should() + .BeEquivalentTo( + new List() + { + new() + { + unit_no = 1, + entity_type = EntityTypes.Chara, + entity_id = (int)Charas.Basileus, + }, + new() + { + unit_no = 2, + entity_type = EntityTypes.Wyrmprint, + entity_id = (int)AbilityCrests.InanUnendingWorld, + }, + new() + { + unit_no = 3, + entity_type = EntityTypes.WeaponBody, + entity_id = (int)WeaponBodies.PrimalAqua, + }, + new() + { + unit_no = 4, + entity_type = EntityTypes.WeaponSkin, + entity_id = 1000 + }, + new() + { + unit_no = 5, + entity_type = EntityTypes.Dragon, + entity_id = (int)Dragons.Ifrit + }, + new() + { + unit_no = 6, + entity_type = EntityTypes.Talisman, + entity_id = (int)Talismans.Raemond + } + } + ); + + List partyList = response.data.quest_clear_party_setting_list.ToList(); + + partyList[0].chara_id.Should().Be(0); + partyList[1].equip_crest_slot_type_1_crest_id_1.Should().Be(0); + partyList[2].equip_weapon_body_id.Should().Be(0); + partyList[3].equip_weapon_skin_id.Should().Be(0); + partyList[4].equip_dragon_key_id.Should().Be(0); + partyList[5].equip_talisman_key_id.Should().Be(0); + partyList[6].edit_skill_1_chara_id.Should().Be(0); + partyList[6].edit_skill_2_chara_id.Should().Be(0); + } + + [Fact] + public async Task SetQuestClearParty_AddsToDatabase() + { + this.ImportSave(); + + DragaliaResponse response = + await this.Client.PostMsgpack( + "/quest/set_quest_clear_party", + new QuestSetQuestClearPartyRequest() + { + quest_id = 3, + request_party_setting_list = TestData.SoloPartySettingLists + } + ); + + response.data.result.Should().Be(1); + + List storedList = await this.ApiContext.QuestClearPartyUnits + .Where( + x => x.QuestId == 3 && x.DeviceAccountId == DeviceAccountId && x.IsMulti == false + ) + .ToListAsync(); + + storedList + .Should() + .BeEquivalentTo(TestData.SoloDbEntities, opts => opts.Excluding(x => x.QuestId)); + storedList.Should().AllSatisfy(x => x.QuestId.Should().Be(3)); + } + + [Fact] + public async Task SetQuestClearPartyMulti_AddsToDatabase() + { + this.ImportSave(); + + DragaliaResponse response = + await this.Client.PostMsgpack( + "/quest/set_quest_clear_party_multi", + new QuestSetQuestClearPartyRequest() + { + quest_id = 4, + request_party_setting_list = TestData.MultiPartySettingLists + } + ); + + response.data.result.Should().Be(1); + + List storedList = await this.ApiContext.QuestClearPartyUnits + .Where(x => x.QuestId == 4 && x.DeviceAccountId == DeviceAccountId && x.IsMulti == true) + .ToListAsync(); + + storedList + .Should() + .BeEquivalentTo(TestData.MultiDbEntities, opts => opts.Excluding(x => x.QuestId)); + storedList.Should().AllSatisfy(x => x.QuestId.Should().Be(4)); + } + + private static class TestData + { + public static readonly List SoloDbEntities = + new() + { + new() + { + DeviceAccountId = DeviceAccountId, + IsMulti = false, + QuestId = 1, + UnitNo = 1, + CharaId = Charas.GalaNedrick, + EquipDragonKeyId = 1, + EquipWeaponBodyId = WeaponBodies.YitianJian, + EquipCrestSlotType1CrestId1 = AbilityCrests.PrimalCrisis, + EquipCrestSlotType1CrestId2 = AbilityCrests.WelcometotheOpera, + EquipCrestSlotType1CrestId3 = AbilityCrests.FelyneHospitality, + EquipCrestSlotType2CrestId1 = AbilityCrests.ThePlaguebringer, + EquipCrestSlotType2CrestId2 = AbilityCrests.TotheExtreme, + EquipCrestSlotType3CrestId1 = AbilityCrests.CrownofLightSerpentsBoon, + EquipCrestSlotType3CrestId2 = AbilityCrests.TutelarysDestinyWolfsBoon, + EquipTalismanKeyId = 1, + EquipWeaponSkinId = 30129901, + EditSkill1CharaId = Charas.Empty, + EditSkill2CharaId = Charas.GalaMym, + EquippedDragonEntityId = Dragons.Cerberus, + EquippedTalismanEntityId = Talismans.GalaMym, + }, + new() + { + DeviceAccountId = DeviceAccountId, + IsMulti = false, + QuestId = 1, + UnitNo = 2, + CharaId = Charas.Patia, + EquipDragonKeyId = 2, + EquipWeaponBodyId = WeaponBodies.QinglongYanyuedao, + EquipCrestSlotType1CrestId1 = AbilityCrests.AHalloweenSpectacular, + EquipCrestSlotType1CrestId2 = AbilityCrests.CastawaysJournal, + EquipCrestSlotType1CrestId3 = AbilityCrests.TheChocolatiers, + EquipCrestSlotType2CrestId1 = AbilityCrests.RoguesBanquet, + EquipCrestSlotType2CrestId2 = AbilityCrests.LuckoftheDraw, + EquipCrestSlotType3CrestId1 = AbilityCrests.RavenousFireCrownsBoon, + EquipCrestSlotType3CrestId2 = AbilityCrests.PromisedPietyStaffsBoon, + EquipTalismanKeyId = 2, + EquipWeaponSkinId = 30129901, + EditSkill1CharaId = Charas.TemplarHope, + EditSkill2CharaId = Charas.Zena, + EquippedDragonEntityId = Dragons.Pazuzu, + EquippedTalismanEntityId = Talismans.GalaMym + } + }; + + public static readonly List SoloPartySettingLists = + new() + { + new() + { + unit_no = 1, + chara_id = Charas.GalaNedrick, + equip_dragon_key_id = 1, + equip_weapon_body_id = WeaponBodies.YitianJian, + equip_crest_slot_type_1_crest_id_1 = AbilityCrests.PrimalCrisis, + equip_crest_slot_type_1_crest_id_2 = AbilityCrests.WelcometotheOpera, + equip_crest_slot_type_1_crest_id_3 = AbilityCrests.FelyneHospitality, + equip_crest_slot_type_2_crest_id_1 = AbilityCrests.ThePlaguebringer, + equip_crest_slot_type_2_crest_id_2 = AbilityCrests.TotheExtreme, + equip_crest_slot_type_3_crest_id_1 = AbilityCrests.CrownofLightSerpentsBoon, + equip_crest_slot_type_3_crest_id_2 = AbilityCrests.TutelarysDestinyWolfsBoon, + equip_talisman_key_id = 1, + equip_weapon_skin_id = 30129901, + edit_skill_1_chara_id = Charas.Empty, + edit_skill_2_chara_id = Charas.GalaMym, + }, + new() + { + unit_no = 2, + chara_id = Charas.Patia, + equip_dragon_key_id = 2, + equip_weapon_body_id = WeaponBodies.QinglongYanyuedao, + equip_crest_slot_type_1_crest_id_1 = AbilityCrests.AHalloweenSpectacular, + equip_crest_slot_type_1_crest_id_2 = AbilityCrests.CastawaysJournal, + equip_crest_slot_type_1_crest_id_3 = AbilityCrests.TheChocolatiers, + equip_crest_slot_type_2_crest_id_1 = AbilityCrests.RoguesBanquet, + equip_crest_slot_type_2_crest_id_2 = AbilityCrests.LuckoftheDraw, + equip_crest_slot_type_3_crest_id_1 = AbilityCrests.RavenousFireCrownsBoon, + equip_crest_slot_type_3_crest_id_2 = AbilityCrests.PromisedPietyStaffsBoon, + equip_talisman_key_id = 2, + equip_weapon_skin_id = 30129901, + edit_skill_1_chara_id = Charas.TemplarHope, + edit_skill_2_chara_id = Charas.Zena, + } + }; + + public static readonly List MultiDbEntities = + new() + { + new() + { + DeviceAccountId = DeviceAccountId, + IsMulti = true, + QuestId = 2, + UnitNo = 1, + CharaId = Charas.GalaNotte, + EquipDragonKeyId = 3, + EquipWeaponBodyId = WeaponBodies.WindrulersFang, + EquipCrestSlotType1CrestId1 = AbilityCrests.BondsBetweenWorlds, + EquipCrestSlotType1CrestId2 = AbilityCrests.AManUnchanging, + EquipCrestSlotType1CrestId3 = AbilityCrests.GoingUndercover, + EquipCrestSlotType2CrestId1 = AbilityCrests.APassionforProduce, + EquipCrestSlotType2CrestId2 = AbilityCrests.DragonsNest, + EquipCrestSlotType3CrestId1 = AbilityCrests.TutelarysDestinyWolfsBoon, + EquipCrestSlotType3CrestId2 = AbilityCrests.CrownofLightSerpentsBoon, + EquipTalismanKeyId = 3, + EquipWeaponSkinId = 0, + EditSkill1CharaId = Charas.Empty, + EditSkill2CharaId = Charas.GalaMym, + EquippedDragonEntityId = Dragons.Leviathan, + EquippedTalismanEntityId = Talismans.GalaMym + }, + new() + { + DeviceAccountId = DeviceAccountId, + IsMulti = true, + QuestId = 2, + UnitNo = 2, + CharaId = Charas.GalaLeif, + EquipDragonKeyId = 4, + EquipWeaponBodyId = WeaponBodies.PrimalTempest, + EquipCrestSlotType1CrestId1 = AbilityCrests.AdventureinthePast, + EquipCrestSlotType1CrestId2 = AbilityCrests.PrimalCrisis, + EquipCrestSlotType1CrestId3 = AbilityCrests.GoingUndercover, + EquipCrestSlotType2CrestId1 = AbilityCrests.DragonsNest, + EquipCrestSlotType2CrestId2 = AbilityCrests.ThePlaguebringer, + EquipCrestSlotType3CrestId1 = AbilityCrests.AKnightsDreamAxesBoon, + EquipCrestSlotType3CrestId2 = AbilityCrests.CrownofLightSerpentsBoon, + EquipTalismanKeyId = 4, + EquipWeaponSkinId = 0, + EditSkill1CharaId = Charas.ShaWujing, + EditSkill2CharaId = Charas.Ranzal, + EquippedDragonEntityId = Dragons.Phoenix, + EquippedTalismanEntityId = Talismans.GalaMym + } + }; + + public static readonly List MultiPartySettingLists = + new() + { + new() + { + unit_no = 1, + chara_id = Charas.GalaNotte, + equip_dragon_key_id = 3, + equip_weapon_body_id = WeaponBodies.WindrulersFang, + equip_crest_slot_type_1_crest_id_1 = AbilityCrests.BondsBetweenWorlds, + equip_crest_slot_type_1_crest_id_2 = AbilityCrests.AManUnchanging, + equip_crest_slot_type_1_crest_id_3 = AbilityCrests.GoingUndercover, + equip_crest_slot_type_2_crest_id_1 = AbilityCrests.APassionforProduce, + equip_crest_slot_type_2_crest_id_2 = AbilityCrests.DragonsNest, + equip_crest_slot_type_3_crest_id_1 = AbilityCrests.TutelarysDestinyWolfsBoon, + equip_crest_slot_type_3_crest_id_2 = AbilityCrests.CrownofLightSerpentsBoon, + equip_talisman_key_id = 3, + equip_weapon_skin_id = 0, + edit_skill_1_chara_id = Charas.Empty, + edit_skill_2_chara_id = Charas.GalaMym, + }, + new() + { + unit_no = 2, + chara_id = Charas.GalaLeif, + equip_dragon_key_id = 4, + equip_weapon_body_id = WeaponBodies.PrimalTempest, + equip_crest_slot_type_1_crest_id_1 = AbilityCrests.AdventureinthePast, + equip_crest_slot_type_1_crest_id_2 = AbilityCrests.PrimalCrisis, + equip_crest_slot_type_1_crest_id_3 = AbilityCrests.GoingUndercover, + equip_crest_slot_type_2_crest_id_1 = AbilityCrests.DragonsNest, + equip_crest_slot_type_2_crest_id_2 = AbilityCrests.ThePlaguebringer, + equip_crest_slot_type_3_crest_id_1 = AbilityCrests.AKnightsDreamAxesBoon, + equip_crest_slot_type_3_crest_id_2 = AbilityCrests.CrownofLightSerpentsBoon, + equip_talisman_key_id = 4, + equip_weapon_skin_id = 0, + edit_skill_1_chara_id = Charas.ShaWujing, + edit_skill_2_chara_id = Charas.Ranzal, + } + }; + + public static List MissingItemDbEntities = + new() + { + new() + { + DeviceAccountId = DeviceAccountId, + UnitNo = 1, + QuestId = 6, + IsMulti = false, + CharaId = Charas.Basileus, + }, + new() + { + DeviceAccountId = DeviceAccountId, + UnitNo = 2, + QuestId = 6, + IsMulti = false, + CharaId = Charas.Cecile, + EquipCrestSlotType1CrestId1 = AbilityCrests.InanUnendingWorld + }, + new() + { + DeviceAccountId = DeviceAccountId, + UnitNo = 3, + QuestId = 6, + IsMulti = false, + CharaId = Charas.Durant, + EquipWeaponBodyId = WeaponBodies.PrimalAqua, + }, + new() + { + DeviceAccountId = DeviceAccountId, + UnitNo = 4, + QuestId = 6, + IsMulti = false, + CharaId = Charas.Elias, + EquipWeaponSkinId = 1000, + }, + new() + { + DeviceAccountId = DeviceAccountId, + UnitNo = 5, + QuestId = 6, + IsMulti = false, + EquipDragonKeyId = 2000, + CharaId = Charas.Emma, + EquippedDragonEntityId = Dragons.Ifrit, + }, + new() + { + DeviceAccountId = DeviceAccountId, + UnitNo = 6, + QuestId = 6, + IsMulti = false, + EquipTalismanKeyId = 3000, + CharaId = Charas.Raemond, + EquippedTalismanEntityId = Talismans.Raemond + }, + new() + { + DeviceAccountId = DeviceAccountId, + UnitNo = 7, + QuestId = 6, + IsMulti = false, + CharaId = Charas.Edward, + EditSkill1CharaId = Charas.Yue, + EditSkill2CharaId = Charas.Marty + } + }; + } + + public void Dispose() + { + this.ApiContext.QuestClearPartyUnits.ExecuteDelete(); + } +} diff --git a/DragaliaAPI.Integration.Test/Dragalia/QuestTest.cs b/DragaliaAPI.Integration.Test/Dragalia/QuestReadStoryTest.cs similarity index 87% rename from DragaliaAPI.Integration.Test/Dragalia/QuestTest.cs rename to DragaliaAPI.Integration.Test/Dragalia/QuestReadStoryTest.cs index 087f46779..0a59923fe 100644 --- a/DragaliaAPI.Integration.Test/Dragalia/QuestTest.cs +++ b/DragaliaAPI.Integration.Test/Dragalia/QuestReadStoryTest.cs @@ -1,16 +1,16 @@ -using DragaliaAPI.Database.Entities; +using DragaliaAPI.Database.Entities; using DragaliaAPI.Models.Generated; using DragaliaAPI.Shared.Definitions.Enums; using Microsoft.EntityFrameworkCore; namespace DragaliaAPI.Integration.Test.Dragalia; -/// -/// Tests -/// -public class QuestTest : TestFixture +public class QuestReadStoryTest : TestFixture { - public QuestTest(CustomWebApplicationFactory factory, ITestOutputHelper outputHelper) + public QuestReadStoryTest( + CustomWebApplicationFactory factory, + ITestOutputHelper outputHelper + ) : base(factory, outputHelper) { } [Fact] diff --git a/DragaliaAPI.Integration.Test/TestFixture.cs b/DragaliaAPI.Integration.Test/TestFixture.cs index 1fa269362..b01686697 100644 --- a/DragaliaAPI.Integration.Test/TestFixture.cs +++ b/DragaliaAPI.Integration.Test/TestFixture.cs @@ -8,6 +8,7 @@ using DragaliaAPI.Shared.Json; using DragaliaAPI.Shared.PlayerDetails; using Microsoft.AspNetCore.Hosting; +using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -109,6 +110,7 @@ protected void ImportSave() { if ( this.ApiContext.PlayerUserData + .AsNoTracking() .First(x => x.DeviceAccountId == DeviceAccountId) .LastSaveImportTime > DateTimeOffset.UnixEpoch ) diff --git a/DragaliaAPI.Shared/Definitions/Enums/AbilityCrests.cs b/DragaliaAPI.Shared/Definitions/Enums/AbilityCrests.cs index c5fa913d2..07d7e398a 100644 --- a/DragaliaAPI.Shared/Definitions/Enums/AbilityCrests.cs +++ b/DragaliaAPI.Shared/Definitions/Enums/AbilityCrests.cs @@ -5,6 +5,7 @@ /// public enum AbilityCrests { + Empty = 0, RingofExaltation = 40020001, SeafoodSoup = 40020002, DragonArcanum = 40020003, diff --git a/DragaliaAPI.Shared/Definitions/Enums/Dragons.cs b/DragaliaAPI.Shared/Definitions/Enums/Dragons.cs index 7abdc59d8..10d548c1d 100644 --- a/DragaliaAPI.Shared/Definitions/Enums/Dragons.cs +++ b/DragaliaAPI.Shared/Definitions/Enums/Dragons.cs @@ -2,6 +2,7 @@ public enum Dragons { + Empty = 0, AC011Garland = 20050312, Agni = 20050101, Andromeda = 20050516, diff --git a/DragaliaAPI.Shared/Definitions/Enums/Talismans.cs b/DragaliaAPI.Shared/Definitions/Enums/Talismans.cs index c5cf4deca..44d0825cf 100644 --- a/DragaliaAPI.Shared/Definitions/Enums/Talismans.cs +++ b/DragaliaAPI.Shared/Definitions/Enums/Talismans.cs @@ -9,6 +9,7 @@ namespace DragaliaAPI.Shared.Definitions.Enums; public enum Talismans { + Empty = 0, Addis = 50240302, Aeleen = 50540301, Akasha = 50850301, diff --git a/DragaliaAPI.Test/Controllers/QuestControllerTest.cs b/DragaliaAPI.Test/Controllers/QuestControllerTest.cs index 38bec4918..d4491f07c 100644 --- a/DragaliaAPI.Test/Controllers/QuestControllerTest.cs +++ b/DragaliaAPI.Test/Controllers/QuestControllerTest.cs @@ -1,5 +1,7 @@ using DragaliaAPI.Controllers.Dragalia; +using DragaliaAPI.Features.ClearParty; using DragaliaAPI.Features.Dungeon; +using DragaliaAPI.Features.Quest; using DragaliaAPI.Models.Generated; using DragaliaAPI.Services; using DragaliaAPI.Shared.Definitions.Enums; @@ -13,6 +15,7 @@ public class QuestControllerTest private readonly Mock mockHelperService; private readonly Mock mockQuestRewardService; private readonly Mock mockUpdateDataService; + private readonly Mock mockClearPartyService; private readonly Mock> mockLogger; private readonly QuestController questController; @@ -23,6 +26,7 @@ public QuestControllerTest() this.mockHelperService = new(MockBehavior.Strict); this.mockQuestRewardService = new(MockBehavior.Strict); this.mockUpdateDataService = new(MockBehavior.Strict); + this.mockClearPartyService = new(MockBehavior.Strict); this.mockLogger = new(MockBehavior.Loose); this.questController = new( @@ -30,6 +34,7 @@ public QuestControllerTest() this.mockHelperService.Object, this.mockQuestRewardService.Object, this.mockUpdateDataService.Object, + this.mockClearPartyService.Object, this.mockLogger.Object ); } diff --git a/DragaliaAPI/AutoMapper/Profiles/UnitMapProfile.cs b/DragaliaAPI/AutoMapper/Profiles/UnitMapProfile.cs index 47b533b77..2d49eeeef 100644 --- a/DragaliaAPI/AutoMapper/Profiles/UnitMapProfile.cs +++ b/DragaliaAPI/AutoMapper/Profiles/UnitMapProfile.cs @@ -50,6 +50,13 @@ public UnitMapProfile() .ForMember(nameof(PartySettingList.equip_amulet_2_key_id), opts => opts.Ignore()) .ForMember(nameof(PartySettingList.equip_skin_weapon_id), opts => opts.Ignore()); + this.CreateMap() + // Deprecated + .ForMember(nameof(PartySettingList.equip_weapon_key_id), opts => opts.Ignore()) + .ForMember(nameof(PartySettingList.equip_amulet_key_id), opts => opts.Ignore()) + .ForMember(nameof(PartySettingList.equip_amulet_2_key_id), opts => opts.Ignore()) + .ForMember(nameof(PartySettingList.equip_skin_weapon_id), opts => opts.Ignore()); + this.CreateMap(); this.CreateMap() diff --git a/DragaliaAPI/AutoMapper/Profiles/UnitReverseMapProfile.cs b/DragaliaAPI/AutoMapper/Profiles/UnitReverseMapProfile.cs index b8a9af352..db0bad9ec 100644 --- a/DragaliaAPI/AutoMapper/Profiles/UnitReverseMapProfile.cs +++ b/DragaliaAPI/AutoMapper/Profiles/UnitReverseMapProfile.cs @@ -45,6 +45,13 @@ public UnitReverseMapProfile() .ForMember(x => x.PartyNo, opts => opts.Ignore()) .ForMember(x => x.Party, opts => opts.Ignore()); + this.CreateMap() + // Manually mapped properties + .ForMember(x => x.QuestId, opts => opts.Ignore()) + .ForMember(x => x.IsMulti, opts => opts.Ignore()) + .ForMember(x => x.EquippedDragonEntityId, opts => opts.Ignore()) + .ForMember(x => x.EquippedTalismanEntityId, opts => opts.Ignore()); + this.CreateMap(); this.CreateMap(); diff --git a/DragaliaAPI/Controllers/Dragalia/MatchingController.cs b/DragaliaAPI/Controllers/Dragalia/MatchingController.cs index a0db62f20..70184d539 100644 --- a/DragaliaAPI/Controllers/Dragalia/MatchingController.cs +++ b/DragaliaAPI/Controllers/Dragalia/MatchingController.cs @@ -1,6 +1,5 @@ using DragaliaAPI.Models.Generated; using DragaliaAPI.Services.Photon; -using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; namespace DragaliaAPI.Controllers.Dragalia; @@ -54,7 +53,7 @@ MatchingGetRoomListByQuestIdRequest request } [HttpPost("check_penalty_user")] - public async Task CheckPenaltyUser(MatchingCheckPenaltyUserRequest request) + public DragaliaResult CheckPenaltyUser(MatchingCheckPenaltyUserRequest request) { return this.Ok(new MatchingCheckPenaltyUserData() { result = 1 }); } diff --git a/DragaliaAPI/Controllers/Dragalia/QuestController.cs b/DragaliaAPI/Controllers/Dragalia/QuestController.cs deleted file mode 100644 index 3b10dd456..000000000 --- a/DragaliaAPI/Controllers/Dragalia/QuestController.cs +++ /dev/null @@ -1,205 +0,0 @@ -using DragaliaAPI.Database.Repositories; -using DragaliaAPI.Features.Dungeon; -using DragaliaAPI.Models; -using DragaliaAPI.Models.Generated; -using DragaliaAPI.Services; -using DragaliaAPI.Services.Game; -using DragaliaAPI.Shared.Definitions.Enums; -using Microsoft.AspNetCore.Mvc; - -namespace DragaliaAPI.Controllers.Dragalia; - -[Route("quest")] -[ApiController] -public class QuestController : DragaliaControllerBase -{ - private readonly IStoryService storyService; - private readonly IHelperService helperService; - private readonly IQuestDropService questRewardService; - private readonly IUpdateDataService updateDataService; - private readonly ILogger logger; - - public QuestController( - IStoryService storyService, - IHelperService helperService, - IQuestDropService questRewardService, - IUpdateDataService updateDataService, - ILogger logger - ) - { - this.storyService = storyService; - this.helperService = helperService; - this.questRewardService = questRewardService; - this.updateDataService = updateDataService; - this.logger = logger; - } - - [HttpPost] - [Route("read_story")] - public async Task ReadStory(QuestReadStoryRequest request) - { - IEnumerable rewardList = await this.storyService.ReadStory( - StoryTypes.Quest, - request.quest_story_id - ); - - EntityResult entityResult = StoryService.GetEntityResult(rewardList); - IEnumerable questRewardList = rewardList.Select( - StoryService.ToQuestStoryReward - ); - - UpdateDataList updateDataList = await this.updateDataService.SaveChangesAsync(); - - return this.Ok( - new QuestReadStoryData() - { - quest_story_reward_list = questRewardList, - entity_result = entityResult, - update_data_list = updateDataList - } - ); - } - - [HttpPost("get_support_user_list")] - public async Task GetUserSupportList() - { - // TODO: this is actually going to be a pretty complicated system - QuestGetSupportUserListData response = await this.helperService.GetHelpers(); - return Ok(response); - } - - [HttpPost("get_quest_clear_party")] - public DragaliaResult GetQuestClearParty() - { - // TODO: Retrieve from database - return Ok( - new QuestGetQuestClearPartyData() - { - quest_clear_party_setting_list = StubData.ClearParty, - lost_unit_list = new List() - } - ); - } - - [HttpPost("get_quest_clear_party_multi")] - public DragaliaResult GetQuestClearPartyMulti() - { - return Ok( - new QuestGetQuestClearPartyMultiData() - { - quest_multi_clear_party_setting_list = StubData.ClearParty, - lost_unit_list = new List() - } - ); - } - - [HttpPost("set_quest_clear_party")] - public DragaliaResult SetQuestClearParty() - { - // TODO: Store in database - return Ok(new QuestSetQuestClearPartyData() { result = 1 }); - } - - [HttpPost("drop_list")] - public DragaliaResult DropList(QuestDropListRequest request) - { - IEnumerable drops = this.questRewardService.GetDrops(request.quest_id); - - return Ok( - new QuestDropListData() - { - quest_drop_info = new() - { - drop_info_list = drops.Select( - x => - new AtgenDuplicateEntityList() - { - entity_id = (int)x, - entity_type = EntityTypes.Material - } - ) - } - } - ); - } - - private static class StubData - { - public static List ClearParty = - new() - { - new() - { - unit_no = 1, - chara_id = Charas.ThePrince, - equip_dragon_key_id = 0, - equip_weapon_body_id = 0, - equip_weapon_skin_id = 0, - equip_crest_slot_type_1_crest_id_1 = 0, - equip_crest_slot_type_1_crest_id_2 = 0, - equip_crest_slot_type_1_crest_id_3 = 0, - equip_crest_slot_type_2_crest_id_1 = 0, - equip_crest_slot_type_2_crest_id_2 = 0, - equip_crest_slot_type_3_crest_id_1 = 0, - equip_crest_slot_type_3_crest_id_2 = 0, - equip_talisman_key_id = 0, - edit_skill_1_chara_id = 0, - edit_skill_2_chara_id = 0, - }, - new() - { - unit_no = 2, - chara_id = Charas.Empty, - equip_dragon_key_id = 0, - equip_weapon_body_id = 0, - equip_weapon_skin_id = 0, - equip_crest_slot_type_1_crest_id_1 = 0, - equip_crest_slot_type_1_crest_id_2 = 0, - equip_crest_slot_type_1_crest_id_3 = 0, - equip_crest_slot_type_2_crest_id_1 = 0, - equip_crest_slot_type_2_crest_id_2 = 0, - equip_crest_slot_type_3_crest_id_1 = 0, - equip_crest_slot_type_3_crest_id_2 = 0, - equip_talisman_key_id = 0, - edit_skill_1_chara_id = 0, - edit_skill_2_chara_id = 0, - }, - new() - { - unit_no = 3, - chara_id = Charas.Empty, - equip_dragon_key_id = 0, - equip_weapon_body_id = 0, - equip_weapon_skin_id = 0, - equip_crest_slot_type_1_crest_id_1 = 0, - equip_crest_slot_type_1_crest_id_2 = 0, - equip_crest_slot_type_1_crest_id_3 = 0, - equip_crest_slot_type_2_crest_id_1 = 0, - equip_crest_slot_type_2_crest_id_2 = 0, - equip_crest_slot_type_3_crest_id_1 = 0, - equip_crest_slot_type_3_crest_id_2 = 0, - equip_talisman_key_id = 0, - edit_skill_1_chara_id = 0, - edit_skill_2_chara_id = 0, - }, - new() - { - unit_no = 4, - chara_id = Charas.Empty, - equip_dragon_key_id = 0, - equip_weapon_body_id = 0, - equip_weapon_skin_id = 0, - equip_crest_slot_type_1_crest_id_1 = 0, - equip_crest_slot_type_1_crest_id_2 = 0, - equip_crest_slot_type_1_crest_id_3 = 0, - equip_crest_slot_type_2_crest_id_1 = 0, - equip_crest_slot_type_2_crest_id_2 = 0, - equip_crest_slot_type_3_crest_id_1 = 0, - equip_crest_slot_type_3_crest_id_2 = 0, - equip_talisman_key_id = 0, - edit_skill_1_chara_id = 0, - edit_skill_2_chara_id = 0, - }, - }; - } -} diff --git a/DragaliaAPI/Controllers/Dragalia/SummonController.cs b/DragaliaAPI/Controllers/Dragalia/SummonController.cs index 8e47b88dc..979d530c5 100644 --- a/DragaliaAPI/Controllers/Dragalia/SummonController.cs +++ b/DragaliaAPI/Controllers/Dragalia/SummonController.cs @@ -207,7 +207,7 @@ await summonRepository.SummonHistory.ToListAsync() [HttpPost] [Route("get_summon_list")] - public async Task GetSummonList() + public DragaliaResult GetSummonList() { return Ok(Data.SummonListData); } diff --git a/DragaliaAPI/Extensions/IEnumerableExtensions.cs b/DragaliaAPI/Extensions/IEnumerableExtensions.cs index bb418deff..4e62b985b 100644 --- a/DragaliaAPI/Extensions/IEnumerableExtensions.cs +++ b/DragaliaAPI/Extensions/IEnumerableExtensions.cs @@ -1,4 +1,5 @@ -using System.Diagnostics.CodeAnalysis; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; namespace DragaliaAPI.Extensions; @@ -9,7 +10,7 @@ public static bool TryGetElementAt( int index, [NotNullWhen(true)] out TElement? element ) - where TElement : class + where TElement : class? { element = enumerable.ElementAtOrDefault(index); diff --git a/DragaliaAPI/Features/ClearParty/ClearPartyRepository.cs b/DragaliaAPI/Features/ClearParty/ClearPartyRepository.cs new file mode 100644 index 000000000..0c2d571a4 --- /dev/null +++ b/DragaliaAPI/Features/ClearParty/ClearPartyRepository.cs @@ -0,0 +1,45 @@ +using System.Diagnostics; +using DragaliaAPI.Database; +using DragaliaAPI.Database.Entities; +using DragaliaAPI.Database.Entities.Scaffold; +using DragaliaAPI.Shared.PlayerDetails; +using Microsoft.EntityFrameworkCore; + +namespace DragaliaAPI.Features.ClearParty; + +public class ClearPartyRepository : IClearPartyRepository +{ + private readonly ApiContext apiContext; + private readonly IPlayerIdentityService playerIdentityService; + + public ClearPartyRepository(ApiContext apiContext, IPlayerIdentityService playerIdentityService) + { + this.apiContext = apiContext; + this.playerIdentityService = playerIdentityService; + } + + public IQueryable QuestClearPartyUnits => + this.apiContext.QuestClearPartyUnits.Where( + x => x.DeviceAccountId == this.playerIdentityService.AccountId + ); + + public IQueryable GetQuestClearParty(int questId, bool isMulti) + { + return this.QuestClearPartyUnits + .Where(x => x.QuestId == questId && x.IsMulti == isMulti) + .OrderBy(x => x.UnitNo); + } + + public void SetQuestClearParty( + int questId, + bool isMulti, + IEnumerable units + ) + { + Debug.Assert(units.All(u => u.QuestId == questId)); + Debug.Assert(units.All(u => u.IsMulti == isMulti)); + + this.apiContext.QuestClearPartyUnits.RemoveRange(this.GetQuestClearParty(questId, isMulti)); + this.apiContext.QuestClearPartyUnits.AddRange(units); + } +} diff --git a/DragaliaAPI/Features/ClearParty/ClearPartyService.cs b/DragaliaAPI/Features/ClearParty/ClearPartyService.cs new file mode 100644 index 000000000..8aaac6141 --- /dev/null +++ b/DragaliaAPI/Features/ClearParty/ClearPartyService.cs @@ -0,0 +1,352 @@ +using System.Collections; +using System.Collections.Immutable; +using AutoMapper; +using DragaliaAPI.Database.Entities; +using DragaliaAPI.Database.Entities.Scaffold; +using DragaliaAPI.Database.Repositories; +using DragaliaAPI.Features.Dungeon; +using DragaliaAPI.Models.Generated; +using DragaliaAPI.Shared.Definitions.Enums; +using DragaliaAPI.Shared.PlayerDetails; +using Microsoft.EntityFrameworkCore; + +namespace DragaliaAPI.Features.ClearParty; + +public class ClearPartyService : IClearPartyService +{ + private readonly IClearPartyRepository clearPartyRepository; + private readonly IUnitRepository unitRepository; + private readonly IDungeonRepository dungeonRepository; + private readonly IMapper mapper; + private readonly IPlayerIdentityService playerIdentityService; + private readonly ILogger logger; + + public ClearPartyService( + IClearPartyRepository clearPartyRepository, + IUnitRepository unitRepository, + IDungeonRepository dungeonRepository, + IMapper mapper, + IPlayerIdentityService playerIdentityService, + ILogger logger + ) + { + this.clearPartyRepository = clearPartyRepository; + this.unitRepository = unitRepository; + this.dungeonRepository = dungeonRepository; + this.mapper = mapper; + this.playerIdentityService = playerIdentityService; + this.logger = logger; + } + + public async Task<( + IEnumerable PartyList, + IEnumerable LostUnitList + )> GetQuestClearParty(int questId, bool isMulti) + { + IQueryable clearPartyQuery = + this.clearPartyRepository.GetQuestClearParty(questId, isMulti); + + IEnumerable clearPartyUnits = await clearPartyQuery.ToListAsync(); + + this.logger.LogDebug( + "Retrieved quest clear party for quest {questId} with {n} units", + questId, + clearPartyUnits.Count() + ); + + IEnumerable mappedPartyList = clearPartyUnits.Select( + this.mapper.Map + ); + + if (!clearPartyUnits.Any()) + { + // The game gracefully handles receiving an empty party by disabling the button + return new(mappedPartyList, Enumerable.Empty()); + } + + IEnumerable detailedPartyUnits = await this.dungeonRepository + .BuildDetailedPartyUnit(clearPartyQuery) + .ToListAsync(); + IEnumerable lostUnitList = ProcessLostUnitList( + clearPartyUnits, + detailedPartyUnits + ) + .ToList(); + + this.logger.LogDebug("Generated lostUnitList: {@lostUnitList}", lostUnitList); + + return new(mappedPartyList, lostUnitList); + } + + public async Task SetQuestClearParty( + int questId, + bool isMulti, + IEnumerable party + ) + { + Dictionary dragons = await this.unitRepository.Dragons + .Where(x => party.Select(y => y.equip_dragon_key_id).Contains((ulong)x.DragonKeyId)) + .ToDictionaryAsync(x => x.DragonKeyId, x => x.DragonId); + + Dictionary talismans = await this.unitRepository.Talismans + .Where(x => party.Select(y => y.equip_talisman_key_id).Contains((ulong)x.TalismanKeyId)) + .ToDictionaryAsync(x => x.TalismanKeyId, x => x.TalismanId); + + IEnumerable dbUnits = party.Select( + x => + this.mapper.Map( + x, + opts => + opts.AfterMap( + (src, dest) => + { + dest.DeviceAccountId = this.playerIdentityService.AccountId; + dest.QuestId = questId; + dest.IsMulti = isMulti; + + dest.EquippedDragonEntityId = dragons.GetValueOrDefault( + dest.EquipDragonKeyId, + Dragons.Empty + ); + dest.EquippedTalismanEntityId = talismans.GetValueOrDefault( + dest.EquipTalismanKeyId, + Talismans.Empty + ); + } + ) + ) + ); + + this.logger.LogDebug( + "Storing quest clear party for quest {questId} with {n} units", + questId, + dbUnits.Count() + ); + + this.clearPartyRepository.SetQuestClearParty(questId, isMulti, dbUnits); + } + + private static IEnumerable ProcessLostUnitList( + IEnumerable clearPartyUnits, + IEnumerable detailedPartyUnits + ) + { + IEnumerable<(DbQuestClearPartyUnit, DbDetailedPartyUnit?)> query = + from clearUnit in clearPartyUnits + join detailUnit in detailedPartyUnits + on clearUnit.UnitNo equals detailUnit.Position + into gj + from subDetailUnit in gj.DefaultIfEmpty() + select new ValueTuple( + clearUnit, + subDetailUnit ?? null + ); + + foreach ((DbQuestClearPartyUnit clearUnit, DbDetailedPartyUnit? detailUnit) in query) + { + if (clearUnit.CharaId == Charas.Empty) + continue; + + if (detailUnit?.CharaData is null) + { + // The game will just grey the button out if a character is missing. + // I don't blame them for not wanting to deal with it... + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Chara, + (int)clearUnit.CharaId + ); + clearUnit.Clear(); + continue; + } + + if (clearUnit.EquipDragonKeyId != 0 && detailUnit.DragonData is null) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Dragon, + (int)clearUnit.EquippedDragonEntityId + ); + clearUnit.EquipDragonKeyId = 0; + } + + if (clearUnit.EquipTalismanKeyId != 0 && detailUnit.TalismanData is null) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Talisman, + (int)clearUnit.EquippedTalismanEntityId + ); + clearUnit.EquipTalismanKeyId = 0; + } + + if ( + clearUnit.EquipWeaponBodyId != WeaponBodies.Empty + && detailUnit.WeaponBodyData is null + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.WeaponBody, + (int)clearUnit.EquipWeaponBodyId + ); + clearUnit.EquipWeaponBodyId = 0; + + // Also remove prints, since those are equipped on a weapon + clearUnit.EquipCrestSlotType1CrestId1 = 0; + clearUnit.EquipCrestSlotType1CrestId2 = 0; + clearUnit.EquipCrestSlotType1CrestId3 = 0; + + clearUnit.EquipCrestSlotType2CrestId1 = 0; + clearUnit.EquipCrestSlotType2CrestId2 = 0; + + clearUnit.EquipCrestSlotType3CrestId1 = 0; + clearUnit.EquipCrestSlotType3CrestId2 = 0; + + clearUnit.EquipTalismanKeyId = 0; + clearUnit.EquippedTalismanEntityId = 0; + } + + if (clearUnit.EquipWeaponSkinId != 0 && detailUnit.WeaponSkinData is null) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.WeaponSkin, + clearUnit.EquipWeaponSkinId + ); + clearUnit.EquipWeaponSkinId = 0; + } + + if ( + clearUnit.EditSkill1CharaId != Charas.Empty + && detailUnit.EditSkill1CharaData is null + ) + { + // There is no entity type for this + clearUnit.EditSkill1CharaId = 0; + } + + if ( + clearUnit.EditSkill2CharaId != Charas.Empty + && detailUnit.EditSkill2CharaData is null + ) + { + clearUnit.EditSkill2CharaId = 0; + } + + // Can this be done without copy and pasting? + // The challenge is that if you put the clearUnit crests into a list, + // it won't be possible to update the crest ID by reference. + + if ( + detailUnit.CrestSlotType1CrestList.IsMissingCrest( + clearUnit.EquipCrestSlotType1CrestId1 + ) + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Wyrmprint, + (int)clearUnit.EquipCrestSlotType1CrestId1 + ); + clearUnit.EquipCrestSlotType1CrestId1 = 0; + } + + if ( + detailUnit.CrestSlotType1CrestList.IsMissingCrest( + clearUnit.EquipCrestSlotType1CrestId2 + ) + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Wyrmprint, + (int)clearUnit.EquipCrestSlotType1CrestId2 + ); + clearUnit.EquipCrestSlotType1CrestId2 = 0; + } + + if ( + detailUnit.CrestSlotType1CrestList.IsMissingCrest( + clearUnit.EquipCrestSlotType1CrestId3 + ) + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Wyrmprint, + (int)clearUnit.EquipCrestSlotType1CrestId3 + ); + clearUnit.EquipCrestSlotType1CrestId3 = 0; + } + + if ( + detailUnit.CrestSlotType2CrestList.IsMissingCrest( + clearUnit.EquipCrestSlotType2CrestId1 + ) + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Wyrmprint, + (int)clearUnit.EquipCrestSlotType2CrestId1 + ); + clearUnit.EquipCrestSlotType2CrestId1 = 0; + } + + if ( + detailUnit.CrestSlotType2CrestList.IsMissingCrest( + clearUnit.EquipCrestSlotType2CrestId2 + ) + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Wyrmprint, + (int)clearUnit.EquipCrestSlotType2CrestId2 + ); + clearUnit.EquipCrestSlotType2CrestId2 = 0; + } + + if ( + detailUnit.CrestSlotType3CrestList.IsMissingCrest( + clearUnit.EquipCrestSlotType3CrestId1 + ) + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Wyrmprint, + (int)clearUnit.EquipCrestSlotType3CrestId1 + ); + clearUnit.EquipCrestSlotType3CrestId1 = 0; + } + + if ( + detailUnit.CrestSlotType3CrestList.IsMissingCrest( + clearUnit.EquipCrestSlotType3CrestId2 + ) + ) + { + yield return new AtgenLostUnitList( + clearUnit.UnitNo, + EntityTypes.Wyrmprint, + (int)clearUnit.EquipCrestSlotType3CrestId2 + ); + clearUnit.EquipCrestSlotType3CrestId2 = 0; + } + } + } +} + +file static class Extensions +{ + public static bool IsMissingCrest(this IEnumerable source, AbilityCrests id) + { + if (id == AbilityCrests.Empty) + return false; + + // ReSharper disable once SimplifyLinqExpressionUseAll + return !source.Any(x => x?.AbilityCrestId == id); + } +} diff --git a/DragaliaAPI/Features/ClearParty/IClearPartyRepository.cs b/DragaliaAPI/Features/ClearParty/IClearPartyRepository.cs new file mode 100644 index 000000000..77bbc6540 --- /dev/null +++ b/DragaliaAPI/Features/ClearParty/IClearPartyRepository.cs @@ -0,0 +1,11 @@ +using DragaliaAPI.Database.Entities; + +namespace DragaliaAPI.Features.ClearParty; + +public interface IClearPartyRepository +{ + IQueryable QuestClearPartyUnits { get; } + + void SetQuestClearParty(int questId, bool isMulti, IEnumerable units); + IQueryable GetQuestClearParty(int questId, bool isMulti); +} diff --git a/DragaliaAPI/Features/ClearParty/IClearPartyService.cs b/DragaliaAPI/Features/ClearParty/IClearPartyService.cs new file mode 100644 index 000000000..50d2a34bb --- /dev/null +++ b/DragaliaAPI/Features/ClearParty/IClearPartyService.cs @@ -0,0 +1,12 @@ +using DragaliaAPI.Models.Generated; + +namespace DragaliaAPI.Features.ClearParty; + +public interface IClearPartyService +{ + Task<( + IEnumerable PartyList, + IEnumerable LostUnitList + )> GetQuestClearParty(int questId, bool isMulti); + Task SetQuestClearParty(int questId, bool isMulti, IEnumerable party); +} diff --git a/DragaliaAPI/Features/Dungeon/DungeonRepository.cs b/DragaliaAPI/Features/Dungeon/DungeonRepository.cs index ace768d45..b131e9424 100644 --- a/DragaliaAPI/Features/Dungeon/DungeonRepository.cs +++ b/DragaliaAPI/Features/Dungeon/DungeonRepository.cs @@ -1,6 +1,7 @@ using System.Diagnostics; using DragaliaAPI.Database; using DragaliaAPI.Database.Entities; +using DragaliaAPI.Database.Entities.Abstract; using DragaliaAPI.Database.Entities.Scaffold; using DragaliaAPI.Models.Generated; using DragaliaAPI.Shared.Definitions.Enums; @@ -21,6 +22,143 @@ public DungeonRepository(ApiContext apiContext, IPlayerIdentityService playerIde this.playerIdentityService = playerIdentityService; } + public IQueryable BuildDetailedPartyUnit( + IQueryable input + ) + { + return from unit in input + from chara in this.apiContext.PlayerCharaData + .Where(x => x.CharaId == unit.CharaId && x.DeviceAccountId == unit.DeviceAccountId) + .DefaultIfEmpty() + from dragon in this.apiContext.PlayerDragonData + .Where( + x => + x.DragonKeyId == unit.EquipDragonKeyId + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from weapon in this.apiContext.PlayerWeapons + .Where( + x => + x.WeaponBodyId == unit.EquipWeaponBodyId + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from crests11 in this.apiContext.PlayerAbilityCrests + .Where( + x => + x.AbilityCrestId == unit.EquipCrestSlotType1CrestId1 + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from crests12 in this.apiContext.PlayerAbilityCrests + .Where( + x => + x.AbilityCrestId == unit.EquipCrestSlotType1CrestId2 + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from crests13 in this.apiContext.PlayerAbilityCrests + .Where( + x => + x.AbilityCrestId == unit.EquipCrestSlotType1CrestId3 + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from crests21 in this.apiContext.PlayerAbilityCrests + .Where( + x => + x.AbilityCrestId == unit.EquipCrestSlotType2CrestId1 + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from crests22 in this.apiContext.PlayerAbilityCrests + .Where( + x => + x.AbilityCrestId == unit.EquipCrestSlotType2CrestId2 + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from crests31 in this.apiContext.PlayerAbilityCrests + .Where( + x => + x.AbilityCrestId == unit.EquipCrestSlotType3CrestId1 + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from crests32 in this.apiContext.PlayerAbilityCrests + .Where( + x => + x.AbilityCrestId == unit.EquipCrestSlotType3CrestId2 + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from charaEs1 in this.apiContext.PlayerCharaData + .Where( + x => + x.CharaId == unit.EditSkill1CharaId + && x.DeviceAccountId == unit.DeviceAccountId + && x.IsUnlockEditSkill + ) + .DefaultIfEmpty() + from charaEs2 in this.apiContext.PlayerCharaData + .Where( + x => + x.CharaId == unit.EditSkill2CharaId + && x.DeviceAccountId == unit.DeviceAccountId + && x.IsUnlockEditSkill + ) + .DefaultIfEmpty() + from talisman in this.apiContext.PlayerTalismans + .Where( + x => + x.TalismanKeyId == unit.EquipTalismanKeyId + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + from skin in this.apiContext.PlayerWeaponSkins + .Where( + x => + x.WeaponSkinId == unit.EquipWeaponSkinId + && x.DeviceAccountId == unit.DeviceAccountId + ) + .DefaultIfEmpty() + select new DbDetailedPartyUnit + { + DeviceAccountId = this.playerIdentityService.AccountId, + Position = unit.UnitNo, + CharaData = chara, + DragonData = dragon, + WeaponBodyData = weapon, + CrestSlotType1CrestList = new List() + { + crests11, + crests12, + crests13 + }, + CrestSlotType2CrestList = new List() { crests21, crests22 }, + CrestSlotType3CrestList = new List() { crests31, crests32 }, + EditSkill1CharaData = + (charaEs1 == null) + ? null + : GetEditSkill( + charaEs1.CharaId, + charaEs1.Skill1Level, + charaEs1.Skill2Level + ), + EditSkill2CharaData = + (charaEs2 == null) + ? null + : GetEditSkill( + charaEs2.CharaId, + charaEs2.Skill1Level, + charaEs2.Skill2Level + ), + TalismanData = talisman, + WeaponSkinData = skin + }; + } + public IQueryable BuildDetailedPartyUnit( IQueryable input, int firstPartyNo @@ -134,7 +272,7 @@ from skin in this.apiContext.PlayerWeaponSkins select new DbDetailedPartyUnit { DeviceAccountId = this.playerIdentityService.AccountId, - Position = unit.UnitNo + (unit.PartyNo == firstPartyNo ? 0 : 4), + Position = unit.PartyNo == firstPartyNo ? unit.UnitNo : unit.UnitNo + 4, CharaData = chara, DragonData = dragon, DragonReliabilityLevel = (dragonReliability == null) ? 0 : dragonReliability.Level, diff --git a/DragaliaAPI/Features/Dungeon/IDungeonRepository.cs b/DragaliaAPI/Features/Dungeon/IDungeonRepository.cs index 839ad5b11..457cc9414 100644 --- a/DragaliaAPI/Features/Dungeon/IDungeonRepository.cs +++ b/DragaliaAPI/Features/Dungeon/IDungeonRepository.cs @@ -1,4 +1,5 @@ using DragaliaAPI.Database.Entities; +using DragaliaAPI.Database.Entities.Abstract; using DragaliaAPI.Database.Entities.Scaffold; using DragaliaAPI.Models.Generated; @@ -14,4 +15,6 @@ IQueryable BuildDetailedPartyUnit( IQueryable input, int firstPartyNo ); + + IQueryable BuildDetailedPartyUnit(IQueryable input); } diff --git a/DragaliaAPI/Features/Quest/QuestController.cs b/DragaliaAPI/Features/Quest/QuestController.cs new file mode 100644 index 000000000..cfa77f869 --- /dev/null +++ b/DragaliaAPI/Features/Quest/QuestController.cs @@ -0,0 +1,162 @@ +using DragaliaAPI.Controllers; +using DragaliaAPI.Features.ClearParty; +using DragaliaAPI.Features.Dungeon; +using DragaliaAPI.Models.Generated; +using DragaliaAPI.Services; +using DragaliaAPI.Services.Game; +using DragaliaAPI.Shared.Definitions.Enums; +using Microsoft.AspNetCore.Mvc; + +namespace DragaliaAPI.Features.Quest; + +[Route("quest")] +[ApiController] +public class QuestController : DragaliaControllerBase +{ + private readonly IStoryService storyService; + private readonly IHelperService helperService; + private readonly IQuestDropService questRewardService; + private readonly IUpdateDataService updateDataService; + private readonly IClearPartyService clearPartyService; + private readonly ILogger logger; + + public QuestController( + IStoryService storyService, + IHelperService helperService, + IQuestDropService questRewardService, + IUpdateDataService updateDataService, + IClearPartyService clearPartyService, + ILogger logger + ) + { + this.storyService = storyService; + this.helperService = helperService; + this.questRewardService = questRewardService; + this.updateDataService = updateDataService; + this.clearPartyService = clearPartyService; + this.logger = logger; + } + + [HttpPost] + [Route("read_story")] + public async Task ReadStory(QuestReadStoryRequest request) + { + IEnumerable rewardList = await this.storyService.ReadStory( + StoryTypes.Quest, + request.quest_story_id + ); + + EntityResult entityResult = StoryService.GetEntityResult(rewardList); + IEnumerable questRewardList = rewardList.Select( + StoryService.ToQuestStoryReward + ); + + UpdateDataList updateDataList = await this.updateDataService.SaveChangesAsync(); + + return this.Ok( + new QuestReadStoryData() + { + quest_story_reward_list = questRewardList, + entity_result = entityResult, + update_data_list = updateDataList + } + ); + } + + [HttpPost("get_support_user_list")] + public async Task GetUserSupportList() + { + // TODO: this is actually going to be a pretty complicated system + QuestGetSupportUserListData response = await this.helperService.GetHelpers(); + return Ok(response); + } + + [HttpPost("get_quest_clear_party")] + public async Task GetQuestClearParty(QuestGetQuestClearPartyRequest request) + { + (IEnumerable clearParty, IEnumerable lostUnitList) = + await this.clearPartyService.GetQuestClearParty(request.quest_id, false); + + await this.updateDataService.SaveChangesAsync(); // Updated lost entities + + return Ok( + new QuestGetQuestClearPartyData() + { + quest_clear_party_setting_list = clearParty, + lost_unit_list = lostUnitList + } + ); + } + + [HttpPost("get_quest_clear_party_multi")] + public async Task GetQuestClearPartyMulti( + QuestGetQuestClearPartyMultiRequest request + ) + { + (IEnumerable clearParty, IEnumerable lostUnitList) = + await this.clearPartyService.GetQuestClearParty(request.quest_id, true); + + await this.updateDataService.SaveChangesAsync(); + + return Ok( + new QuestGetQuestClearPartyMultiData() + { + quest_multi_clear_party_setting_list = clearParty, + lost_unit_list = lostUnitList + } + ); + } + + [HttpPost("set_quest_clear_party")] + public async Task SetQuestClearParty(QuestSetQuestClearPartyRequest request) + { + await this.clearPartyService.SetQuestClearParty( + request.quest_id, + false, + request.request_party_setting_list + ); + + await this.updateDataService.SaveChangesAsync(); + + return Ok(new QuestSetQuestClearPartyData() { result = 1 }); + } + + [HttpPost("set_quest_clear_party_multi")] + public async Task SetQuestClearParty( + QuestSetQuestClearPartyMultiRequest request + ) + { + await this.clearPartyService.SetQuestClearParty( + request.quest_id, + true, + request.request_party_setting_list + ); + + await this.updateDataService.SaveChangesAsync(); + + return Ok(new QuestSetQuestClearPartyMultiData() { result = 1 }); + } + + [HttpPost("drop_list")] + public DragaliaResult DropList(QuestDropListRequest request) + { + IEnumerable drops = this.questRewardService.GetDrops(request.quest_id); + + return Ok( + new QuestDropListData() + { + quest_drop_info = new() + { + drop_info_list = drops.Select( + x => + new AtgenDuplicateEntityList() + { + entity_id = (int)x, + entity_type = EntityTypes.Material + } + ) + } + } + ); + } +} diff --git a/DragaliaAPI/Models/Generated/Components.cs b/DragaliaAPI/Models/Generated/Components.cs index 4686d7bff..572c27811 100644 --- a/DragaliaAPI/Models/Generated/Components.cs +++ b/DragaliaAPI/Models/Generated/Components.cs @@ -866,28 +866,28 @@ public class AtgenCharaUnitSetDetailList public int unit_set_no { get; set; } public string unit_set_name { get; set; } public ulong dragon_key_id { get; set; } - public int weapon_body_id { get; set; } - public int crest_slot_type_1_crest_id_1 { get; set; } - public int crest_slot_type_1_crest_id_2 { get; set; } - public int crest_slot_type_1_crest_id_3 { get; set; } - public int crest_slot_type_2_crest_id_1 { get; set; } - public int crest_slot_type_2_crest_id_2 { get; set; } - public int crest_slot_type_3_crest_id_1 { get; set; } - public int crest_slot_type_3_crest_id_2 { get; set; } + public WeaponBodies weapon_body_id { get; set; } + public AbilityCrests crest_slot_type_1_crest_id_1 { get; set; } + public AbilityCrests crest_slot_type_1_crest_id_2 { get; set; } + public AbilityCrests crest_slot_type_1_crest_id_3 { get; set; } + public AbilityCrests crest_slot_type_2_crest_id_1 { get; set; } + public AbilityCrests crest_slot_type_2_crest_id_2 { get; set; } + public AbilityCrests crest_slot_type_3_crest_id_1 { get; set; } + public AbilityCrests crest_slot_type_3_crest_id_2 { get; set; } public ulong talisman_key_id { get; set; } public AtgenCharaUnitSetDetailList( int unit_set_no, string unit_set_name, ulong dragon_key_id, - int weapon_body_id, - int crest_slot_type_1_crest_id_1, - int crest_slot_type_1_crest_id_2, - int crest_slot_type_1_crest_id_3, - int crest_slot_type_2_crest_id_1, - int crest_slot_type_2_crest_id_2, - int crest_slot_type_3_crest_id_1, - int crest_slot_type_3_crest_id_2, + WeaponBodies weapon_body_id, + AbilityCrests crest_slot_type_1_crest_id_1, + AbilityCrests crest_slot_type_1_crest_id_2, + AbilityCrests crest_slot_type_1_crest_id_3, + AbilityCrests crest_slot_type_2_crest_id_1, + AbilityCrests crest_slot_type_2_crest_id_2, + AbilityCrests crest_slot_type_3_crest_id_1, + AbilityCrests crest_slot_type_3_crest_id_2, ulong talisman_key_id ) { @@ -3267,26 +3267,26 @@ public AtgenRequestAbilityCrestSetData() { } public class AtgenRequestCharaUnitSetData { public ulong dragon_key_id { get; set; } - public int weapon_body_id { get; set; } - public int crest_slot_type_1_crest_id_1 { get; set; } - public int crest_slot_type_1_crest_id_2 { get; set; } - public int crest_slot_type_1_crest_id_3 { get; set; } - public int crest_slot_type_2_crest_id_1 { get; set; } - public int crest_slot_type_2_crest_id_2 { get; set; } - public int crest_slot_type_3_crest_id_1 { get; set; } - public int crest_slot_type_3_crest_id_2 { get; set; } + public WeaponBodies weapon_body_id { get; set; } + public AbilityCrests crest_slot_type_1_crest_id_1 { get; set; } + public AbilityCrests crest_slot_type_1_crest_id_2 { get; set; } + public AbilityCrests crest_slot_type_1_crest_id_3 { get; set; } + public AbilityCrests crest_slot_type_2_crest_id_1 { get; set; } + public AbilityCrests crest_slot_type_2_crest_id_2 { get; set; } + public AbilityCrests crest_slot_type_3_crest_id_1 { get; set; } + public AbilityCrests crest_slot_type_3_crest_id_2 { get; set; } public ulong talisman_key_id { get; set; } public AtgenRequestCharaUnitSetData( ulong dragon_key_id, - int weapon_body_id, - int crest_slot_type_1_crest_id_1, - int crest_slot_type_1_crest_id_2, - int crest_slot_type_1_crest_id_3, - int crest_slot_type_2_crest_id_1, - int crest_slot_type_2_crest_id_2, - int crest_slot_type_3_crest_id_1, - int crest_slot_type_3_crest_id_2, + WeaponBodies weapon_body_id, + AbilityCrests crest_slot_type_1_crest_id_1, + AbilityCrests crest_slot_type_1_crest_id_2, + AbilityCrests crest_slot_type_1_crest_id_3, + AbilityCrests crest_slot_type_2_crest_id_1, + AbilityCrests crest_slot_type_2_crest_id_2, + AbilityCrests crest_slot_type_3_crest_id_1, + AbilityCrests crest_slot_type_3_crest_id_2, ulong talisman_key_id ) { @@ -7291,6 +7291,8 @@ Charas edit_skill_2_chara_id } public PartySettingList() { } + + public static PartySettingList Empty(int unit_no) => new() { unit_no = unit_no }; } #nullable enable diff --git a/DragaliaAPI/Program.cs b/DragaliaAPI/Program.cs index bff0bda77..d3b1d82c3 100644 --- a/DragaliaAPI/Program.cs +++ b/DragaliaAPI/Program.cs @@ -5,6 +5,7 @@ using DragaliaAPI.Features.Missions; using DragaliaAPI.Features.Stamp; using DragaliaAPI.Extensions; +using DragaliaAPI.Features.ClearParty; using DragaliaAPI.Features.GraphQL; using DragaliaAPI.Features.SavefileUpdate; using DragaliaAPI.Features.Shop; @@ -164,7 +165,10 @@ .AddScoped() .AddScoped() .AddScoped() - .AddScoped(); + .AddScoped() + // Clear party feature + .AddScoped() + .AddScoped(); builder.Services.AddAllOfType(); builder.Services.AddAllOfType(); diff --git a/DragaliaAPI/Services/Photon/HeroParamService.cs b/DragaliaAPI/Services/Photon/HeroParamService.cs index d4e146c55..fc6a2f331 100644 --- a/DragaliaAPI/Services/Photon/HeroParamService.cs +++ b/DragaliaAPI/Services/Photon/HeroParamService.cs @@ -1,5 +1,4 @@ using System.Collections.Immutable; -using System.ComponentModel.DataAnnotations; using DragaliaAPI.Database.Entities; using DragaliaAPI.Database.Entities.Scaffold; using DragaliaAPI.Database.Repositories; @@ -11,7 +10,6 @@ using DragaliaAPI.Shared.MasterAsset; using DragaliaAPI.Shared.MasterAsset.Models; using DragaliaAPI.Shared.PlayerDetails; -using Microsoft.AspNetCore.Mvc.ModelBinding; using Microsoft.EntityFrameworkCore; namespace DragaliaAPI.Services.Photon; @@ -63,8 +61,6 @@ public async Task> GetHeroParam(long viewerId, int partyS { this.logger.LogDebug("Fetching HeroParam for slot {partySlots}", partySlot); - List result = new(); - DbPlayerUserData userData = await this.userDataRepository .GetViewerData(viewerId) .SingleAsync();