1
0
mirror of synced 2024-11-27 16:10:53 +01:00

Fixed migration issues from CHN

* WordListEntries are now loaded using FirstOrDefault to avoid crashes when using malformed custom wordlists
* Added missing field UnlockedUraSongIdList to AddMyDonEntryCommand
This commit is contained in:
Farewell_ 2024-11-08 15:54:59 +01:00
parent 463f832b31
commit 5b0c81e104
6 changed files with 655 additions and 16 deletions

View File

@ -12,7 +12,6 @@ namespace GameDatabase.Entities
public List<uint> FavoriteSongsArray { get; set; } = [];
public List<uint> ToneFlgArray { get; set; } = [0];
public List<uint> TitleFlgArray { get; set; } = [];
public string CostumeFlgArray { get; set; } = "[[],[],[],[],[]]";
public List<uint> UnlockedKigurumi { get; set; } = [0];
public List<uint> UnlockedHead { get; set; } = [0];
public List<uint> UnlockedBody { get; set; }= [0];
@ -23,12 +22,9 @@ namespace GameDatabase.Entities
public int NotesPosition { get; set; }
public bool IsVoiceOn { get; set; } = true;
public bool IsSkipOn { get; set; }
public string DifficultyPlayedArray { get; set; } = "[]";
public uint DifficultyPlayedCourse { get; set; }
public uint DifficultyPlayedStar { get; set; }
public uint DifficultyPlayedSort { get; set; }
public string DifficultySettingArray { get; set; } = "[]";
public uint DifficultySettingCourse { get; set; }
public uint DifficultySettingStar { get; set; }
public uint DifficultySettingSort { get; set; }
@ -38,8 +34,6 @@ namespace GameDatabase.Entities
public uint ColorBody { get; set; }
public uint ColorFace { get; set; }
public uint ColorLimb { get; set; }
public string CostumeData { get; set; } = "[]";
public uint CurrentKigurumi { get; set; }
public uint CurrentHead { get; set; }
public uint CurrentBody { get; set; }

View File

