Pack logic cleanup

This commit is contained in:
gamer147
2026-05-24 09:27:10 -04:00
parent 79209bd70b
commit d9ef9fe1fc
33 changed files with 71175 additions and 245 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,338 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SVSim.Database.Migrations
{
/// <inheritdoc />
public partial class RefactorGameConfigurationToJsonb : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
// Step 1: Add the new jsonb column FIRST so the backfill SQL can read the old columns.
migrationBuilder.AddColumn<string>(
name: "Config",
table: "GameConfigurations",
type: "jsonb",
nullable: false,
defaultValue: "");
// Step 2: Backfill — project old flat columns into the new jsonb document.
// For fresh-install databases (no pre-existing rows) this is a no-op; the
// DefaultSettingsSeeder InsertData in the previous migration already seeded the
// parent row, so the UPDATE below covers it. PackRates defaults are hard-coded
// here because the old schema had no equivalent columns.
// Use provider-specific SQL: PostgreSQL jsonb functions vs SQLite json functions.
migrationBuilder.Sql(
"""
UPDATE "GameConfigurations"
SET "Config" = jsonb_build_object(
'DefaultGrants', jsonb_build_object(
'Crystals', "DefaultCrystals",
'Rupees', "DefaultRupees",
'Ether', "DefaultEther"
),
'Player', jsonb_build_object(
'MaxFriends', "MaxFriends"
),
'DefaultLoadout', jsonb_build_object(
'DegreeId', "DefaultDegreeId",
'EmblemId', "DefaultEmblemId",
'MyPageBackgroundId', "DefaultMyPageBackgroundId",
'SleeveId', "DefaultSleeveId"
),
'Challenge', jsonb_build_object(
'UseTwoPickPremiumCard', "ChallengeUseTwoPickPremiumCard",
'TwoPickSleeveId', "ChallengeTwoPickSleeveId"
),
'Rotation', jsonb_build_object(
'TsRotationId', "TsRotationId",
'IsBattlePassPeriod', "IsBattlePassPeriod",
'IsBeginnerMission', "IsBeginnerMission",
'CardSetIdForResourceDlView', "CardSetIdForResourceDlView"
),
'PackRates', jsonb_build_object(
'AnimatedRate', 0.08,
'Default', jsonb_build_object('Bronze', 0.6744, 'Silver', 0.25, 'Gold', 0.06, 'Legendary', 0.015),
'PerSlot', jsonb_build_array(
jsonb_build_object('Slot', '8', 'Bronze', 0, 'Silver', 0.7692, 'Gold', 0.1846, 'Legendary', 0.0462)
)
)
)
WHERE "Id" = 'default';
""",
suppressTransaction: true);
// For SQLite (tests): use json() and json_object() functions.
migrationBuilder.Sql(
"""
UPDATE "GameConfigurations"
SET "Config" = json('{"DefaultGrants":{"Crystals":'||COALESCE("DefaultCrystals", 0)||',"Rupees":'||COALESCE("DefaultRupees", 0)||',"Ether":'||COALESCE("DefaultEther", 0)||'},'||
'"Player":{"MaxFriends":'||COALESCE("MaxFriends", 0)||'},'||
'"DefaultLoadout":{"DegreeId":'||COALESCE("DefaultDegreeId", 0)||',"EmblemId":'||COALESCE("DefaultEmblemId", 0)||',"MyPageBackgroundId":'||COALESCE("DefaultMyPageBackgroundId", 0)||',"SleeveId":'||COALESCE("DefaultSleeveId", 0)||'},'||
'"Challenge":{"UseTwoPickPremiumCard":'||(CASE WHEN "ChallengeUseTwoPickPremiumCard" THEN 'true' ELSE 'false' END)||',"TwoPickSleeveId":'||COALESCE("ChallengeTwoPickSleeveId", 0)||'},'||
'"Rotation":{"TsRotationId":"'||COALESCE("TsRotationId", '')||'","IsBattlePassPeriod":'||(CASE WHEN "IsBattlePassPeriod" THEN 'true' ELSE 'false' END)||',"IsBeginnerMission":'||(CASE WHEN "IsBeginnerMission" THEN 'true' ELSE 'false' END)||',"CardSetIdForResourceDlView":'||COALESCE("CardSetIdForResourceDlView", 0)||'},'||
'"PackRates":{"AnimatedRate":0.08,"Default":{"Bronze":0.6744,"Silver":0.25,"Gold":0.06,"Legendary":0.015},"PerSlot":[{"Slot":"8","Bronze":0,"Silver":0.7692,"Gold":0.1846,"Legendary":0.0462}]}'||
'}')
WHERE "Id" = 'default';
""",
suppressTransaction: true);
// Step 3: Drop FK constraints, indexes, and old flat columns.
migrationBuilder.DropForeignKey(
name: "FK_GameConfigurations_Degrees_DefaultDegreeId",
table: "GameConfigurations");
migrationBuilder.DropForeignKey(
name: "FK_GameConfigurations_Emblems_DefaultEmblemId",
table: "GameConfigurations");
migrationBuilder.DropForeignKey(
name: "FK_GameConfigurations_MyPageBackgrounds_DefaultMyPageBackgroun~",
table: "GameConfigurations");
migrationBuilder.DropForeignKey(
name: "FK_GameConfigurations_Sleeves_DefaultSleeveId",
table: "GameConfigurations");
migrationBuilder.DropIndex(
name: "IX_GameConfigurations_DefaultDegreeId",
table: "GameConfigurations");
migrationBuilder.DropIndex(
name: "IX_GameConfigurations_DefaultEmblemId",
table: "GameConfigurations");
migrationBuilder.DropIndex(
name: "IX_GameConfigurations_DefaultMyPageBackgroundId",
table: "GameConfigurations");
migrationBuilder.DropIndex(
name: "IX_GameConfigurations_DefaultSleeveId",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "CardSetIdForResourceDlView",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "ChallengeTwoPickSleeveId",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "ChallengeUseTwoPickPremiumCard",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "DefaultCrystals",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "DefaultDegreeId",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "DefaultEmblemId",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "DefaultEther",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "DefaultMyPageBackgroundId",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "DefaultRupees",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "DefaultSleeveId",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "IsBattlePassPeriod",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "IsBeginnerMission",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "MaxFriends",
table: "GameConfigurations");
migrationBuilder.DropColumn(
name: "TsRotationId",
table: "GameConfigurations");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Config",
table: "GameConfigurations");
migrationBuilder.AddColumn<int>(
name: "CardSetIdForResourceDlView",
table: "GameConfigurations",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<long>(
name: "ChallengeTwoPickSleeveId",
table: "GameConfigurations",
type: "bigint",
nullable: false,
defaultValue: 0L);
migrationBuilder.AddColumn<bool>(
name: "ChallengeUseTwoPickPremiumCard",
table: "GameConfigurations",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<decimal>(
name: "DefaultCrystals",
table: "GameConfigurations",
type: "numeric(20,0)",
nullable: false,
defaultValue: 0m);
migrationBuilder.AddColumn<int>(
name: "DefaultDegreeId",
table: "GameConfigurations",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "DefaultEmblemId",
table: "GameConfigurations",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<decimal>(
name: "DefaultEther",
table: "GameConfigurations",
type: "numeric(20,0)",
nullable: false,
defaultValue: 0m);
migrationBuilder.AddColumn<int>(
name: "DefaultMyPageBackgroundId",
table: "GameConfigurations",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<decimal>(
name: "DefaultRupees",
table: "GameConfigurations",
type: "numeric(20,0)",
nullable: false,
defaultValue: 0m);
migrationBuilder.AddColumn<int>(
name: "DefaultSleeveId",
table: "GameConfigurations",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<bool>(
name: "IsBattlePassPeriod",
table: "GameConfigurations",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "IsBeginnerMission",
table: "GameConfigurations",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<int>(
name: "MaxFriends",
table: "GameConfigurations",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<string>(
name: "TsRotationId",
table: "GameConfigurations",
type: "text",
nullable: false,
defaultValue: "");
migrationBuilder.UpdateData(
table: "GameConfigurations",
keyColumn: "Id",
keyValue: "default",
columns: new[] { "CardSetIdForResourceDlView", "ChallengeTwoPickSleeveId", "ChallengeUseTwoPickPremiumCard", "DefaultCrystals", "DefaultDegreeId", "DefaultEmblemId", "DefaultEther", "DefaultMyPageBackgroundId", "DefaultRupees", "DefaultSleeveId", "IsBattlePassPeriod", "IsBeginnerMission", "MaxFriends", "TsRotationId" },
values: new object[] { 0, 0L, false, 50000m, 300003, 100000000, 50000m, 100000000, 50000m, 3000011, false, false, 20, "" });
migrationBuilder.CreateIndex(
name: "IX_GameConfigurations_DefaultDegreeId",
table: "GameConfigurations",
column: "DefaultDegreeId");
migrationBuilder.CreateIndex(
name: "IX_GameConfigurations_DefaultEmblemId",
table: "GameConfigurations",
column: "DefaultEmblemId");
migrationBuilder.CreateIndex(
name: "IX_GameConfigurations_DefaultMyPageBackgroundId",
table: "GameConfigurations",
column: "DefaultMyPageBackgroundId");
migrationBuilder.CreateIndex(
name: "IX_GameConfigurations_DefaultSleeveId",
table: "GameConfigurations",
column: "DefaultSleeveId");
migrationBuilder.AddForeignKey(
name: "FK_GameConfigurations_Degrees_DefaultDegreeId",
table: "GameConfigurations",
column: "DefaultDegreeId",
principalTable: "Degrees",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_GameConfigurations_Emblems_DefaultEmblemId",
table: "GameConfigurations",
column: "DefaultEmblemId",
principalTable: "Emblems",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_GameConfigurations_MyPageBackgrounds_DefaultMyPageBackgroun~",
table: "GameConfigurations",
column: "DefaultMyPageBackgroundId",
principalTable: "MyPageBackgrounds",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
migrationBuilder.AddForeignKey(
name: "FK_GameConfigurations_Sleeves_DefaultSleeveId",
table: "GameConfigurations",
column: "DefaultSleeveId",
principalTable: "Sleeves",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace SVSim.Database.Migrations
{
/// <inheritdoc />
public partial class AddIsFoilToCards : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "IsFoil",
table: "Cards",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "IsFoil",
table: "Cards");
}
}
}

View File

@@ -21730,87 +21730,15 @@ namespace SVSim.Database.Migrations
b.Property<string>("Id")
.HasColumnType("text");
b.Property<int>("CardSetIdForResourceDlView")
.HasColumnType("integer");
b.Property<long>("ChallengeTwoPickSleeveId")
.HasColumnType("bigint");
b.Property<bool>("ChallengeUseTwoPickPremiumCard")
.HasColumnType("boolean");
b.Property<DateTime>("DateCreated")
.HasColumnType("timestamp with time zone");
b.Property<DateTime?>("DateUpdated")
.HasColumnType("timestamp with time zone");
b.Property<decimal>("DefaultCrystals")
.HasColumnType("numeric(20,0)");
b.Property<int>("DefaultDegreeId")
.HasColumnType("integer");
b.Property<int>("DefaultEmblemId")
.HasColumnType("integer");
b.Property<decimal>("DefaultEther")
.HasColumnType("numeric(20,0)");
b.Property<int>("DefaultMyPageBackgroundId")
.HasColumnType("integer");
b.Property<decimal>("DefaultRupees")
.HasColumnType("numeric(20,0)");
b.Property<int>("DefaultSleeveId")
.HasColumnType("integer");
b.Property<bool>("IsBattlePassPeriod")
.HasColumnType("boolean");
b.Property<bool>("IsBeginnerMission")
.HasColumnType("boolean");
b.Property<int>("MaxFriends")
.HasColumnType("integer");
b.Property<string>("TsRotationId")
.IsRequired()
.HasColumnType("text");
b.HasKey("Id");
b.HasIndex("DefaultDegreeId");
b.HasIndex("DefaultEmblemId");
b.HasIndex("DefaultMyPageBackgroundId");
b.HasIndex("DefaultSleeveId");
b.ToTable("GameConfigurations");
b.HasData(
new
{
Id = "default",
CardSetIdForResourceDlView = 0,
ChallengeTwoPickSleeveId = 0L,
ChallengeUseTwoPickPremiumCard = false,
DateCreated = new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified),
DefaultCrystals = 50000m,
DefaultDegreeId = 300003,
DefaultEmblemId = 100000000,
DefaultEther = 50000m,
DefaultMyPageBackgroundId = 100000000,
DefaultRupees = 50000m,
DefaultSleeveId = 3000011,
IsBattlePassPeriod = false,
IsBeginnerMission = false,
MaxFriends = 20,
TsRotationId = ""
});
});
modelBuilder.Entity("SVSim.Database.Models.ItemEntry", b =>
@@ -26427,6 +26355,9 @@ namespace SVSim.Database.Migrations
b.Property<int?>("Defense")
.HasColumnType("integer");
b.Property<bool>("IsFoil")
.HasColumnType("boolean");
b.Property<string>("Name")
.IsRequired()
.HasColumnType("text");
@@ -34232,37 +34163,230 @@ namespace SVSim.Database.Migrations
modelBuilder.Entity("SVSim.Database.Models.GameConfiguration", b =>
{
b.HasOne("SVSim.Database.Models.DegreeEntry", "DefaultDegree")
.WithMany()
.HasForeignKey("DefaultDegreeId")
.OnDelete(DeleteBehavior.Cascade)
b.OwnsOne("SVSim.Database.Models.GameConfigRoot", "Config", b1 =>
{
b1.Property<string>("GameConfigurationId")
.HasColumnType("text");
b1.HasKey("GameConfigurationId");
b1.ToTable("GameConfigurations");
b1.ToJson("Config");
b1.WithOwner()
.HasForeignKey("GameConfigurationId");
b1.OwnsOne("SVSim.Database.Models.Config.ChallengeConfig", "Challenge", b2 =>
{
b2.Property<string>("GameConfigRootGameConfigurationId")
.HasColumnType("text");
b2.Property<long>("TwoPickSleeveId")
.HasColumnType("bigint");
b2.Property<bool>("UseTwoPickPremiumCard")
.HasColumnType("boolean");
b2.HasKey("GameConfigRootGameConfigurationId");
b2.ToTable("GameConfigurations");
b2.WithOwner()
.HasForeignKey("GameConfigRootGameConfigurationId");
});
b1.OwnsOne("SVSim.Database.Models.Config.DefaultGrantsConfig", "DefaultGrants", b2 =>
{
b2.Property<string>("GameConfigRootGameConfigurationId")
.HasColumnType("text");
b2.Property<decimal>("Crystals")
.HasColumnType("numeric(20,0)");
b2.Property<decimal>("Ether")
.HasColumnType("numeric(20,0)");
b2.Property<decimal>("Rupees")
.HasColumnType("numeric(20,0)");
b2.HasKey("GameConfigRootGameConfigurationId");
b2.ToTable("GameConfigurations");
b2.WithOwner()
.HasForeignKey("GameConfigRootGameConfigurationId");
});
b1.OwnsOne("SVSim.Database.Models.Config.DefaultLoadoutConfig", "DefaultLoadout", b2 =>
{
b2.Property<string>("GameConfigRootGameConfigurationId")
.HasColumnType("text");
b2.Property<int>("DegreeId")
.HasColumnType("integer");
b2.Property<int>("EmblemId")
.HasColumnType("integer");
b2.Property<int>("MyPageBackgroundId")
.HasColumnType("integer");
b2.Property<int>("SleeveId")
.HasColumnType("integer");
b2.HasKey("GameConfigRootGameConfigurationId");
b2.ToTable("GameConfigurations");
b2.WithOwner()
.HasForeignKey("GameConfigRootGameConfigurationId");
});
b1.OwnsOne("SVSim.Database.Models.Config.PackRateConfig", "PackRates", b2 =>
{
b2.Property<string>("GameConfigRootGameConfigurationId")
.HasColumnType("text");
b2.Property<double>("AnimatedRate")
.HasColumnType("double precision");
b2.HasKey("GameConfigRootGameConfigurationId");
b2.ToTable("GameConfigurations");
b2.WithOwner()
.HasForeignKey("GameConfigRootGameConfigurationId");
b2.OwnsOne("SVSim.Database.Models.Config.SlotRarityWeights", "Default", b3 =>
{
b3.Property<string>("PackRateConfigGameConfigRootGameConfigurationId")
.HasColumnType("text");
b3.Property<double>("Bronze")
.HasColumnType("double precision");
b3.Property<double>("Gold")
.HasColumnType("double precision");
b3.Property<double>("Legendary")
.HasColumnType("double precision");
b3.Property<double>("Silver")
.HasColumnType("double precision");
b3.Property<string>("Slot")
.HasColumnType("text");
b3.HasKey("PackRateConfigGameConfigRootGameConfigurationId");
b3.ToTable("GameConfigurations");
b3.WithOwner()
.HasForeignKey("PackRateConfigGameConfigRootGameConfigurationId");
});
b2.OwnsMany("SVSim.Database.Models.Config.SlotRarityWeights", "PerSlot", b3 =>
{
b3.Property<string>("PackRateConfigGameConfigRootGameConfigurationId")
.HasColumnType("text");
b3.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer");
b3.Property<double>("Bronze")
.HasColumnType("double precision");
b3.Property<double>("Gold")
.HasColumnType("double precision");
b3.Property<double>("Legendary")
.HasColumnType("double precision");
b3.Property<double>("Silver")
.HasColumnType("double precision");
b3.Property<string>("Slot")
.HasColumnType("text");
b3.HasKey("PackRateConfigGameConfigRootGameConfigurationId", "Id");
b3.ToTable("GameConfigurations");
b3.WithOwner()
.HasForeignKey("PackRateConfigGameConfigRootGameConfigurationId");
});
b2.Navigation("Default")
.IsRequired();
b2.Navigation("PerSlot");
});
b1.OwnsOne("SVSim.Database.Models.Config.PlayerConfig", "Player", b2 =>
{
b2.Property<string>("GameConfigRootGameConfigurationId")
.HasColumnType("text");
b2.Property<int>("MaxFriends")
.HasColumnType("integer");
b2.HasKey("GameConfigRootGameConfigurationId");
b2.ToTable("GameConfigurations");
b2.WithOwner()
.HasForeignKey("GameConfigRootGameConfigurationId");
});
b1.OwnsOne("SVSim.Database.Models.Config.RotationConfig", "Rotation", b2 =>
{
b2.Property<string>("GameConfigRootGameConfigurationId")
.HasColumnType("text");
b2.Property<int>("CardSetIdForResourceDlView")
.HasColumnType("integer");
b2.Property<bool>("IsBattlePassPeriod")
.HasColumnType("boolean");
b2.Property<bool>("IsBeginnerMission")
.HasColumnType("boolean");
b2.Property<string>("TsRotationId")
.IsRequired()
.HasColumnType("text");
b2.HasKey("GameConfigRootGameConfigurationId");
b2.ToTable("GameConfigurations");
b2.WithOwner()
.HasForeignKey("GameConfigRootGameConfigurationId");
});
b1.Navigation("Challenge")
.IsRequired();
b1.Navigation("DefaultGrants")
.IsRequired();
b1.Navigation("DefaultLoadout")
.IsRequired();
b1.Navigation("PackRates")
.IsRequired();
b1.Navigation("Player")
.IsRequired();
b1.Navigation("Rotation")
.IsRequired();
});
b.Navigation("Config")
.IsRequired();
b.HasOne("SVSim.Database.Models.EmblemEntry", "DefaultEmblem")
.WithMany()
.HasForeignKey("DefaultEmblemId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SVSim.Database.Models.MyPageBackgroundEntry", "DefaultMyPageBackground")
.WithMany()
.HasForeignKey("DefaultMyPageBackgroundId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("SVSim.Database.Models.SleeveEntry", "DefaultSleeve")
.WithMany()
.HasForeignKey("DefaultSleeveId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("DefaultDegree");
b.Navigation("DefaultEmblem");
b.Navigation("DefaultMyPageBackground");
b.Navigation("DefaultSleeve");
});
modelBuilder.Entity("SVSim.Database.Models.LeaderSkinEntry", b =>