diff --git a/GameDatabase/Entities/UserDatum.cs b/GameDatabase/Entities/UserDatum.cs index f9a81c0..5a33c78 100644 --- a/GameDatabase/Entities/UserDatum.cs +++ b/GameDatabase/Entities/UserDatum.cs @@ -17,6 +17,8 @@ namespace GameDatabase.Entities public int NotesPosition { get; set; } public bool IsVoiceOn { get; set; } public bool IsSkipOn { get; set; } + public string DifficultyPlayedArray { get; set; } = "[]"; + public string DifficultySettingArray { get; set; } = "[]"; public uint SelectedToneId { get; set; } public DateTime LastPlayDatetime { get; set; } public uint LastPlayMode { get; set; } diff --git a/GameDatabase/Migrations/20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData.Designer.cs b/GameDatabase/Migrations/20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData.Designer.cs new file mode 100644 index 0000000..1e75389 --- /dev/null +++ b/GameDatabase/Migrations/20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData.Designer.cs @@ -0,0 +1,451 @@ +// +using System; +using GameDatabase.Context; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace TaikoLocalServer.Migrations +{ + [DbContext(typeof(TaikoDbContext))] + [Migration("20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData")] + partial class AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder.HasAnnotation("ProductVersion", "7.0.0-rc.1.22426.7"); + + modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("IsWin") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty"); + + b.ToTable("AiScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("SectionIndex") + .HasColumnType("INTEGER"); + + b.Property("Crown") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("IsWin") + .HasColumnType("INTEGER"); + + b.Property("MissCount") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex"); + + b.ToTable("AiSectionScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.Card", b => + { + b.Property("AccessCode") + .HasColumnType("TEXT"); + + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.HasKey("AccessCode"); + + b.HasIndex(new[] { "Baid" }, "IX_Card_Baid") + .IsUnique(); + + b.ToTable("Card", (string)null); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("DanId") + .HasColumnType("INTEGER"); + + b.Property("ArrivalSongCount") + .HasColumnType("INTEGER"); + + b.Property("ClearState") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER") + .HasDefaultValue(0u); + + b.Property("ComboCountTotal") + .HasColumnType("INTEGER"); + + b.Property("SoulGaugeTotal") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "DanId"); + + b.ToTable("DanScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("DanId") + .HasColumnType("INTEGER"); + + b.Property("SongNumber") + .HasColumnType("INTEGER"); + + b.Property("BadCount") + .HasColumnType("INTEGER"); + + b.Property("ComboCount") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("HighScore") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("PlayScore") + .HasColumnType("INTEGER"); + + b.Property("TotalHitCount") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "DanId", "SongNumber"); + + b.ToTable("DanStageScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("BestCrown") + .HasColumnType("INTEGER"); + + b.Property("BestRate") + .HasColumnType("INTEGER"); + + b.Property("BestScore") + .HasColumnType("INTEGER"); + + b.Property("BestScoreRank") + .HasColumnType("INTEGER"); + + b.HasKey("Baid", "SongId", "Difficulty"); + + b.ToTable("SongBestData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("INTEGER"); + + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("ComboCount") + .HasColumnType("INTEGER"); + + b.Property("Crown") + .HasColumnType("INTEGER"); + + b.Property("Difficulty") + .HasColumnType("INTEGER"); + + b.Property("DrumrollCount") + .HasColumnType("INTEGER"); + + b.Property("GoodCount") + .HasColumnType("INTEGER"); + + b.Property("HitCount") + .HasColumnType("INTEGER"); + + b.Property("MissCount") + .HasColumnType("INTEGER"); + + b.Property("OkCount") + .HasColumnType("INTEGER"); + + b.Property("PlayTime") + .HasColumnType("datetime"); + + b.Property("Score") + .HasColumnType("INTEGER"); + + b.Property("ScoreRank") + .HasColumnType("INTEGER"); + + b.Property("ScoreRate") + .HasColumnType("INTEGER"); + + b.Property("Skipped") + .HasColumnType("INTEGER"); + + b.Property("SongId") + .HasColumnType("INTEGER"); + + b.Property("SongNumber") + .HasColumnType("INTEGER"); + + b.HasKey("Id"); + + b.HasIndex("Baid"); + + b.ToTable("SongPlayData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.UserDatum", b => + { + b.Property("Baid") + .HasColumnType("INTEGER"); + + b.Property("AchievementDisplayDifficulty") + .HasColumnType("INTEGER"); + + b.Property("AiWinCount") + .HasColumnType("INTEGER"); + + b.Property("ColorBody") + .HasColumnType("INTEGER"); + + b.Property("ColorFace") + .HasColumnType("INTEGER"); + + b.Property("ColorLimb") + .HasColumnType("INTEGER"); + + b.Property("CostumeData") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("CostumeFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DifficultyPlayedArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DifficultySettingArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DisplayAchievement") + .HasColumnType("INTEGER"); + + b.Property("DisplayDan") + .HasColumnType("INTEGER"); + + b.Property("FavoriteSongsArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("GenericInfoFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("IsSkipOn") + .HasColumnType("INTEGER"); + + b.Property("IsVoiceOn") + .HasColumnType("INTEGER"); + + b.Property("LastPlayDatetime") + .HasColumnType("datetime"); + + b.Property("LastPlayMode") + .HasColumnType("INTEGER"); + + b.Property("MyDonName") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("NotesPosition") + .HasColumnType("INTEGER"); + + b.Property("OptionSetting") + .HasColumnType("INTEGER"); + + b.Property("SelectedToneId") + .HasColumnType("INTEGER"); + + b.Property("Title") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TitleFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("TitlePlateId") + .HasColumnType("INTEGER"); + + b.Property("TokenCountDict") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("ToneFlgArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("UnlockedSongIdList") + .IsRequired() + .HasColumnType("TEXT"); + + b.HasKey("Baid"); + + b.ToTable("UserData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b => + { + b.HasOne("GameDatabase.Entities.Card", "Ba") + .WithMany() + .HasForeignKey("Baid") + .HasPrincipalKey("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.DanScoreDatum", b => + { + b.HasOne("GameDatabase.Entities.Card", "Ba") + .WithMany() + .HasForeignKey("Baid") + .HasPrincipalKey("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") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Parent"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b => + { + b.HasOne("GameDatabase.Entities.Card", "Ba") + .WithMany() + .HasForeignKey("Baid") + .HasPrincipalKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b => + { + b.HasOne("GameDatabase.Entities.Card", "Ba") + .WithMany() + .HasForeignKey("Baid") + .HasPrincipalKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.UserDatum", b => + { + b.HasOne("GameDatabase.Entities.Card", "Ba") + .WithMany() + .HasForeignKey("Baid") + .HasPrincipalKey("Baid") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Ba"); + }); + + modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b => + { + b.Navigation("AiSectionScoreData"); + }); + + modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b => + { + b.Navigation("DanStageScoreData"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/GameDatabase/Migrations/20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData.cs b/GameDatabase/Migrations/20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData.cs new file mode 100644 index 0000000..240b325 --- /dev/null +++ b/GameDatabase/Migrations/20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData.cs @@ -0,0 +1,40 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace TaikoLocalServer.Migrations +{ + /// + public partial class AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "DifficultyPlayedArray", + table: "UserData", + type: "TEXT", + nullable: false, + defaultValue: "[]"); + + migrationBuilder.AddColumn( + name: "DifficultySettingArray", + table: "UserData", + type: "TEXT", + nullable: false, + defaultValue: "[]"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "DifficultyPlayedArray", + table: "UserData"); + + migrationBuilder.DropColumn( + name: "DifficultySettingArray", + table: "UserData"); + } + } +} diff --git a/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs b/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs index 0c04119..2c0118c 100644 --- a/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs +++ b/GameDatabase/Migrations/TaikoDbContextModelSnapshot.cs @@ -276,6 +276,14 @@ namespace TaikoLocalServer.Migrations .IsRequired() .HasColumnType("TEXT"); + b.Property("DifficultyPlayedArray") + .IsRequired() + .HasColumnType("TEXT"); + + b.Property("DifficultySettingArray") + .IsRequired() + .HasColumnType("TEXT"); + b.Property("DisplayAchievement") .HasColumnType("INTEGER"); diff --git a/TaikoLocalServer/Controllers/Game/PlayResultController.cs b/TaikoLocalServer/Controllers/Game/PlayResultController.cs index 013f12c..d71f9d0 100644 --- a/TaikoLocalServer/Controllers/Game/PlayResultController.cs +++ b/TaikoLocalServer/Controllers/Game/PlayResultController.cs @@ -203,16 +203,17 @@ public class PlayResultController : BaseController }; userdata.CostumeData = JsonSerializer.Serialize(costumeData); + // Skip user setting altogether following official logic // Skip user setting saving when in dan mode as dan mode uses its own default setting - if (playMode != PlayMode.DanMode) - { - var lastStage = playResultData.AryStageInfoes.Last(); - var option = BinaryPrimitives.ReadInt16LittleEndian(lastStage.OptionFlg); - userdata.OptionSetting = option; - userdata.IsSkipOn = lastStage.IsSkipOn; - userdata.IsVoiceOn = !lastStage.IsVoiceOn; - userdata.NotesPosition = lastStage.NotesPosition; - } + // if (playMode != PlayMode.DanMode) + // { + // var lastStage = playResultData.AryStageInfoes.Last(); + // var option = BinaryPrimitives.ReadInt16LittleEndian(lastStage.OptionFlg); + // userdata.OptionSetting = option; + // userdata.IsSkipOn = lastStage.IsSkipOn; + // userdata.IsVoiceOn = !lastStage.IsVoiceOn; + // userdata.NotesPosition = lastStage.NotesPosition; + // } userdata.LastPlayDatetime = lastPlayDatetime; userdata.LastPlayMode = playResultData.PlayMode; @@ -236,6 +237,14 @@ public class PlayResultController : BaseController userdata.GenericInfoFlgArray = UpdateJsonUintFlagArray(userdata.GenericInfoFlgArray, playResultData.GetGenericInfoNoes, nameof(userdata.GenericInfoFlgArray)); + var difficultyPlayedArray = new List + { + playResultData.DifficultyPlayedCourse, + playResultData.DifficultyPlayedStar, + playResultData.DifficultyPlayedSort + }; + userdata.DifficultyPlayedArray = JsonSerializer.Serialize(difficultyPlayedArray); + userdata.AiWinCount += playResultData.AryStageInfoes.Count(data => data.IsWin); await userDatumService.UpdateUserDatum(userdata); } diff --git a/TaikoLocalServer/Controllers/Game/UserDataController.cs b/TaikoLocalServer/Controllers/Game/UserDataController.cs index 582e680..69cc0bf 100644 --- a/TaikoLocalServer/Controllers/Game/UserDataController.cs +++ b/TaikoLocalServer/Controllers/Game/UserDataController.cs @@ -110,7 +110,27 @@ public class UserDataController : BaseController var defaultOptions = new byte[2]; BinaryPrimitives.WriteInt16LittleEndian(defaultOptions, userData.OptionSetting); + + var difficultyPlayedArray = Array.Empty(); + try + { + difficultyPlayedArray = JsonSerializer.Deserialize(userData.DifficultyPlayedArray); + } + catch (JsonException e) + { + Logger.LogError(e, "Parsing difficulty played json data failed"); + } + var difficultySettingArray = Array.Empty(); + try + { + difficultySettingArray = JsonSerializer.Deserialize(userData.DifficultySettingArray); + } + catch (JsonException e) + { + Logger.LogError(e, "Parsing difficulty setting json data failed"); + } + var response = new UserDataResponse { Result = 1, @@ -128,6 +148,20 @@ public class UserDataController : BaseController SongRecentCnt = (uint)recentSongs.Length }; + if (difficultyPlayedArray is { Length: >= 3 }) + { + response.DifficultyPlayedCourse = difficultyPlayedArray[0]; + response.DifficultyPlayedStar = difficultyPlayedArray[1]; + response.DifficultyPlayedSort = difficultyPlayedArray[2]; + } + + if (difficultySettingArray is { Length: >= 3 }) + { + response.DifficultySettingCourse = difficultySettingArray[0]; + response.DifficultySettingStar = difficultySettingArray[1]; + response.DifficultySettingSort = difficultySettingArray[2]; + } + return Ok(response); } } \ No newline at end of file