@ -0,0 +1,576 @@
// <auto-generated />
using System;
using GameDatabase.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace GameDatabase.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20241108132749_RemoveUnusedArrays")]
partial class RemoveUnusedArrays
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.4");
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<bool>("IsWin")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty");
b.ToTable("AiScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<int>("SectionIndex")
.HasColumnType("INTEGER");
b.Property<int>("Crown")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<bool>("IsWin")
.HasColumnType("INTEGER");
b.Property<uint>("MissCount")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<uint>("Score")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
b.ToTable("AiSectionScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
{
b.Property<string>("AccessCode")
.HasColumnType("TEXT");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.HasKey("AccessCode");
b.HasIndex("Baid");
b.ToTable("Card", (string)null);
});
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Salt")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Baid");
b.ToTable("Credential", (string)null);
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
b.Property<int>("DanType")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(1);
b.Property<uint>("ArrivalSongCount")
.HasColumnType("INTEGER");
b.Property<uint>("ClearState")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(0u);
b.Property<uint>("ComboCountTotal")
.HasColumnType("INTEGER");
b.Property<uint>("SoulGaugeTotal")
.HasColumnType("INTEGER");
b.HasKey("Baid", "DanId", "DanType");
b.ToTable("DanScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
b.Property<int>("DanType")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER")
.HasDefaultValue(1);
b.Property<uint>("SongNumber")
.HasColumnType("INTEGER");
b.Property<uint>("BadCount")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<uint>("HighScore")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<uint>("PlayScore")
.HasColumnType("INTEGER");
b.Property<uint>("TotalHitCount")
.HasColumnType("INTEGER");
b.HasKey("Baid", "DanId", "DanType", "SongNumber");
b.ToTable("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<uint>("BestCrown")
.HasColumnType("INTEGER");
b.Property<uint>("BestRate")
.HasColumnType("INTEGER");
b.Property<uint>("BestScore")
.HasColumnType("INTEGER");
b.Property<uint>("BestScoreRank")
.HasColumnType("INTEGER");
b.HasKey("Baid", "SongId", "Difficulty");
b.ToTable("SongBestData");
});
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("ComboCount")
.HasColumnType("INTEGER");
b.Property<uint>("Crown")
.HasColumnType("INTEGER");
b.Property<uint>("Difficulty")
.HasColumnType("INTEGER");
b.Property<uint>("DrumrollCount")
.HasColumnType("INTEGER");
b.Property<uint>("GoodCount")
.HasColumnType("INTEGER");
b.Property<uint>("HitCount")
.HasColumnType("INTEGER");
b.Property<uint>("MissCount")
.HasColumnType("INTEGER");
b.Property<uint>("OkCount")
.HasColumnType("INTEGER");
b.Property<DateTime>("PlayTime")
.HasColumnType("datetime");
b.Property<uint>("Score")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRank")
.HasColumnType("INTEGER");
b.Property<uint>("ScoreRate")
.HasColumnType("INTEGER");
b.Property<bool>("Skipped")
.HasColumnType("INTEGER");
b.Property<uint>("SongId")
.HasColumnType("INTEGER");
b.Property<uint>("SongNumber")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("Baid");
b.ToTable("SongPlayData");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.Property<uint>("Baid")
.HasColumnType("INTEGER");
b.Property<int>("Id")
.HasColumnType("INTEGER");
b.Property<int>("Count")
.HasColumnType("INTEGER");
b.HasKey("Baid", "Id");
b.ToTable("Tokens");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Property<uint>("Baid")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<uint>("AchievementDisplayDifficulty")
.HasColumnType("INTEGER");
b.Property<int>("AiWinCount")
.HasColumnType("INTEGER");
b.Property<uint>("ColorBody")
.HasColumnType("INTEGER");
b.Property<uint>("ColorFace")
.HasColumnType("INTEGER");
b.Property<uint>("ColorLimb")
.HasColumnType("INTEGER");
b.Property<string>("CostumeData")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("CostumeFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("CurrentBody")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentFace")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentHead")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentKigurumi")
.HasColumnType("INTEGER");
b.Property<uint>("CurrentPuchi")
.HasColumnType("INTEGER");
b.Property<string>("DifficultyPlayedArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("DifficultyPlayedCourse")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultyPlayedSort")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultyPlayedStar")
.HasColumnType("INTEGER");
b.Property<string>("DifficultySettingArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("DifficultySettingCourse")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultySettingSort")
.HasColumnType("INTEGER");
b.Property<uint>("DifficultySettingStar")
.HasColumnType("INTEGER");
b.Property<bool>("DisplayAchievement")
.HasColumnType("INTEGER");
b.Property<bool>("DisplayDan")
.HasColumnType("INTEGER");
b.Property<string>("FavoriteSongsArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("GenericInfoFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("IsAdmin")
.HasColumnType("INTEGER");
b.Property<bool>("IsSkipOn")
.HasColumnType("INTEGER");
b.Property<bool>("IsVoiceOn")
.HasColumnType("INTEGER");
b.Property<DateTime>("LastPlayDatetime")
.HasColumnType("datetime");
b.Property<uint>("LastPlayMode")
.HasColumnType("INTEGER");
b.Property<string>("MyDonName")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("MyDonNameLanguage")
.HasColumnType("INTEGER");
b.Property<int>("NotesPosition")
.HasColumnType("INTEGER");
b.Property<short>("OptionSetting")
.HasColumnType("INTEGER");
b.Property<uint>("SelectedToneId")
.HasColumnType("INTEGER");
b.Property<string>("Title")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("TitleFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<uint>("TitlePlateId")
.HasColumnType("INTEGER");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedBody")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedFace")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedHead")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedKigurumi")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedPuchi")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedSongIdList")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("UnlockedUraSongIdList")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Baid");
b.ToTable("UserData");
});
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.AiScoreDatum", "Parent")
.WithMany("AiSectionScoreData")
.HasForeignKey("Baid", "SongId", "Difficulty")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Parent");
});
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.HasOne("GameDatabase.Entities.DanScoreDatum", "Parent")
.WithMany("DanStageScoreData")
.HasForeignKey("Baid", "DanId", "DanType")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Parent");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
.WithMany()
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Ba");
});
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
{
b.HasOne("GameDatabase.Entities.UserDatum", "Datum")
.WithMany("Tokens")
.HasForeignKey("Baid")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Datum");
});
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Navigation("AiSectionScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Navigation("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{
b.Navigation("Tokens");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,67 @@
using GameDatabase.Context;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace GameDatabase.Migrations
{
/// <inheritdoc />
public partial class RemoveUnusedArrays : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
//We messed up a few migrations before so this is aiming to fix the usual issues you can encounter when migrating from 08.18 and CHN.
//Removing the following tables as they have been split a while ago and are not longer being used.
migrationBuilder.Sql(@"ALTER TABLE UserData DROP COLUMN CostumeData");
migrationBuilder.Sql(@"ALTER TABLE UserData DROP COLUMN CostumeFlgArray");
migrationBuilder.Sql(@"ALTER TABLE UserData DROP COLUMN DifficultyPlayedArray");
migrationBuilder.Sql(@"ALTER TABLE UserData DROP COLUMN DifficultySettingArray");
//The default value of the previous migration was incorrectly set, causing a crash on load.
migrationBuilder.Sql(@"UPDATE UserData SET UnlockedUraSongIdList = '[]' WHERE UnlockedUraSongIdList = ''");
migrationBuilder.Sql(@"UPDATE UserData SET UnlockedSongIdList = '[]' WHERE UnlockedSongIdList = ''");
//These arrays should not be empty
migrationBuilder.Sql(@"UPDATE UserData SET UnlockedPuchi = '[0]' WHERE UnlockedPuchi = '[]'");
migrationBuilder.Sql(@"UPDATE UserData SET UnlockedHead = '[0]' WHERE UnlockedHead = '[]'");
migrationBuilder.Sql(@"UPDATE UserData SET UnlockedFace = '[0]' WHERE UnlockedFace = '[]'");
migrationBuilder.Sql(@"UPDATE UserData SET UnlockedBody = '[0]' WHERE UnlockedBody = '[]'");
migrationBuilder.Sql(@"UPDATE UserData SET ToneFlgArray = '[0]' WHERE ToneFlgArray = '[]'");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "CostumeData",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "[]");
migrationBuilder.AddColumn<string>(
name: "CostumeFlgArray",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "[]");
migrationBuilder.AddColumn<string>(
name: "DifficultyPlayedArray",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "[0,0,0]");
migrationBuilder.AddColumn<string>(
name: "DifficultySettingArray",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "[0,0,0]");
}
}
}

View File

@ -15,7 +15,7 @@ namespace TaikoLocalServer.Migrations
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.3");
modelBuilder.HasAnnotation("ProductVersion", "8.0.4");
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{

View File

@ -33,7 +33,8 @@ public class AddMyDonEntryCommandHandler(TaikoDbContext context, ILogger<AddMyDo
UnlockedHead = [0],
UnlockedPuchi = [0],
GenericInfoFlgArray = [],
UnlockedSongIdList = []
UnlockedSongIdList = [],
UnlockedUraSongIdList = [],
};
context.UserData.Add(newUser);

View File

@ -403,14 +403,15 @@ public class GameDataService(IOptions<DataSettings> dataSettings) : IGameDataSer
var musicId = musicInfo.Id;
var musicNameKey = $"song_{musicId}";
var musicArtistKey = $"song_sub_{musicId}";
var musicName = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).JapaneseText;
var musicArtist = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).JapaneseText;
var musicNameEn = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).EnglishUsText;
var musicArtistEn = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).EnglishUsText;
var musicNameCn = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).ChineseTText;
var musicArtistCn = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).ChineseTText;
var musicNameKo = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).KoreanText;
var musicArtistKo = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).KoreanText;
//Using FirstOrDefault because the server could crash when the wordlist had missing song_sub entries.
var musicName = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicNameKey)?.JapaneseText ?? "";
var musicArtist = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicArtistKey)?.JapaneseText ?? "";
var musicNameEn = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicNameKey)?.EnglishUsText ?? "";
var musicArtistEn = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicArtistKey)?.EnglishUsText ?? "";
var musicNameCn = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicNameKey)?.ChineseTText ?? "";
var musicArtistCn = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicArtistKey)?.ChineseTText ?? "";
var musicNameKo = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicNameKey)?.KoreanText ?? "";
var musicArtistKo = wordlistData.WordListEntries.FirstOrDefault(entry => entry.Key == musicArtistKey)?.KoreanText ?? "";
var musicGenre = musicInfo.Genre;
var musicStarEasy = musicInfo.StarEasy;
var musicStarNormal = musicInfo.StarNormal;