1
0
mirror of synced 2024-11-23 22:41:01 +01:00

Merge from TaikoLocalServer-CHN repo

This commit is contained in:
S-Sebb 2023-10-16 10:38:27 +01:00
commit df2c8024ea
844 changed files with 10284 additions and 5356 deletions

View File

@ -4,7 +4,7 @@ namespace GameDatabase.Entities;
public class AiScoreDatum public class AiScoreDatum
{ {
public uint Baid { get; set; } public ulong Baid { get; set; }
public uint SongId { get; set; } public uint SongId { get; set; }

View File

@ -4,7 +4,7 @@ namespace GameDatabase.Entities;
public class AiSectionScoreDatum public class AiSectionScoreDatum
{ {
public uint Baid { get; set; } public ulong Baid { get; set; }
public uint SongId { get; set; } public uint SongId { get; set; }

View File

@ -3,6 +3,8 @@
public partial class Card public partial class Card
{ {
public string AccessCode { get; set; } = null!; public string AccessCode { get; set; } = null!;
public uint Baid { get; set; } public ulong Baid { get; set; }
public string Password { get; set; } = null!;
public string Salt { get; set; } = null!;
} }
} }

View File

@ -4,7 +4,7 @@ namespace GameDatabase.Entities;
public class DanScoreDatum public class DanScoreDatum
{ {
public uint Baid { get; set; } public ulong Baid { get; set; }
public uint DanId { get; set; } public uint DanId { get; set; }
public uint ArrivalSongCount { get; set; } public uint ArrivalSongCount { get; set; }
public uint SoulGaugeTotal { get; set; } public uint SoulGaugeTotal { get; set; }

View File

@ -2,7 +2,7 @@
public class DanStageScoreDatum public class DanStageScoreDatum
{ {
public uint Baid { get; set; } public ulong Baid { get; set; }
public uint DanId { get; set; } public uint DanId { get; set; }

View File

@ -2,16 +2,16 @@
namespace GameDatabase.Entities namespace GameDatabase.Entities
{ {
public partial class SongBestDatum public partial class SongBestDatum
{ {
public uint Baid { get; set; } public ulong Baid { get; set; }
public uint SongId { get; set; } public uint SongId { get; set; }
public Difficulty Difficulty { get; set; } public Difficulty Difficulty { get; set; }
public uint BestScore { get; set; } public uint BestScore { get; set; }
public uint BestRate { get; set; } public uint BestRate { get; set; }
public CrownType BestCrown { get; set; } public CrownType BestCrown { get; set; }
public ScoreRank BestScoreRank { get; set; } public ScoreRank BestScoreRank { get; set; }
public virtual Card? Ba { get; set; } public virtual Card? Ba { get; set; }
} }
} }

View File

@ -5,7 +5,7 @@ namespace GameDatabase.Entities
public partial class SongPlayDatum public partial class SongPlayDatum
{ {
public long Id { get; set; } public long Id { get; set; }
public uint Baid { get; set; } public ulong Baid { get; set; }
public uint SongNumber { get; set; } public uint SongNumber { get; set; }

View File

@ -2,33 +2,37 @@
namespace GameDatabase.Entities namespace GameDatabase.Entities
{ {
public partial class UserDatum public partial class UserDatum
{ {
public uint Baid { get; set; } public ulong Baid { get; set; }
public string MyDonName { get; set; } = string.Empty; public string MyDonName { get; set; } = string.Empty;
public string Title { get; set; } = string.Empty; public uint MyDonNameLanguage { get; set; }
public uint TitlePlateId { get; set; } public string Title { get; set; } = string.Empty;
public string FavoriteSongsArray { get; set; } = "[]"; public uint TitlePlateId { get; set; }
public string ToneFlgArray { get; set; } = "[]"; public string FavoriteSongsArray { get; set; } = "[]";
public string TitleFlgArray { get; set; } = "[]"; public string ToneFlgArray { get; set; } = "[]";
public string CostumeFlgArray { get; set; } = "[[],[],[],[],[]]"; public string TitleFlgArray { get; set; } = "[]";
public string GenericInfoFlgArray { get; set; } = "[]"; public string CostumeFlgArray { get; set; } = "[[],[],[],[],[]]";
public short OptionSetting { get; set; } public string GenericInfoFlgArray { get; set; } = "[]";
public int NotesPosition { get; set; } public short OptionSetting { get; set; }
public bool IsVoiceOn { get; set; } public int NotesPosition { get; set; }
public bool IsSkipOn { get; set; } public bool IsVoiceOn { get; set; }
public uint SelectedToneId { get; set; } public bool IsSkipOn { get; set; }
public DateTime LastPlayDatetime { get; set; } public string DifficultyPlayedArray { get; set; } = "[]";
public uint LastPlayMode { get; set; } public string DifficultySettingArray { get; set; } = "[]";
public uint ColorBody { get; set; } public uint SelectedToneId { get; set; }
public uint ColorFace { get; set; } public DateTime LastPlayDatetime { get; set; }
public uint ColorLimb { get; set; } public uint LastPlayMode { get; set; }
public string CostumeData { get; set; } = "[[],[],[],[],[]]"; public uint ColorBody { get; set; }
public bool DisplayDan { get; set; } public uint ColorFace { get; set; }
public bool DisplayAchievement { get; set; } public uint ColorLimb { get; set; }
public Difficulty AchievementDisplayDifficulty { get; set; } public string CostumeData { get; set; } = "[]";
public bool DisplayDan { get; set; }
public int AiWinCount { get; set; } public bool DisplayAchievement { get; set; }
public virtual Card? Ba { get; set; } public Difficulty AchievementDisplayDifficulty { get; set; }
} public int AiWinCount { get; set; }
public string TokenCountDict { get; set; } = "{}";
public string UnlockedSongIdList { get; set; } = "[]";
public virtual Card? Ba { get; set; }
}
} }

View File

@ -1,22 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>11</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\SharedProject\SharedProject.csproj" /> <ProjectReference Include="..\SharedProject\SharedProject.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0-rc.1.22426.7" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0-rc.1.23419.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-rc.1.22426.7" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-rc.1.23419.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-rc.1.22426.7"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0-rc.1.23419.6">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -0,0 +1,443 @@
// <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 TaikoLocalServer.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20230916161613_AddTokenCountDictAndUnlockedSongIdListToUserdata")]
partial class AddTokenCountDictAndUnlockedSongIdListToUserdata
{
/// <inheritdoc />
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<ulong>("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<ulong>("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<ulong>("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<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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");
b.ToTable("DanScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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", "SongNumber");
b.ToTable("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<ulong>("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<ulong>("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.UserDatum", b =>
{
b.Property<ulong>("Baid")
.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<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>("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<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>("TokenCountDict")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("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
}
}
}

View File

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TaikoLocalServer.Migrations
{
/// <inheritdoc />
public partial class AddTokenCountDictAndUnlockedSongIdListToUserdata : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "TokenCountDict",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "UnlockedSongIdList",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "TokenCountDict",
table: "UserData");
migrationBuilder.DropColumn(
name: "UnlockedSongIdList",
table: "UserData");
}
}
}

View File

@ -0,0 +1,451 @@
// <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 TaikoLocalServer.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20230918052543_AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData")]
partial class AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData
{
/// <inheritdoc />
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<ulong>("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<ulong>("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<ulong>("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<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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");
b.ToTable("DanScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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", "SongNumber");
b.ToTable("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<ulong>("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<ulong>("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.UserDatum", b =>
{
b.Property<ulong>("Baid")
.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<string>("DifficultyPlayedArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("DifficultySettingArray")
.IsRequired()
.HasColumnType("TEXT");
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>("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<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>("TokenCountDict")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("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
}
}
}

View File

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TaikoLocalServer.Migrations
{
/// <inheritdoc />
public partial class AddDifficultyPlayedArrayAndDifficultySettingArrayToUserData : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "DifficultyPlayedArray",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "[]");
migrationBuilder.AddColumn<string>(
name: "DifficultySettingArray",
table: "UserData",
type: "TEXT",
nullable: false,
defaultValue: "[]");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "DifficultyPlayedArray",
table: "UserData");
migrationBuilder.DropColumn(
name: "DifficultySettingArray",
table: "UserData");
}
}
}

View File

@ -0,0 +1,454 @@
// <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 TaikoLocalServer.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20230918101009_AddMyDonNameLanguageToUserData")]
partial class AddMyDonNameLanguageToUserData
{
/// <inheritdoc />
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<ulong>("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<ulong>("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<ulong>("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<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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");
b.ToTable("DanScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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", "SongNumber");
b.ToTable("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<ulong>("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<ulong>("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.UserDatum", b =>
{
b.Property<ulong>("Baid")
.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<string>("DifficultyPlayedArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("DifficultySettingArray")
.IsRequired()
.HasColumnType("TEXT");
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>("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>("TokenCountDict")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("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
}
}
}

View File

@ -0,0 +1,29 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TaikoLocalServer.Migrations
{
/// <inheritdoc />
public partial class AddMyDonNameLanguageToUserData : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<uint>(
name: "MyDonNameLanguage",
table: "UserData",
type: "INTEGER",
nullable: false,
defaultValue: 0u);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MyDonNameLanguage",
table: "UserData");
}
}
}

View File

@ -0,0 +1,462 @@
// <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 TaikoLocalServer.Migrations
{
[DbContext(typeof(TaikoDbContext))]
[Migration("20230928150650_AddPasswordAndSaltToCard")]
partial class AddPasswordAndSaltToCard
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6");
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{
b.Property<ulong>("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<ulong>("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<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Salt")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("AccessCode");
b.HasIndex(new[] { "Baid" }, "IX_Card_Baid")
.IsUnique();
b.ToTable("Card", (string)null);
});
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{
b.Property<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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");
b.ToTable("DanScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{
b.Property<ulong>("Baid")
.HasColumnType("INTEGER");
b.Property<uint>("DanId")
.HasColumnType("INTEGER");
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", "SongNumber");
b.ToTable("DanStageScoreData");
});
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{
b.Property<ulong>("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<ulong>("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.UserDatum", b =>
{
b.Property<ulong>("Baid")
.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<string>("DifficultyPlayedArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("DifficultySettingArray")
.IsRequired()
.HasColumnType("TEXT");
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>("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>("TokenCountDict")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ToneFlgArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("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
}
}
}

View File

@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace TaikoLocalServer.Migrations
{
/// <inheritdoc />
public partial class AddPasswordAndSaltToCard : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Password",
table: "Card",
type: "TEXT",
nullable: false,
defaultValue: "");
migrationBuilder.AddColumn<string>(
name: "Salt",
table: "Card",
type: "TEXT",
nullable: false,
defaultValue: "");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Password",
table: "Card");
migrationBuilder.DropColumn(
name: "Salt",
table: "Card");
}
}
}

View File

@ -15,11 +15,11 @@ namespace TaikoLocalServer.Migrations
protected override void BuildModel(ModelBuilder modelBuilder) protected override void BuildModel(ModelBuilder modelBuilder)
{ {
#pragma warning disable 612, 618 #pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "7.0.0-preview.7.22376.2"); modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.1.23419.6");
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{ {
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("SongId") b.Property<uint>("SongId")
@ -36,9 +36,9 @@ namespace TaikoLocalServer.Migrations
b.ToTable("AiScoreData"); b.ToTable("AiScoreData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{ {
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("SongId") b.Property<uint>("SongId")
@ -76,14 +76,22 @@ namespace TaikoLocalServer.Migrations
b.ToTable("AiSectionScoreData"); b.ToTable("AiSectionScoreData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.Card", b => modelBuilder.Entity("GameDatabase.Entities.Card", b =>
{ {
b.Property<string>("AccessCode") b.Property<string>("AccessCode")
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("Password")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Salt")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("AccessCode"); b.HasKey("AccessCode");
b.HasIndex(new[] { "Baid" }, "IX_Card_Baid") b.HasIndex(new[] { "Baid" }, "IX_Card_Baid")
@ -92,9 +100,9 @@ namespace TaikoLocalServer.Migrations
b.ToTable("Card", (string)null); b.ToTable("Card", (string)null);
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{ {
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("DanId") b.Property<uint>("DanId")
@ -119,9 +127,9 @@ namespace TaikoLocalServer.Migrations
b.ToTable("DanScoreData"); b.ToTable("DanScoreData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.DanStageScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{ {
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("DanId") b.Property<uint>("DanId")
@ -159,9 +167,9 @@ namespace TaikoLocalServer.Migrations
b.ToTable("DanStageScoreData"); b.ToTable("DanStageScoreData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.SongBestDatum", b => modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{ {
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("SongId") b.Property<uint>("SongId")
@ -187,13 +195,13 @@ namespace TaikoLocalServer.Migrations
b.ToTable("SongBestData"); b.ToTable("SongBestData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.SongPlayDatum", b => modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{ {
b.Property<long>("Id") b.Property<long>("Id")
.ValueGeneratedOnAdd() .ValueGeneratedOnAdd()
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("ComboCount") b.Property<uint>("ComboCount")
@ -248,9 +256,9 @@ namespace TaikoLocalServer.Migrations
b.ToTable("SongPlayData"); b.ToTable("SongPlayData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.UserDatum", b => modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{ {
b.Property<uint>("Baid") b.Property<ulong>("Baid")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<uint>("AchievementDisplayDifficulty") b.Property<uint>("AchievementDisplayDifficulty")
@ -276,6 +284,14 @@ namespace TaikoLocalServer.Migrations
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<string>("DifficultyPlayedArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("DifficultySettingArray")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("DisplayAchievement") b.Property<bool>("DisplayAchievement")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
@ -306,6 +322,9 @@ namespace TaikoLocalServer.Migrations
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<uint>("MyDonNameLanguage")
.HasColumnType("INTEGER");
b.Property<int>("NotesPosition") b.Property<int>("NotesPosition")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
@ -326,18 +345,26 @@ namespace TaikoLocalServer.Migrations
b.Property<uint>("TitlePlateId") b.Property<uint>("TitlePlateId")
.HasColumnType("INTEGER"); .HasColumnType("INTEGER");
b.Property<string>("TokenCountDict")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ToneFlgArray") b.Property<string>("ToneFlgArray")
.IsRequired() .IsRequired()
.HasColumnType("TEXT"); .HasColumnType("TEXT");
b.Property<string>("UnlockedSongIdList")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Baid"); b.HasKey("Baid");
b.ToTable("UserData"); b.ToTable("UserData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{ {
b.HasOne("TaikoLocalServer.Entities.Card", "Ba") b.HasOne("GameDatabase.Entities.Card", "Ba")
.WithMany() .WithMany()
.HasForeignKey("Baid") .HasForeignKey("Baid")
.HasPrincipalKey("Baid") .HasPrincipalKey("Baid")
@ -347,9 +374,9 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Ba"); b.Navigation("Ba");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.AiSectionScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
{ {
b.HasOne("TaikoLocalServer.Entities.AiScoreDatum", "Parent") b.HasOne("GameDatabase.Entities.AiScoreDatum", "Parent")
.WithMany("AiSectionScoreData") .WithMany("AiSectionScoreData")
.HasForeignKey("Baid", "SongId", "Difficulty") .HasForeignKey("Baid", "SongId", "Difficulty")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
@ -358,9 +385,9 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Parent"); b.Navigation("Parent");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{ {
b.HasOne("TaikoLocalServer.Entities.Card", "Ba") b.HasOne("GameDatabase.Entities.Card", "Ba")
.WithMany() .WithMany()
.HasForeignKey("Baid") .HasForeignKey("Baid")
.HasPrincipalKey("Baid") .HasPrincipalKey("Baid")
@ -370,9 +397,9 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Ba"); b.Navigation("Ba");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.DanStageScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
{ {
b.HasOne("TaikoLocalServer.Entities.DanScoreDatum", "Parent") b.HasOne("GameDatabase.Entities.DanScoreDatum", "Parent")
.WithMany("DanStageScoreData") .WithMany("DanStageScoreData")
.HasForeignKey("Baid", "DanId") .HasForeignKey("Baid", "DanId")
.OnDelete(DeleteBehavior.Cascade) .OnDelete(DeleteBehavior.Cascade)
@ -381,9 +408,9 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Parent"); b.Navigation("Parent");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.SongBestDatum", b => modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
{ {
b.HasOne("TaikoLocalServer.Entities.Card", "Ba") b.HasOne("GameDatabase.Entities.Card", "Ba")
.WithMany() .WithMany()
.HasForeignKey("Baid") .HasForeignKey("Baid")
.HasPrincipalKey("Baid") .HasPrincipalKey("Baid")
@ -393,9 +420,9 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Ba"); b.Navigation("Ba");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.SongPlayDatum", b => modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
{ {
b.HasOne("TaikoLocalServer.Entities.Card", "Ba") b.HasOne("GameDatabase.Entities.Card", "Ba")
.WithMany() .WithMany()
.HasForeignKey("Baid") .HasForeignKey("Baid")
.HasPrincipalKey("Baid") .HasPrincipalKey("Baid")
@ -405,9 +432,9 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Ba"); b.Navigation("Ba");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.UserDatum", b => modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
{ {
b.HasOne("TaikoLocalServer.Entities.Card", "Ba") b.HasOne("GameDatabase.Entities.Card", "Ba")
.WithMany() .WithMany()
.HasForeignKey("Baid") .HasForeignKey("Baid")
.HasPrincipalKey("Baid") .HasPrincipalKey("Baid")
@ -417,12 +444,12 @@ namespace TaikoLocalServer.Migrations
b.Navigation("Ba"); b.Navigation("Ba");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.AiScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
{ {
b.Navigation("AiSectionScoreData"); b.Navigation("AiSectionScoreData");
}); });
modelBuilder.Entity("TaikoLocalServer.Entities.DanScoreDatum", b => modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
{ {
b.Navigation("DanStageScoreData"); b.Navigation("DanStageScoreData");
}); });

View File

@ -2,17 +2,18 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<Version>1.0.0-beta1</Version> <Version>1.0.0-beta1</Version>
<LangVersion>11</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="JorgeSerrano.Json.JsonSnakeCaseNamingPolicy" Version="0.9.0" /> <PackageReference Include="JorgeSerrano.Json.JsonSnakeCaseNamingPolicy" Version="0.9.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.0-rc.1.22426.7" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0-rc.1.23419.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-rc.1.22426.7" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-rc.1.23419.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="7.0.0-rc.1.22426.7"> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0-rc.1.23419.6">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>

View File

@ -1,61 +1,61 @@
using System.CommandLine; using GameDatabase.Context;
using System.CommandLine.Parsing;
using System.Text;
using System.Text.Json;
using GameDatabase.Context;
using GameDatabase.Entities; using GameDatabase.Entities;
using ICSharpCode.SharpZipLib.GZip; using ICSharpCode.SharpZipLib.GZip;
using JorgeSerrano.Json; using JorgeSerrano.Json;
using LocalSaveModScoreMigrator; using LocalSaveModScoreMigrator;
using SharedProject.Enums; using SharedProject.Enums;
using System.CommandLine;
using System.CommandLine.Parsing;
using System.Text;
using System.Text.Json;
var rootCommand = new RootCommand("Command-line tool to migrate saves from local save mod to local server database."); var rootCommand = new RootCommand("Command-line tool to migrate saves from local save mod to local server database.");
FileInfo? Parse(SymbolResult result, string defaultFileName) FileInfo? Parse(SymbolResult result, string defaultFileName)
{ {
if (result.Tokens.Count == 0) if (result.Tokens.Count == 0)
{ {
return new FileInfo(defaultFileName); return new FileInfo(defaultFileName);
} }
var filePath = result.Tokens.Single().Value; var filePath = result.Tokens.Single().Value;
if (File.Exists(filePath)) if (File.Exists(filePath))
{ {
return new FileInfo(filePath); return new FileInfo(filePath);
} }
result.ErrorMessage = $"File {filePath} does not exist"; result.ErrorMessage = $"File {filePath} does not exist";
return null; return null;
} }
var saveFileArgument = new Option<FileInfo?>( var saveFileArgument = new Option<FileInfo?>(
name: "--save-file-path", name: "--save-file-path",
description: "Path to the save file from local save mod", description: "Path to the save file from local save mod",
isDefault: true, isDefault: true,
parseArgument: result => Parse(result, "record_enso_p1.json") parseArgument: result => Parse(result, "record_enso_p1.json")
); );
saveFileArgument.AddAlias("-s"); saveFileArgument.AddAlias("-s");
var dbFileArgument = new Option<FileInfo?>( var dbFileArgument = new Option<FileInfo?>(
name: "--db-file-path", name: "--db-file-path",
description: "Path to the database file for local server", description: "Path to the database file for local server",
isDefault: true, isDefault: true,
parseArgument: result => Parse(result, "wwwroot/taiko.db3") parseArgument: result => Parse(result, "wwwroot/taiko.db3")
); );
dbFileArgument.AddAlias("-db"); dbFileArgument.AddAlias("-db");
var musicInfoArgument = new Option<FileInfo?>( var musicInfoArgument = new Option<FileInfo?>(
name: "--musicinfo-file-path", name: "--musicinfo-file-path",
description: "Path to the music info json/bin file", description: "Path to the music info json/bin file",
isDefault: true, isDefault: true,
parseArgument: result => Parse(result, "wwwroot/data/musicinfo.json") parseArgument: result => Parse(result, "wwwroot/data/musicinfo.json")
); );
musicInfoArgument.AddAlias("-m"); musicInfoArgument.AddAlias("-m");
var baidArgument = new Option<int>( var baidArgument = new Option<ulong>(
name: "--baid", name: "--baid",
description: "Target card's baid, data will be imported to that card", description: "Target card's baid, data will be imported to that card",
getDefaultValue: () => 1 getDefaultValue: () => 1
); );
baidArgument.AddAlias("-b"); baidArgument.AddAlias("-b");
@ -64,133 +64,133 @@ rootCommand.Add(dbFileArgument);
rootCommand.Add(musicInfoArgument); rootCommand.Add(musicInfoArgument);
rootCommand.Add(baidArgument); rootCommand.Add(baidArgument);
rootCommand.SetHandler((saveFile, dbFile, musicInfoFile, baid) => Run(saveFile!, dbFile!, musicInfoFile!, baid), rootCommand.SetHandler((saveFile, dbFile, musicInfoFile, baid) => Run(saveFile!, dbFile!, musicInfoFile!, baid),
saveFileArgument, dbFileArgument, musicInfoArgument, baidArgument); saveFileArgument, dbFileArgument, musicInfoArgument, baidArgument);
await rootCommand.InvokeAsync(args); await rootCommand.InvokeAsync(args);
void Run(FileSystemInfo saveFile, FileSystemInfo dbFile, FileSystemInfo musicInfoFile, int baid) void Run(FileSystemInfo saveFile, FileSystemInfo dbFile, FileSystemInfo musicInfoFile, ulong baid)
{ {
using var db = new TaikoDbContext(dbFile.FullName); using var db = new TaikoDbContext(dbFile.FullName);
var card = db.Cards.FirstOrDefault(card1 => card1.Baid == baid); var card = db.Cards.FirstOrDefault(card1 => card1.Baid == baid);
if (card is null) if (card is null)
{ {
Console.ResetColor(); Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Red;
Console.Error.WriteLine($"Card with baid {baid} does not exist!"); Console.Error.WriteLine($"Card with baid {baid} does not exist!");
Console.ResetColor(); Console.ResetColor();
return; return;
} }
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"Baid: {card.Baid}");
Console.WriteLine($"Access code: {card.AccessCode}");
Console.ResetColor();
var localSaveJson = File.ReadAllText(saveFile.FullName); Console.ResetColor();
var options = new JsonSerializerOptions Console.ForegroundColor = ConsoleColor.Cyan;
{ Console.WriteLine($"Baid: {card.Baid}");
PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy() Console.WriteLine($"Access code: {card.AccessCode}");
}; Console.ResetColor();
options.Converters.Add(new DateTimeConverter());
options.Converters.Add(new ScoreRankConverter());
var playRecordJson = JsonSerializer.Deserialize<List<PlayRecordJson>>(localSaveJson, options);
if (playRecordJson is null)
{
throw new ApplicationException("Play record json is null");
}
Console.WriteLine(playRecordJson.First().SongId); var localSaveJson = File.ReadAllText(saveFile.FullName);
var options = new JsonSerializerOptions
var musicInfoJson = File.ReadAllText(musicInfoFile.FullName); {
if (musicInfoFile.FullName.EndsWith(".bin")) PropertyNamingPolicy = new JsonSnakeCaseNamingPolicy()
{ };
var compressed = File.OpenRead(musicInfoFile.FullName); options.Converters.Add(new DateTimeConverter());
using var gZipInputStream = new GZipInputStream(compressed); options.Converters.Add(new ScoreRankConverter());
using var decompressed = new MemoryStream(); var playRecordJson = JsonSerializer.Deserialize<List<PlayRecordJson>>(localSaveJson, options);
if (playRecordJson is null)
// Decompress {
gZipInputStream.CopyTo(decompressed); throw new ApplicationException("Play record json is null");
}
// Reset stream for reading Console.WriteLine(playRecordJson.First().SongId);
decompressed.Position = 0;
musicInfoJson = Encoding.UTF8.GetString(decompressed.ToArray());
}
var musicInfo = JsonSerializer.Deserialize<MusicInfo>(musicInfoJson);
if (musicInfo is null) var musicInfoJson = File.ReadAllText(musicInfoFile.FullName);
{ if (musicInfoFile.FullName.EndsWith(".bin"))
throw new ApplicationException("Music info is null"); {
} var compressed = File.OpenRead(musicInfoFile.FullName);
using var gZipInputStream = new GZipInputStream(compressed);
using var decompressed = new MemoryStream();
var user = db.UserData.First(); // Decompress
var musicInfoMap = musicInfo.Items.DistinctBy(entry => entry.Id) gZipInputStream.CopyTo(decompressed);
.ToDictionary(entry => entry.Id, entry => entry.SongId);
foreach (var playRecord in playRecordJson) // Reset stream for reading
{ decompressed.Position = 0;
var key = playRecord.SongId.Split("_")[1]; musicInfoJson = Encoding.UTF8.GetString(decompressed.ToArray());
if (!musicInfoMap.ContainsKey(key)) }
{ var musicInfo = JsonSerializer.Deserialize<MusicInfo>(musicInfoJson);
Console.ResetColor();
Console.ForegroundColor = ConsoleColor.Yellow; if (musicInfo is null)
Console.WriteLine($"Key {key} does not exist!!!"); {
Console.ResetColor(); throw new ApplicationException("Music info is null");
continue; }
}
var songId = musicInfoMap[key]; var user = db.UserData.First();
Console.ResetColor(); var musicInfoMap = musicInfo.Items.DistinctBy(entry => entry.Id)
Console.ForegroundColor = ConsoleColor.Cyan; .ToDictionary(entry => entry.Id, entry => entry.SongId);
Console.WriteLine($"Importing song with id: {songId}"); foreach (var playRecord in playRecordJson)
Console.WriteLine($"Song play time: {playRecord.DateTime}"); {
Console.ResetColor(); var key = playRecord.SongId.Split("_")[1];
var playLog = new SongPlayDatum if (!musicInfoMap.ContainsKey(key))
{ {
Baid = user.Baid, Console.ResetColor();
Difficulty = playRecord.Difficulty, Console.ForegroundColor = ConsoleColor.Yellow;
Crown = playRecord.Crown, Console.WriteLine($"Key {key} does not exist!!!");
Score = playRecord.Score, Console.ResetColor();
ScoreRank = playRecord.Scorerank, continue;
ComboCount = playRecord.Combo, }
DrumrollCount = playRecord.Drumroll, var songId = musicInfoMap[key];
PlayTime = playRecord.DateTime, Console.ResetColor();
GoodCount = playRecord.Good, Console.ForegroundColor = ConsoleColor.Cyan;
MissCount = playRecord.Bad, Console.WriteLine($"Importing song with id: {songId}");
OkCount = playRecord.Ok, Console.WriteLine($"Song play time: {playRecord.DateTime}");
Skipped = false, Console.ResetColor();
SongNumber = 0, var playLog = new SongPlayDatum
SongId = songId {
}; Baid = user.Baid,
db.SongPlayData.Add(playLog); Difficulty = playRecord.Difficulty,
Crown = playRecord.Crown,
Score = playRecord.Score,
ScoreRank = playRecord.Scorerank,
ComboCount = playRecord.Combo,
DrumrollCount = playRecord.Drumroll,
PlayTime = playRecord.DateTime,
GoodCount = playRecord.Good,
MissCount = playRecord.Bad,
OkCount = playRecord.Ok,
Skipped = false,
SongNumber = 0,
SongId = songId
};
db.SongPlayData.Add(playLog);
var best = new SongBestDatum var best = new SongBestDatum
{ {
Baid = user.Baid, Baid = user.Baid,
Difficulty = playRecord.Difficulty, Difficulty = playRecord.Difficulty,
BestCrown = playRecord.Crown, BestCrown = playRecord.Crown,
BestScore = playRecord.Score, BestScore = playRecord.Score,
BestScoreRank = playRecord.Scorerank, BestScoreRank = playRecord.Scorerank,
SongId = songId SongId = songId
}; };
var existing = db.SongBestData.FirstOrDefault(datum => datum.Baid == user.Baid && var existing = db.SongBestData.FirstOrDefault(datum => datum.Baid == user.Baid &&
datum.Difficulty == playLog.Difficulty && datum.Difficulty == playLog.Difficulty &&
datum.SongId == songId); datum.SongId == songId);
if (existing is null) if (existing is null)
{ {
db.SongBestData.Add(best); db.SongBestData.Add(best);
} }
else else
{ {
existing.BestCrown = (CrownType)Math.Max((int)existing.BestCrown, (int)playRecord.Crown); existing.BestCrown = (CrownType)Math.Max((int)existing.BestCrown, (int)playRecord.Crown);
existing.BestScoreRank = (ScoreRank)Math.Max((int)existing.BestScoreRank, (int)playRecord.Scorerank); existing.BestScoreRank = (ScoreRank)Math.Max((int)existing.BestScoreRank, (int)playRecord.Scorerank);
existing.BestScore = Math.Max(existing.BestScore, playRecord.Score); existing.BestScore = Math.Max(existing.BestScore, playRecord.Score);
db.SongBestData.Update(existing); db.SongBestData.Update(existing);
} }
} }
db.SaveChanges(); db.SaveChanges();
} }

View File

@ -4,6 +4,6 @@ public enum PlayMode
{ {
Normal = 0, Normal = 0,
DanMode = 1, DanMode = 1,
// Not sure about this GaidenMode = 4,
AiBattle = 6 AiBattle = 6
} }

View File

@ -8,6 +8,6 @@ public enum SongGenre
Vocaloid = 3, Vocaloid = 3,
GameMusic = 4, GameMusic = 4,
NamcoOriginal = 5, NamcoOriginal = 5,
Variety = 7, Variety = 6,
Classical = 8 Classical = 7
} }

View File

@ -4,15 +4,18 @@ namespace SharedProject.Models;
public class EventFolderData public class EventFolderData
{ {
[JsonPropertyName("folderId")] [JsonPropertyName("folderId")]
public uint FolderId { get; set; } public uint FolderId { get; set; }
[JsonPropertyName("verupNo")] [JsonPropertyName("verupNo")]
public uint VerupNo { get; set; } public uint VerupNo { get; set; }
[JsonPropertyName("priority")] [JsonPropertyName("priority")]
public uint Priority { get; set; } public uint Priority { get; set; }
[JsonPropertyName("songNo")] [JsonPropertyName("songNo")]
public uint[]? SongNo { get; set; } public uint[]? SongNo { get; set; }
[JsonPropertyName("parentFolderId")]
public uint ParentFolderId { get; set; }
} }

View File

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace SharedProject.Models;
public class MovieData
{
[JsonPropertyName("movie_id")]
public uint MovieId { get; set; }
[JsonPropertyName("enable_days")]
public uint EnableDays { get; set; }
}

View File

@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
namespace SharedProject.Models;
public class QRCodeData
{
[JsonPropertyName("serial")] public string Serial { get; set; } = null!;
[JsonPropertyName("id")] public uint Id { get; set; }
}

View File

@ -2,7 +2,7 @@
public class SetFavoriteRequest public class SetFavoriteRequest
{ {
public uint Baid { get; set; } public ulong Baid { get; set; }
public uint SongId { get; set; } public uint SongId { get; set; }
public bool IsFavorite { get; set; } public bool IsFavorite { get; set; }
} }

View File

@ -0,0 +1,8 @@
namespace SharedProject.Models.Requests;
public class SetPasswordRequest
{
public string AccessCode { get; set; } = default!;
public string Password { get; set; } = default!;
public string Salt { get; set; } = default!;
}

View File

@ -0,0 +1,10 @@
using System.Text.Json.Serialization;
namespace SharedProject.Models;
public class ShopFolderData
{
[JsonPropertyName("songNo")] public uint SongNo { get; set; }
[JsonPropertyName("price")] public uint Price { get; set; }
}

View File

@ -3,6 +3,10 @@
public class User public class User
{ {
public string AccessCode { get; set; } = string.Empty; public string AccessCode { get; set; } = string.Empty;
public uint Baid { get; set; } public uint Baid { get; set; }
public string Password { get; set; } = string.Empty;
public string Salt { get; set; } = string.Empty;
} }

View File

@ -7,49 +7,57 @@ public class UserSetting
public uint ToneId { get; set; } public uint ToneId { get; set; }
public bool IsDisplayAchievement { get; set; } public bool IsDisplayAchievement { get; set; }
public bool IsDisplayDanOnNamePlate { get; set; } public bool IsDisplayDanOnNamePlate { get; set; }
public uint DifficultySettingCourse { get; set; }
public uint DifficultySettingStar { get; set; }
public uint DifficultySettingSort { get; set; }
public bool IsVoiceOn { get; set; } public bool IsVoiceOn { get; set; }
public bool IsSkipOn { get; set; } public bool IsSkipOn { get; set; }
public Difficulty AchievementDisplayDifficulty { get; set; } public Difficulty AchievementDisplayDifficulty { get; set; }
public PlaySetting PlaySetting { get; set; } = new(); public PlaySetting PlaySetting { get; set; } = new();
public int NotesPosition { get; set; } public int NotesPosition { get; set; }
public string MyDonName { get; set; } = string.Empty; public string MyDonName { get; set; } = string.Empty;
public uint MyDonNameLanguage { get; set; }
public string Title { get; set; } = string.Empty; public string Title { get; set; } = string.Empty;
public uint TitlePlateId { get; set; } public uint TitlePlateId { get; set; }
public uint Kigurumi { get; set; } public uint Kigurumi { get; set; }
public uint Head { get; set; } public uint Head { get; set; }
public uint Body { get; set; } public uint Body { get; set; }
public uint Face { get; set; } public uint Face { get; set; }
public uint Puchi { get; set; } public uint Puchi { get; set; }
public List<uint> UnlockedKigurumi { get; set; } = new(); public List<uint> UnlockedKigurumi { get; set; } = new();
public List<uint> UnlockedHead { get; set; } = new(); public List<uint> UnlockedHead { get; set; } = new();
public List<uint> UnlockedBody { get; set; } = new(); public List<uint> UnlockedBody { get; set; } = new();
public List<uint> UnlockedFace { get; set; } = new(); public List<uint> UnlockedFace { get; set; } = new();
public List<uint> UnlockedPuchi { get; set; } = new(); public List<uint> UnlockedPuchi { get; set; } = new();
public uint FaceColor { get; set; } public uint FaceColor { get; set; }
public uint BodyColor { get; set; } public uint BodyColor { get; set; }
public uint LimbColor { get; set; } public uint LimbColor { get; set; }
} }

View File

@ -1,9 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<LangVersion>11</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@ -1 +1,3 @@
wwwroot/data/music_attribute.json wwwroot/data/music_order.json
wwwroot/data/musicinfo.json
wwwroot/data/wordlist.json

View File

@ -2,44 +2,18 @@
public static class Constants public static class Constants
{ {
public const string DATE_TIME_FORMAT = "yyyyMMddHHmmss"; public const string DATE_TIME_FORMAT = "yyyyMMddHHmmss";
public const int MUSIC_ID_MAX = 1599; public const int MUSIC_ID_MAX = 1599;
public const int MUSIC_ID_MAX_EXPANDED = 9000; public const int MUSIC_ID_MAX_EXPANDED = 9000;
public const string DEFAULT_DB_NAME = "taiko.db3"; public const string DEFAULT_DB_NAME = "taiko.db3";
public const string MUSIC_ATTRIBUTE_FILE_NAME = "music_attribute.json"; public const string MUSIC_INFO_BASE_NAME = "musicinfo";
public const string MUSIC_ATTRIBUTE_COMPRESSED_FILE_NAME = "music_attribute.bin"; public const string WORDLIST_BASE_NAME = "wordlist";
public const string MUSIC_ORDER_BASE_NAME = "music_order";
public const string DAN_DATA_FILE_NAME = "dan_data.json"; public const string DON_COS_REWARD_BASE_NAME = "don_cos_reward";
public const string INTRO_DATA_FILE_NAME = "intro_data.json"; public const string SHOUGOU_BASE_NAME = "shougou";
public const string EVENT_FOLDER_DATA_FILE_NAME = "event_folder_data.json"; public const string NEIRO_BASE_NAME = "neiro";
public static readonly int[] EVENT_FOLDER_IDS = {
1, 2, 3, 4, 5, 6, 7, 8, 12, 13, 14
};
public const int MIN_DAN_ID = 1;
public const int MAX_DAN_ID = 19;
public const int TONE_UID_MAX = 19;
public const int TITLE_UID_MAX = 814;
private const int COSTUME_FLAG_1_ARRAY_SIZE = 154;
private const int COSTUME_FLAG_2_ARRAY_SIZE = 140;
private const int COSTUME_FLAG_3_ARRAY_SIZE = 156;
private const int COSTUME_FLAG_4_ARRAY_SIZE = 58;
private const int COSTUME_FLAG_5_ARRAY_SIZE = 129;
public static readonly int[] CostumeFlagArraySizes =
{
COSTUME_FLAG_1_ARRAY_SIZE,
COSTUME_FLAG_2_ARRAY_SIZE,
COSTUME_FLAG_3_ARRAY_SIZE,
COSTUME_FLAG_4_ARRAY_SIZE,
COSTUME_FLAG_5_ARRAY_SIZE
};
} }

View File

@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using System.Collections.Immutable;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using GameDatabase.Entities; using GameDatabase.Entities;
@ -70,7 +71,7 @@ public static class FlagCalculator
return (ushort)(previous | result); return (ushort)(previous | result);
} }
public static byte[] ComputeGotDanFlags(List<DanScoreDatum> danScoreData) public static byte[] ComputeGotDanFlags(List<DanScoreDatum> danScoreData, List<uint> danIdList)
{ {
var gotDanFlagList = new List<int>(); var gotDanFlagList = new List<int>();
var gotDanFlag = new BitVector32(); var gotDanFlag = new BitVector32();
@ -84,10 +85,9 @@ public static class FlagCalculator
var section8 = BitVector32.CreateSection(8, section7); var section8 = BitVector32.CreateSection(8, section7);
var sections = new[] { section1, section2, section3, section4, section5, section6, section7, section8 }; var sections = new[] { section1, section2, section3, section4, section5, section6, section7, section8 };
for (var i = Constants.MIN_DAN_ID; i < Constants.MAX_DAN_ID; i++) foreach (var danId in danIdList)
{ {
var danId = i;
var flag = 0; var flag = 0;
if (danScoreData.Any(datum => datum.DanId == danId)) if (danScoreData.Any(datum => datum.DanId == danId))
{ {
@ -126,4 +126,22 @@ public static class FlagCalculator
return result; return result;
} }
public static byte[] GetBitArrayTrue(int bitArraySize)
{
var result = new byte[(bitArraySize / 8) + 1];
var bitSet = new BitArray(bitArraySize, true);
bitSet.CopyTo(result, 0);
return result;
}
public static byte[] GetBitArrayFalse(int bitArraySize)
{
var result = new byte[(bitArraySize / 8) + 1];
var bitSet = new BitArray(bitArraySize, false);
bitSet.CopyTo(result, 0);
return result;
}
} }

View File

@ -1,15 +1,39 @@
using System.Text.Json; using GameDatabase.Entities;
using GameDatabase.Entities; using System.Text.Json;
namespace TaikoLocalServer.Common.Utils; namespace TaikoLocalServer.Common.Utils;
public static class JsonHelper public static class JsonHelper
{ {
public static uint[] GetUIntArrayFromJson(string data, int length, ILogger logger, string fieldName)
{
var array = new uint[length];
try
{
array = JsonSerializer.Deserialize<uint[]>(data);
}
catch (JsonException e)
{
logger.LogError(e, "Parsing {FieldName} json data failed", fieldName);
}
if (array != null && array.Length >= length)
{
return array;
}
logger.LogWarning($"{fieldName} is null or length less than {length}!");
array = new uint[length];
return array;
}
public static List<uint> GetCostumeDataFromUserData(UserDatum userData, ILogger logger) public static List<uint> GetCostumeDataFromUserData(UserDatum userData, ILogger logger)
{ {
var costumeData = new List<uint> { 0, 0, 0, 0, 0 }; var costumeData = new List<uint> { 0, 0, 0, 0, 0 };
try try
{ {
// logger.LogInformation(userData.CostumeData);
costumeData = JsonSerializer.Deserialize<List<uint>>(userData.CostumeData); costumeData = JsonSerializer.Deserialize<List<uint>>(userData.CostumeData);
} }
catch (JsonException e) catch (JsonException e)
@ -21,13 +45,13 @@ public static class JsonHelper
{ {
return costumeData; return costumeData;
} }
logger.LogWarning("Costume data is null or count less than 5!"); logger.LogWarning("Costume data is null or count less than 5!");
costumeData = new List<uint> { 0, 0, 0, 0, 0 }; costumeData = new List<uint> { 0, 0, 0, 0, 0 };
return costumeData; return costumeData;
} }
public static List<List<uint>> GetCostumeUnlockDataFromUserData(UserDatum userData, ILogger logger) public static List<List<uint>> GetCostumeUnlockDataFromUserData(UserDatum userData, ILogger logger)
{ {
var costumeUnlockData = new List<List<uint>> { new(), new(), new(), new(), new() }; var costumeUnlockData = new List<List<uint>> { new(), new(), new(), new(), new() };
@ -44,7 +68,7 @@ public static class JsonHelper
{ {
return costumeUnlockData; return costumeUnlockData;
} }
logger.LogWarning("Costume unlock data is null or count less than 5!"); logger.LogWarning("Costume unlock data is null or count less than 5!");
costumeUnlockData = new List<List<uint>> { new(), new(), new(), new(), new() }; costumeUnlockData = new List<List<uint>> { new(), new(), new(), new(), new() };

View File

@ -4,17 +4,8 @@
"BaseServer": { "BaseServer": {
"Url": "http://0.0.0.0:5000" "Url": "http://0.0.0.0:5000"
}, },
"AmAuthServer": {
"Url": "http://0.0.0.0:80"
},
"MuchaServer": {
"Url": "https://0.0.0.0:10122"
},
"GameServer1": { "GameServer1": {
"Url": "https://0.0.0.0:54430" "Url": "https://0.0.0.0:57402"
},
"GameServer2": {
"Url": "https://0.0.0.0:54431"
} }
}, },
"Certificates": { "Certificates": {

View File

@ -2,6 +2,6 @@
"ServerSettings": { "ServerSettings": {
"MuchaUrl": "https://v402-front.mucha-prd.nbgi-amnet.jp:10122", "MuchaUrl": "https://v402-front.mucha-prd.nbgi-amnet.jp:10122",
"GameUrl": "vsapi.taiko-p.jp", "GameUrl": "vsapi.taiko-p.jp",
"EnableMoreSongs": true "EnableMoreSongs": false
} }
} }

View File

@ -1,4 +1,6 @@
namespace TaikoLocalServer.Controllers.Api; using SharedProject.Models.Requests;
namespace TaikoLocalServer.Controllers.Api;
[ApiController] [ApiController]
[Route("api/[controller]")] [Route("api/[controller]")]
@ -19,4 +21,13 @@ public class CardsController : BaseController<CardsController>
return result ? NoContent() : NotFound(); return result ? NoContent() : NotFound();
} }
[HttpPost]
public async Task<IActionResult> UpdatePassword(SetPasswordRequest request)
{
var accessCode = request.AccessCode;
var password = request.Password;
var salt = request.Salt;
var result = await cardService.UpdatePassword(accessCode, password, salt);
return result ? NoContent() : NotFound();
}
} }

View File

@ -15,7 +15,7 @@ public class DanBestDataController : BaseController<DanBestDataController>
} }
[HttpGet("{baid}")] [HttpGet("{baid}")]
public async Task<IActionResult> GetDanBestData(uint baid) public async Task<IActionResult> GetDanBestData(ulong baid)
{ {
var danScores = await danScoreDatumService.GetDanScoreDatumByBaid(baid); var danScores = await danScoreDatumService.GetDanScoreDatumByBaid(baid);
var danDataList = new List<DanBestData>(); var danDataList = new List<DanBestData>();

View File

@ -21,7 +21,7 @@ public class PlayDataController : BaseController<PlayDataController>
} }
[HttpGet("{baid}")] [HttpGet("{baid}")]
public async Task<ActionResult<SongBestResponse>> GetSongBestRecords(uint baid) public async Task<ActionResult<SongBestResponse>> GetSongBestRecords(ulong baid)
{ {
var user = await userDatumService.GetFirstUserDatumOrNull(baid); var user = await userDatumService.GetFirstUserDatumOrNull(baid);
if (user is null) if (user is null)

View File

@ -1,6 +1,6 @@
using System.Text.Json; using SharedProject.Models;
using SharedProject.Models;
using SharedProject.Utils; using SharedProject.Utils;
using System.Text.Json;
namespace TaikoLocalServer.Controllers.Api; namespace TaikoLocalServer.Controllers.Api;
@ -16,7 +16,7 @@ public class UserSettingsController : BaseController<UserSettingsController>
} }
[HttpGet] [HttpGet]
public async Task<ActionResult<UserSetting>> GetUserSetting(uint baid) public async Task<ActionResult<UserSetting>> GetUserSetting(ulong baid)
{ {
var user = await userDatumService.GetFirstUserDatumOrNull(baid); var user = await userDatumService.GetFirstUserDatumOrNull(baid);
@ -25,6 +25,8 @@ public class UserSettingsController : BaseController<UserSettingsController>
return NotFound(); return NotFound();
} }
var difficultySettingArray = JsonHelper.GetUIntArrayFromJson(user.DifficultySettingArray, 3, Logger, nameof(user.DifficultySettingArray));
var costumeData = JsonHelper.GetCostumeDataFromUserData(user, Logger); var costumeData = JsonHelper.GetCostumeDataFromUserData(user, Logger);
var costumeUnlockData = JsonHelper.GetCostumeUnlockDataFromUserData(user, Logger); var costumeUnlockData = JsonHelper.GetCostumeUnlockDataFromUserData(user, Logger);
@ -34,12 +36,16 @@ public class UserSettingsController : BaseController<UserSettingsController>
AchievementDisplayDifficulty = user.AchievementDisplayDifficulty, AchievementDisplayDifficulty = user.AchievementDisplayDifficulty,
IsDisplayAchievement = user.DisplayAchievement, IsDisplayAchievement = user.DisplayAchievement,
IsDisplayDanOnNamePlate = user.DisplayDan, IsDisplayDanOnNamePlate = user.DisplayDan,
DifficultySettingCourse = difficultySettingArray[0],
DifficultySettingStar = difficultySettingArray[1],
DifficultySettingSort = difficultySettingArray[2],
IsVoiceOn = user.IsVoiceOn, IsVoiceOn = user.IsVoiceOn,
IsSkipOn = user.IsSkipOn, IsSkipOn = user.IsSkipOn,
NotesPosition = user.NotesPosition, NotesPosition = user.NotesPosition,
PlaySetting = PlaySettingConverter.ShortToPlaySetting(user.OptionSetting), PlaySetting = PlaySettingConverter.ShortToPlaySetting(user.OptionSetting),
ToneId = user.SelectedToneId, ToneId = user.SelectedToneId,
MyDonName = user.MyDonName, MyDonName = user.MyDonName,
MyDonNameLanguage = user.MyDonNameLanguage,
Title = user.Title, Title = user.Title,
TitlePlateId = user.TitlePlateId, TitlePlateId = user.TitlePlateId,
Kigurumi = costumeData[0], Kigurumi = costumeData[0],
@ -48,9 +54,9 @@ public class UserSettingsController : BaseController<UserSettingsController>
Face = costumeData[3], Face = costumeData[3],
Puchi = costumeData[4], Puchi = costumeData[4],
UnlockedKigurumi = costumeUnlockData[0], UnlockedKigurumi = costumeUnlockData[0],
UnlockedHead = costumeUnlockData[1], UnlockedHead = costumeUnlockData[1],
UnlockedBody = costumeUnlockData[2], UnlockedBody = costumeUnlockData[2],
UnlockedFace = costumeUnlockData[3], UnlockedFace = costumeUnlockData[3],
UnlockedPuchi = costumeUnlockData[4], UnlockedPuchi = costumeUnlockData[4],
BodyColor = user.ColorBody, BodyColor = user.ColorBody,
FaceColor = user.ColorFace, FaceColor = user.ColorFace,
@ -60,7 +66,7 @@ public class UserSettingsController : BaseController<UserSettingsController>
} }
[HttpPost] [HttpPost]
public async Task<IActionResult> SaveUserSetting(uint baid, UserSetting userSetting) public async Task<IActionResult> SaveUserSetting(ulong baid, UserSetting userSetting)
{ {
var user = await userDatumService.GetFirstUserDatumOrNull(baid); var user = await userDatumService.GetFirstUserDatumOrNull(baid);
@ -77,23 +83,31 @@ public class UserSettingsController : BaseController<UserSettingsController>
userSetting.Face, userSetting.Face,
userSetting.Puchi, userSetting.Puchi,
}; };
var difficultySettings = new List<uint>
{
userSetting.DifficultySettingCourse,
userSetting.DifficultySettingStar,
userSetting.DifficultySettingSort
};
user.IsSkipOn = userSetting.IsSkipOn; user.IsSkipOn = userSetting.IsSkipOn;
user.IsVoiceOn = userSetting.IsVoiceOn; user.IsVoiceOn = userSetting.IsVoiceOn;
user.DisplayAchievement = userSetting.IsDisplayAchievement; user.DisplayAchievement = userSetting.IsDisplayAchievement;
user.DisplayDan = userSetting.IsDisplayDanOnNamePlate; user.DisplayDan = userSetting.IsDisplayDanOnNamePlate;
user.DifficultySettingArray = JsonSerializer.Serialize(difficultySettings);
user.NotesPosition = userSetting.NotesPosition; user.NotesPosition = userSetting.NotesPosition;
user.SelectedToneId = userSetting.ToneId; user.SelectedToneId = userSetting.ToneId;
user.AchievementDisplayDifficulty = userSetting.AchievementDisplayDifficulty; user.AchievementDisplayDifficulty = userSetting.AchievementDisplayDifficulty;
user.OptionSetting = PlaySettingConverter.PlaySettingToShort(userSetting.PlaySetting); user.OptionSetting = PlaySettingConverter.PlaySettingToShort(userSetting.PlaySetting);
user.MyDonName = userSetting.MyDonName; user.MyDonName = userSetting.MyDonName;
user.MyDonNameLanguage = userSetting.MyDonNameLanguage;
user.Title = userSetting.Title; user.Title = userSetting.Title;
user.TitlePlateId = userSetting.TitlePlateId; user.TitlePlateId = userSetting.TitlePlateId;
user.ColorBody = userSetting.BodyColor; user.ColorBody = userSetting.BodyColor;
user.ColorFace = userSetting.FaceColor; user.ColorFace = userSetting.FaceColor;
user.ColorLimb = userSetting.LimbColor; user.ColorLimb = userSetting.LimbColor;
user.CostumeData = JsonSerializer.Serialize(costumes); user.CostumeData = JsonSerializer.Serialize(costumes);
await userDatumService.UpdateUserDatum(user); await userDatumService.UpdateUserDatum(user);

View File

@ -1,15 +1,56 @@
namespace TaikoLocalServer.Controllers.Game; using System.Text.Json;
using Throw;
[Route("/v12r03/chassis/addtokencount.php")] namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r00_cn/chassis/addtokencount.php")]
[ApiController] [ApiController]
public class AddTokenCountController : BaseController<AddTokenCountController> public class AddTokenCountController : BaseController<AddTokenCountController>
{ {
private readonly IUserDatumService userDatumService;
public AddTokenCountController(IUserDatumService userDatumService)
{
this.userDatumService = userDatumService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult AddTokenCount([FromBody] AddTokenCountRequest request) public async Task<IActionResult> AddTokenCount([FromBody] AddTokenCountRequest request)
{ {
Logger.LogInformation("AddTokenCount request : {Request}", request.Stringify()); Logger.LogInformation("AddTokenCount request : {Request}", request.Stringify());
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
var tokenCountDict = new Dictionary<uint, int>();
try
{
tokenCountDict = !string.IsNullOrEmpty(user.TokenCountDict)
? JsonSerializer.Deserialize<Dictionary<uint, int>>(user.TokenCountDict)
: new Dictionary<uint, int>();
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing TokenCountDict data for user with baid {Request} failed!", request.Baid);
}
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");
foreach (var addTokenCountData in request.AryAddTokenCountDatas)
{
var tokenId = addTokenCountData.TokenId;
var addTokenCount = addTokenCountData.AddTokenCount;
if (tokenCountDict.ContainsKey(tokenId))
tokenCountDict[tokenId] += addTokenCount;
else
tokenCountDict.Add(tokenId, addTokenCount);
}
user.TokenCountDict = JsonSerializer.Serialize(tokenCountDict);
await userDatumService.UpdateUserDatum(user);
var response = new AddTokenCountResponse var response = new AddTokenCountResponse
{ {
Result = 1 Result = 1

View File

@ -1,206 +1,200 @@
using System.Text.Json; using GameDatabase.Entities;
using GameDatabase.Entities; using System.Text.Json;
using Serilog;
using Throw; using Throw;
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[ApiController] [ApiController]
[Route("/v12r03/chassis/baidcheck.php")] [Route("/v12r00_cn/chassis/baidcheck.php")]
public class BaidController : BaseController<BaidController> public class BaidController : BaseController<BaidController>
{ {
private readonly IUserDatumService userDatumService; private readonly IUserDatumService userDatumService;
private readonly ICardService cardService; private readonly ICardService cardService;
private readonly ISongBestDatumService songBestDatumService; private readonly ISongBestDatumService songBestDatumService;
private readonly IDanScoreDatumService danScoreDatumService; private readonly IDanScoreDatumService danScoreDatumService;
private readonly IAiDatumService aiDatumService; private readonly IAiDatumService aiDatumService;
private readonly IGameDataService gameDataService;
public BaidController(IUserDatumService userDatumService, ICardService cardService, public BaidController(IUserDatumService userDatumService, ICardService cardService,
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService) ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService,
{ IGameDataService gameDataService)
this.userDatumService = userDatumService; {
this.cardService = cardService; this.userDatumService = userDatumService;
this.songBestDatumService = songBestDatumService; this.cardService = cardService;
this.danScoreDatumService = danScoreDatumService; this.songBestDatumService = songBestDatumService;
this.aiDatumService = aiDatumService; this.danScoreDatumService = danScoreDatumService;
} this.aiDatumService = aiDatumService;
this.gameDataService = gameDataService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public async Task<IActionResult> GetBaid([FromBody] BAIDRequest request) public async Task<IActionResult> GetBaid([FromBody] BAIDRequest request)
{ {
Logger.LogInformation("Baid request: {Request}", request.Stringify()); Logger.LogInformation("Baid request: {Request}", request.Stringify());
BAIDResponse response; BAIDResponse response;
var card = await cardService.GetCardByAccessCode(request.AccessCode); var card = await cardService.GetCardByAccessCode(request.WechatQrStr);
if (card is null) if (card is null)
{ {
Logger.LogInformation("New user with access code {AccessCode}", request.AccessCode); Logger.LogInformation("New user with access code {AccessCode}", request.WechatQrStr);
var newId = cardService.GetNextBaid(); var newId = cardService.GetNextBaid();
response = new BAIDResponse response = new BAIDResponse
{ {
Result = 1, Result = 1,
PlayerType = 1, PlayerType = 1,
ComSvrResult = 1, Baid = newId,
MbId = 1, };
Baid = newId,
AccessCode = request.AccessCode,
IsPublish = true,
CardOwnNum = 1,
RegCountryId = "JPN",
PurposeId = 1,
RegionId = 1
};
return Ok(response); return Ok(response);
} }
var baid = card.Baid; var baid = card.Baid;
var userData = await userDatumService.GetFirstUserDatumOrDefault(baid); var userData = await userDatumService.GetFirstUserDatumOrDefault(baid);
var songBestData = await songBestDatumService.GetAllSongBestData(baid); var songBestData = await songBestDatumService.GetAllSongBestData(baid);
var achievementDisplayDifficulty = userData.AchievementDisplayDifficulty;
if (userData.AchievementDisplayDifficulty == Difficulty.None)
{
achievementDisplayDifficulty = songBestData.Any(datum => datum.BestCrown >= CrownType.Clear) ?
songBestData.Where(datum => datum.BestCrown >= CrownType.Clear).Max(datum => datum.Difficulty) :
Difficulty.Easy;
}
var songCountData = songBestData.Where(datum => achievementDisplayDifficulty != Difficulty.UraOni ? var achievementDisplayDifficulty = userData.AchievementDisplayDifficulty;
datum.Difficulty == achievementDisplayDifficulty : if (userData.AchievementDisplayDifficulty == Difficulty.None)
datum.Difficulty is Difficulty.Oni or Difficulty.UraOni).ToList(); {
achievementDisplayDifficulty = songBestData.Any(datum => datum.BestCrown >= CrownType.Clear) ?
songBestData.Where(datum => datum.BestCrown >= CrownType.Clear).Max(datum => datum.Difficulty) :
Difficulty.Easy;
}
var crownCount = CalculateCrownCount(songCountData); var songCountData = songBestData.Where(datum => achievementDisplayDifficulty != Difficulty.UraOni ?
datum.Difficulty == achievementDisplayDifficulty :
datum.Difficulty is Difficulty.Oni or Difficulty.UraOni).ToList();
var scoreRankCount = CalculateScoreRankCount(songCountData); var crownCount = CalculateCrownCount(songCountData);
var scoreRankCount = CalculateScoreRankCount(songCountData);
var costumeData = JsonHelper.GetCostumeDataFromUserData(userData, Logger); var costumeData = JsonHelper.GetCostumeDataFromUserData(userData, Logger);
var costumeArrays = JsonHelper.GetCostumeUnlockDataFromUserData(userData, Logger); var costumeArrays = JsonHelper.GetCostumeUnlockDataFromUserData(userData, Logger);
var costumeFlagArrays = Constants.CostumeFlagArraySizes var costumeFlagArrays = gameDataService.GetCostumeFlagArraySizes()
.Select((size, index) => FlagCalculator.GetBitArrayFromIds(costumeArrays[index], size, Logger)) .Select((size, index) => FlagCalculator.GetBitArrayFromIds(costumeArrays[index], size, Logger))
.ToList(); .ToList();
var danData = await danScoreDatumService.GetDanScoreDatumByBaid(baid); var danData = await danScoreDatumService.GetDanScoreDatumByBaid(baid);
var maxDan = danData.Where(datum => datum.ClearState != DanClearState.NotClear)
.Select(datum => datum.DanId)
.DefaultIfEmpty()
.Max();
var gotDanFlagArray = FlagCalculator.ComputeGotDanFlags(danData);
var genericInfoFlg = Array.Empty<uint>(); var maxDan = danData.Where(datum => datum.ClearState != DanClearState.NotClear)
try .Select(datum => datum.DanId)
{ .DefaultIfEmpty()
genericInfoFlg = JsonSerializer.Deserialize<uint[]>(userData.GenericInfoFlgArray); .Max();
}
catch (JsonException e) var danDataDictionary = gameDataService.GetDanDataDictionary();
{ var danIdList = danDataDictionary.Keys.ToList();
Logger.LogError(e, "Parsing genericinfo flg json data failed"); var gotDanFlagArray = FlagCalculator.ComputeGotDanFlags(danData, danIdList);
}
var gaidenDataDictionary = gameDataService.GetGaidenDataDictionary();
var gaidenIdList = gaidenDataDictionary.Keys.ToList();
danIdList.AddRange(gaidenIdList);
var gotGaidenFlagArray = FlagCalculator.ComputeGotDanFlags(danData, danIdList);
// The only way to get a null is provide string "null" as input, var genericInfoFlg = Array.Empty<uint>();
// which means database content need to be fixed, so better throw try
genericInfoFlg.ThrowIfNull("Genericinfo flg should never be null!"); {
genericInfoFlg = JsonSerializer.Deserialize<uint[]>(userData.GenericInfoFlgArray);
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing genericinfo flg json data failed");
}
var genericInfoFlgLength = genericInfoFlg.Any()? genericInfoFlg.Max() + 1 : 0; // The only way to get a null is provide string "null" as input,
var genericInfoFlgArray = FlagCalculator.GetBitArrayFromIds(genericInfoFlg, (int)genericInfoFlgLength, Logger); // which means database content need to be fixed, so better throw
genericInfoFlg.ThrowIfNull("Genericinfo flg should never be null!");
var aiRank = (uint)(userData.AiWinCount / 10); var genericInfoFlgLength = genericInfoFlg.Any() ? genericInfoFlg.Max() + 1 : 0;
if (aiRank > 11) var genericInfoFlgArray = FlagCalculator.GetBitArrayFromIds(genericInfoFlg, (int)genericInfoFlgLength, Logger);
{
aiRank = 11;
}
response = new BAIDResponse
{
Result = 1,
PlayerType = 0,
ComSvrResult = 1,
MbId = 1,
Baid = baid,
AccessCode = request.AccessCode,
IsPublish = true,
CardOwnNum = 1,
RegCountryId = "JPN",
PurposeId = 1,
RegionId = 1,
MydonName = userData.MyDonName,
Title = userData.Title,
TitleplateId = userData.TitlePlateId,
ColorFace = userData.ColorFace,
ColorBody = userData.ColorBody,
ColorLimb = userData.ColorLimb,
AryCostumedata = new BAIDResponse.CostumeData
{
Costume1 = costumeData[0],
Costume2 = costumeData[1],
Costume3 = costumeData[2],
Costume4 = costumeData[3],
Costume5 = costumeData[4]
},
CostumeFlg1 = costumeFlagArrays[0],
CostumeFlg2 = costumeFlagArrays[1],
CostumeFlg3 = costumeFlagArrays[2],
CostumeFlg4 = costumeFlagArrays[3],
CostumeFlg5 = costumeFlagArrays[4],
LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DATE_TIME_FORMAT),
IsDispDanOn = userData.DisplayDan,
GotDanMax = maxDan,
GotDanFlg = gotDanFlagArray,
GotDanextraFlg = new byte[20],
DefaultToneSetting = userData.SelectedToneId,
GenericInfoFlg = genericInfoFlgArray,
AryCrownCounts = crownCount,
AryScoreRankCounts = scoreRankCount,
IsDispAchievementOn = userData.DisplayAchievement,
DispAchievementType = (uint)achievementDisplayDifficulty,
IsDispAchievementTypeSet = true,
LastPlayMode = userData.LastPlayMode,
IsDispSouuchiOn = true,
AiRank = aiRank,
AiTotalWin = (uint)userData.AiWinCount,
Accesstoken = "123456",
ContentInfo = GZipBytesUtil.GetGZipBytes(new byte[10])
};
return Ok(response); var aiRank = (uint)(userData.AiWinCount / 10);
} if (aiRank > 11)
{
aiRank = 11;
}
response = new BAIDResponse
{
Result = 1,
PlayerType = 0,
Baid = baid,
MydonName = userData.MyDonName,
MydonNameLanguage = userData.MyDonNameLanguage,
Title = userData.Title,
TitleplateId = userData.TitlePlateId,
ColorFace = userData.ColorFace,
ColorBody = userData.ColorBody,
ColorLimb = userData.ColorLimb,
AryCostumedata = new BAIDResponse.CostumeData
{
Costume1 = costumeData[0],
Costume2 = costumeData[1],
Costume3 = costumeData[2],
Costume4 = costumeData[3],
Costume5 = costumeData[4]
},
CostumeFlg1 = costumeFlagArrays[0],
CostumeFlg2 = costumeFlagArrays[1],
CostumeFlg3 = costumeFlagArrays[2],
CostumeFlg4 = costumeFlagArrays[3],
CostumeFlg5 = costumeFlagArrays[4],
LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DATE_TIME_FORMAT),
IsDispDanOn = userData.DisplayDan,
GotDanMax = maxDan,
GotDanFlg = gotDanFlagArray,
GotDanextraFlg = gotGaidenFlagArray,
DefaultToneSetting = userData.SelectedToneId,
GenericInfoFlg = genericInfoFlgArray,
AryCrownCounts = crownCount,
AryScoreRankCounts = scoreRankCount,
IsDispAchievementOn = userData.DisplayAchievement,
DispAchievementType = (uint)achievementDisplayDifficulty,
IsDispAchievementTypeSet = true,
LastPlayMode = userData.LastPlayMode,
IsDispSouuchiOn = true
};
private static uint[] CalculateScoreRankCount(IReadOnlyCollection<SongBestDatum> songCountData) return Ok(response);
{ }
var scoreRankCount = new uint[7];
foreach (var scoreRankType in Enum.GetValues<ScoreRank>())
{
if (scoreRankType != ScoreRank.None)
{
scoreRankCount[(int)scoreRankType - 2] =
(uint)songCountData.Count(datum => datum.BestScoreRank == scoreRankType);
}
}
return scoreRankCount; private static uint[] CalculateScoreRankCount(IReadOnlyCollection<SongBestDatum> songCountData)
} {
var scoreRankCount = new uint[7];
foreach (var scoreRankType in Enum.GetValues<ScoreRank>())
{
if (scoreRankType != ScoreRank.None)
{
scoreRankCount[(int)scoreRankType - 2] =
(uint)songCountData.Count(datum => datum.BestScoreRank == scoreRankType);
}
}
private static uint[] CalculateCrownCount(IReadOnlyCollection<SongBestDatum> songCountData) return scoreRankCount;
{ }
var crownCount = new uint[3];
foreach (var crownType in Enum.GetValues<CrownType>())
{
if (crownType != CrownType.None)
{
crownCount[(int)crownType - 1] = (uint)songCountData.Count(datum => datum.BestCrown == crownType);
}
}
return crownCount; private static uint[] CalculateCrownCount(IReadOnlyCollection<SongBestDatum> songCountData)
} {
var crownCount = new uint[3];
foreach (var crownType in Enum.GetValues<CrownType>())
{
if (crownType != CrownType.None)
{
crownCount[(int)crownType - 1] = (uint)songCountData.Count(datum => datum.BestCrown == crownType);
}
}
return crownCount;
}
} }

View File

@ -1,7 +1,7 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[ApiController] [ApiController]
[Route("/v12r03/chassis/bookkeeping.php")] [Route("/v12r00_cn/chassis/bookkeeping.php")]
public class BookkeepingController : BaseController<BookkeepingController> public class BookkeepingController : BaseController<BookkeepingController>
{ {
[HttpPost] [HttpPost]

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/challengecompe.php")] [Route("/v12r00_cn/chassis/challengecompe.php")]
[ApiController] [ApiController]
public class ChallengeCompetitionController : BaseController<ChallengeCompetitionController> public class ChallengeCompetitionController : BaseController<ChallengeCompetitionController>
{ {

View File

@ -3,7 +3,7 @@ using TaikoLocalServer.Settings;
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/crownsdata.php")] [Route("/v12r00_cn/chassis/crownsdata.php")]
[ApiController] [ApiController]
public class CrownsDataController : BaseController<CrownsDataController> public class CrownsDataController : BaseController<CrownsDataController>
{ {

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/executeqrcode.php")] [Route("/v12r00_cn/chassis/executeqrcode.php")]
[ApiController] [ApiController]
public class ExecuteQrCodeController : BaseController<ExecuteQrCodeController> public class ExecuteQrCodeController : BaseController<ExecuteQrCodeController>
{ {

View File

@ -2,7 +2,7 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getaidata.php")] [Route("/v12r00_cn/chassis/getaidata.php")]
[ApiController] [ApiController]
public class GetAiDataController : BaseController<GetAiDataController> public class GetAiDataController : BaseController<GetAiDataController>
{ {

View File

@ -2,7 +2,7 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getaiscore.php")] [Route("/v12r00_cn/chassis/getaiscore.php")]
[ApiController] [ApiController]
public class GetAiScoreController : BaseController<GetAiScoreController> public class GetAiScoreController : BaseController<GetAiScoreController>
{ {

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getapplicationurl.php")] [Route("/v12r00_cn/chassis/getapplicationurl.php")]
[ApiController] [ApiController]
public class GetApplicationUrlController : BaseController<GetApplicationUrlController> public class GetApplicationUrlController : BaseController<GetApplicationUrlController>
{ {

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getdanodai.php")] [Route("/v12r00_cn/chassis/getdanodai.php")]
[ApiController] [ApiController]
public class GetDanOdaiController : BaseController<GetDanOdaiController> public class GetDanOdaiController : BaseController<GetDanOdaiController>
{ {
@ -16,29 +16,41 @@ public class GetDanOdaiController : BaseController<GetDanOdaiController>
public IActionResult GetDanOdai([FromBody] GetDanOdaiRequest request) public IActionResult GetDanOdai([FromBody] GetDanOdaiRequest request)
{ {
Logger.LogInformation("GetDanOdai request : {Request}", request.Stringify()); Logger.LogInformation("GetDanOdai request : {Request}", request.Stringify());
var response = new GetDanOdaiResponse var response = new GetDanOdaiResponse
{ {
Result = 1 Result = 1
}; };
if (request.Type == 2) if (request.Type == 1)
{ {
return Ok(response); foreach (var danId in request.DanIds)
{
gameDataService.GetDanDataDictionary().TryGetValue(danId, out var odaiData);
if (odaiData is null)
{
Logger.LogWarning("Requested dan id {Id} does not exist!", danId);
continue;
}
response.AryOdaiDatas.Add(odaiData);
}
}
else if (request.Type == 2)
{
foreach (var danId in request.DanIds)
{
gameDataService.GetGaidenDataDictionary().TryGetValue(danId, out var odaiData);
if (odaiData is null)
{
Logger.LogWarning("Requested dan id {Id} does not exist!", danId);
continue;
}
response.AryOdaiDatas.Add(odaiData);
}
} }
foreach (var danId in request.DanIds)
{
gameDataService.GetDanDataDictionary().TryGetValue(danId, out var odaiData);
if (odaiData is null)
{
Logger.LogWarning("Requested dan id {Id} does not exist!", danId);
continue;
}
response.AryOdaiDatas.Add(odaiData);
}
return Ok(response); return Ok(response);
} }
} }

View File

@ -2,7 +2,7 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getdanscore.php")] [Route("/v12r00_cn/chassis/getdanscore.php")]
[ApiController] [ApiController]
public class GetDanScoreController : BaseController<GetDanScoreController> public class GetDanScoreController : BaseController<GetDanScoreController>
{ {

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getfolder.php")] [Route("/v12r00_cn/chassis/getfolder.php")]
[ApiController] [ApiController]
public class GetFolderController : BaseController<GetFolderController> public class GetFolderController : BaseController<GetFolderController>
{ {

View File

@ -0,0 +1,24 @@
namespace TaikoLocalServer.Controllers.Game;
[ApiController]
[Route("/v12r00_cn/chassis/getgenericmaster.php")]
public class GetGenericMasterController : BaseController<GetGenericMasterController>
{
[HttpPost]
[Produces("application/protobuf")]
public IActionResult GetGenericMaster([FromBody] GetGenericMasterRequest request)
{
Logger.LogInformation("GetGenericMasterRequest: {Request}", request.Stringify());
var response = new GetGenericMasterResponse
{
Result = 1,
VerupNo = 2,
EnableIdBit = FlagCalculator.GetBitArrayTrue(5000)
};
return Ok(response);
}
}

View File

@ -3,7 +3,7 @@ using TaikoLocalServer.Settings;
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getscorerank.php")] [Route("/v12r00_cn/chassis/getscorerank.php")]
[ApiController] [ApiController]
public class GetScoreRankController : BaseController<GetScoreRankController> public class GetScoreRankController : BaseController<GetScoreRankController>
{ {

View File

@ -1,27 +1,34 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getshopfolder.php")] [Route("/v12r00_cn/chassis/getshopfolder.php")]
[ApiController] [ApiController]
public class GetShopFolderController : BaseController<GetShopFolderController> public class GetShopFolderController : BaseController<GetShopFolderController>
{ {
private readonly IGameDataService gameDataService;
public GetShopFolderController(IGameDataService gameDataService)
{
this.gameDataService = gameDataService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult GetShopFolder([FromBody] GetShopFolderRequest request) public IActionResult GetShopFolder([FromBody] GetShopFolderRequest request)
{ {
Logger.LogInformation("GetShopFolder request : {Request}", request.Stringify()); Logger.LogInformation("GetShopFolder request : {Request}", request.Stringify());
gameDataService.GetTokenDataDictionary().TryGetValue("shopTokenId", out var shopTokenId);
var shopFolderList = gameDataService.GetShopFolderList();
var response = new GetShopFolderResponse var response = new GetShopFolderResponse
{ {
Result = 1, Result = 1,
TokenId = 1, TokenId = shopTokenId > 0 ? (uint)shopTokenId : 1,
VerupNo = 2 VerupNo = 2
}; };
response.AryShopFolderDatas.Add(new GetShopFolderResponse.ShopFolderData response.AryShopFolderDatas.AddRange(shopFolderList);
{
Price = 1,
SongNo = 2
});
return Ok(response); return Ok(response);
} }

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getsongintroduction.php")] [Route("/v12r00_cn/chassis/getsongintroduction.php")]
[ApiController] [ApiController]
public class GetSongIntroductionController : BaseController<GetSongIntroductionController> public class GetSongIntroductionController : BaseController<GetSongIntroductionController>
{ {

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/gettelop.php")] [Route("/v12r00_cn/chassis/gettelop.php")]
[ApiController] [ApiController]
public class GetTelopController : BaseController<GetTelopController> public class GetTelopController : BaseController<GetTelopController>
{ {

View File

@ -1,26 +1,102 @@
namespace TaikoLocalServer.Controllers.Game; using System.Text.Json;
using Throw;
[Route("/v12r03/chassis/gettokencount.php")] namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r00_cn/chassis/gettokencount.php")]
[ApiController] [ApiController]
public class GetTokenCountController : BaseController<GetTokenCountController> public class GetTokenCountController : BaseController<GetTokenCountController>
{ {
private readonly IGameDataService gameDataService;
private readonly IUserDatumService userDatumService;
public GetTokenCountController(IUserDatumService userDatumService, IGameDataService gameDataService)
{
this.userDatumService = userDatumService;
this.gameDataService = gameDataService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult GetTokenCount([FromBody] GetTokenCountRequest request) public async Task<IActionResult> GetTokenCount([FromBody] GetTokenCountRequest request)
{ {
Logger.LogInformation("GetTokenCount request : {Request}", request.Stringify()); Logger.LogInformation("GetTokenCount request : {Request}", request.Stringify());
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
var tokenDataDictionary = gameDataService.GetTokenDataDictionary();
tokenDataDictionary.TryGetValue("shopTokenId", out var shopTokenId);
tokenDataDictionary.TryGetValue("kaTokenId", out var kaTokenId);
tokenDataDictionary.TryGetValue("onePieceTokenId", out var onePieceTokenId);
tokenDataDictionary.TryGetValue("soshinaTokenId", out var soshinaTokenId);
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
var tokenCountDict = new Dictionary<uint, int>();
try
{
tokenCountDict = !string.IsNullOrEmpty(user.TokenCountDict)
? JsonSerializer.Deserialize<Dictionary<uint, int>>(user.TokenCountDict)
: new Dictionary<uint, int>();
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing TokenCountDict data for user with baid {Request} failed!", request.Baid);
}
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");
var response = new GetTokenCountResponse var response = new GetTokenCountResponse
{ {
Result = 1 Result = 1
}; };
response.AryTokenCountDatas.Add(new GetTokenCountResponse.TokenCountData if (tokenCountDict.Count == 0) tokenCountDict.Add(1, 0);
if (shopTokenId > 0)
{ {
TokenCount = 10, var castedShopTokenId = (uint)shopTokenId;
TokenId = 1 tokenCountDict.TryAdd(castedShopTokenId, 0);
}); response.AryTokenCountDatas.Add(new GetTokenCountResponse.TokenCountData
{
TokenCount = tokenCountDict[castedShopTokenId],
TokenId = castedShopTokenId
});
}
if (kaTokenId > 0)
{
var castedKaTokenId = (uint)kaTokenId;
tokenCountDict.TryAdd(castedKaTokenId, 0);
response.AryTokenCountDatas.Add(new GetTokenCountResponse.TokenCountData
{
TokenCount = tokenCountDict[castedKaTokenId],
TokenId = castedKaTokenId
});
}
if (onePieceTokenId > 0)
{
var castedOnePieceTokenId = (uint)onePieceTokenId;
tokenCountDict.TryAdd(castedOnePieceTokenId, 0);
response.AryTokenCountDatas.Add(new GetTokenCountResponse.TokenCountData
{
TokenCount = tokenCountDict[castedOnePieceTokenId],
TokenId = castedOnePieceTokenId
});
}
if (soshinaTokenId > 0)
{
var castedSoshinaTokenId = (uint)soshinaTokenId;
tokenCountDict.TryAdd(castedSoshinaTokenId, 0);
response.AryTokenCountDatas.Add(new GetTokenCountResponse.TokenCountData
{
TokenCount = tokenCountDict[castedSoshinaTokenId],
TokenId = castedSoshinaTokenId
});
}
user.TokenCountDict = JsonSerializer.Serialize(tokenCountDict);
await userDatumService.UpdateUserDatum(user);
return Ok(response); return Ok(response);
} }
} }

View File

@ -0,0 +1,39 @@
namespace TaikoLocalServer.Controllers.Game;
[ApiController]
[Route("/v12r00_cn/chassis/headclerk2.php")]
public class Headclerk2Controller : BaseController<Headclerk2Controller>
{
[HttpPost]
[Produces("application/protobuf")]
public IActionResult Headclerk2([FromBody] HeadClerk2Request request)
{
Logger.LogInformation("Headclerk2 request: {Request}", request.Stringify());
var chassisId = request.ChassisId;
var shopId = request.ShopId;
foreach (var playInfo in request.AryPlayInfoes)
{
var baid = playInfo.Baid;
var playedAt = playInfo.PlayedAt;
var isRight = playInfo.IsRight;
var type = playInfo.Type;
var amount = playInfo.Amount;
Logger.LogInformation("CSV WRITE: \n" +
"ChassisId:{ChassisId},\n" +
"ShopId:{ShopId},\n" +
"Baid:{Baid},\n" +
"PlayedAt{PlayedAt},\n" +
"IsRight:{IsRight},\n" +
"Type:{Type},\n" +
"Amount{Amount}", chassisId, shopId, baid, playedAt, isRight, type, amount);
}
var response = new HeadClerk2Response
{
Result = 1
};
return Ok(response);
}
}

View File

@ -1,21 +1,20 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[ApiController] [ApiController]
[Route("/v12r03/chassis/heartbeat.php")] [Route("/v12r00_cn/chassis/heartbeat.php")]
public class HeartbeatController : BaseController<HeartbeatController> public class HeartbeatController : BaseController<HeartbeatController>
{ {
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult HeartBeat([FromBody] HeartBeatRequest request) public IActionResult HeartBeat([FromBody] HeartBeatRequest request)
{ {
Logger.LogInformation("Heartbeat request: {Request}", request.Stringify()); Logger.LogInformation("Heartbeat request: {Request}", request.Stringify());
var response = new HeartBeatResponse var response = new HeartBeatResponse
{ {
Result = 1, Result = 1,
ComSvrStat = 1, GameSvrStat = 1
GameSvrStat = 1 };
};
return Ok(response); return Ok(response);
} }
} }

View File

@ -4,114 +4,138 @@ using TaikoLocalServer.Settings;
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[ApiController] [ApiController]
[Route("/v12r03/chassis/initialdatacheck.php")] [Route("/v12r00_cn/chassis/initialdatacheck.php")]
public class InitialDataCheckController : BaseController<InitialDataCheckController> public class InitialDataCheckController : BaseController<InitialDataCheckController>
{ {
private readonly IGameDataService gameDataService; private readonly IGameDataService gameDataService;
private readonly ServerSettings settings; private readonly ServerSettings settings;
public InitialDataCheckController(IGameDataService gameDataService, IOptions<ServerSettings> settings) public InitialDataCheckController(IGameDataService gameDataService, IOptions<ServerSettings> settings)
{ {
this.gameDataService = gameDataService; this.gameDataService = gameDataService;
this.settings = settings.Value; this.settings = settings.Value;
} }
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult InitialDataCheck([FromBody] InitialdatacheckRequest request) public IActionResult InitialDataCheck([FromBody] InitialdatacheckRequest request)
{ {
Logger.LogInformation("Initial data check request: {Request}", request.Stringify()); Logger.LogInformation("Initial data check request: {Request}", request.Stringify());
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX; var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
var enabledArray =
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicList(), songIdMax, Logger);
var danData = new List<InitialdatacheckResponse.InformationData>(); var musicList = gameDataService.GetMusicList();
for (var danId = Constants.MIN_DAN_ID; danId <= Constants.MAX_DAN_ID; danId++) var lockedSongsList = gameDataService.GetLockedSongsList();
{
danData.Add(new InitialdatacheckResponse.InformationData
{
InfoId = (uint)danId,
VerupNo = 1
});
}
var introData = new List<InitialdatacheckResponse.InformationData>();
for (var setId = 1; setId <= gameDataService.GetSongIntroDictionary().Count; setId++)
{
introData.Add(new InitialdatacheckResponse.InformationData
{
InfoId = (uint)setId,
VerupNo = 1
});
}
var eventFolderData = new List<InitialdatacheckResponse.InformationData>(); var enabledArray =
foreach (var folderId in Constants.EVENT_FOLDER_IDS) FlagCalculator.GetBitArrayFromIds(musicList, songIdMax, Logger);
{
eventFolderData.Add(new InitialdatacheckResponse.InformationData
{
InfoId = (uint)folderId,
VerupNo = 0
});
}
var response = new InitialdatacheckResponse var defaultSongList = musicList.Except(lockedSongsList);
{ var defaultSongFlg =
Result = 1, FlagCalculator.GetBitArrayFromIds(defaultSongList, songIdMax, Logger);
IsDanplay = true,
IsAibattle = true, var defaultSongWithUraList = gameDataService.GetMusicWithUraList();
IsClose = false, var uraReleaseBit =
DefaultSongFlg = enabledArray, FlagCalculator.GetBitArrayFromIds(defaultSongWithUraList, songIdMax, Logger);
AchievementSongBit = enabledArray,
SongIntroductionEndDatetime = DateTime.Now.AddYears(10).ToString(Constants.DATE_TIME_FORMAT), var response = new InitialdatacheckResponse
AryShopFolderDatas = {
{ Result = 1,
new InitialdatacheckResponse.InformationData DefaultSongFlg = defaultSongFlg,
{ AchievementSongBit = enabledArray,
InfoId = 1, UraReleaseBit = uraReleaseBit,
VerupNo = 2 SongIntroductionEndDatetime = DateTime.Now.AddYears(10).ToString(Constants.DATE_TIME_FORMAT),
} };
},
/*AryTelopDatas = var movieDataDictionary = gameDataService.GetMovieDataDictionary();
{ foreach (var movieData in movieDataDictionary) response.AryMovieInfoes.Add(movieData.Value);
new InitialdatacheckResponse.InformationData
{ var verupNo1 = new uint[] { 2, 3, 4, 5, 6, 7, 8, 13, 15, 24, 25, 26, 27, 28, 29, 30, 31, 104 };
InfoId = 1, var aryVerUp = verupNo1.Select(i => new InitialdatacheckResponse.VerupNoData1
VerupNo = 1 {
} MasterType = i,
}, VerupNo = 1
AryDanextraOdaiDatas = })
{ .ToList();
new InitialdatacheckResponse.InformationData response.AryVerupNoData1s.AddRange(aryVerUp);
{
InfoId = 1, var danData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
VerupNo = 1 var danDataDictionary = gameDataService.GetDanDataDictionary();
} foreach (var danId in danDataDictionary.Keys)
}, {
AryAiEventDatas = gameDataService.GetDanDataDictionary().TryGetValue(danId, out var odaiData);
{ danData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
new InitialdatacheckResponse.AiEventData {
{ InfoId = danId,
AiEventId = 1, VerupNo = odaiData?.VerupNo ?? 1
TokenId = 1 });
} }
}, var verUp2Type101 = new InitialdatacheckResponse.VerupNoData2
AryMovieInfos = {
{ MasterType = 101,
new InitialdatacheckResponse.MovieData };
{ verUp2Type101.AryInformationDatas.AddRange(danData);
MovieId = 2, response.AryVerupNoData2s.Add(verUp2Type101);
EnableDays = 9999
} var gaidenData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
}*/ var gaidenDataDictionary = gameDataService.GetGaidenDataDictionary();
}; foreach (var gaidenId in gaidenDataDictionary.Keys)
{
response.AryDanOdaiDatas.AddRange(danData); gaidenDataDictionary.TryGetValue(gaidenId, out var odaiData);
response.ArySongIntroductionDatas.AddRange(introData); gaidenData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
response.AryEventfolderDatas.AddRange(eventFolderData); {
return Ok(response); InfoId = gaidenId,
} VerupNo = odaiData?.VerupNo ?? 1
});
}
var verUp2Type102 = new InitialdatacheckResponse.VerupNoData2
{
MasterType = 102,
};
verUp2Type102.AryInformationDatas.AddRange(gaidenData);
response.AryVerupNoData2s.Add(verUp2Type102);
var eventFolderData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
var eventFolderDictionary = gameDataService.GetFolderDictionary();
foreach (var folderId in eventFolderDictionary.Keys)
{
eventFolderDictionary.TryGetValue(folderId, out var folderData);
eventFolderData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
{
InfoId = folderId,
VerupNo = folderData?.VerupNo ?? 1
});
}
var verUp2Type103 = new InitialdatacheckResponse.VerupNoData2
{
MasterType = 103,
};
verUp2Type103.AryInformationDatas.AddRange(eventFolderData);
response.AryVerupNoData2s.Add(verUp2Type103);
var songIntroData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
var songIntroDictionary = gameDataService.GetSongIntroDictionary();
foreach (var setId in songIntroDictionary.Select(item => item.Value.SetId))
{
songIntroDictionary.TryGetValue(setId, out var introData);
songIntroData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
{
InfoId = setId,
VerupNo = introData?.VerupNo ?? 1
});
}
var verUp2Type105 = new InitialdatacheckResponse.VerupNoData2
{
MasterType = 105,
};
verUp2Type105.AryInformationDatas.AddRange(songIntroData);
response.AryVerupNoData2s.Add(verUp2Type105);
response.AryChassisFunctionIds = new uint[] { 1, 2, 3 };
return Ok(response);
}
} }

View File

@ -2,68 +2,65 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/mydonentry.php")] [Route("/v12r00_cn/chassis/mydonentry.php")]
[ApiController] [ApiController]
public class MyDonEntryController : BaseController<MyDonEntryController> public class MyDonEntryController : BaseController<MyDonEntryController>
{ {
private readonly IUserDatumService userDatumService; private readonly IUserDatumService userDatumService;
private readonly ICardService cardService; private readonly ICardService cardService;
public MyDonEntryController(IUserDatumService userDatumService, ICardService cardService)
{
this.userDatumService = userDatumService;
this.cardService = cardService;
}
[HttpPost] public MyDonEntryController(IUserDatumService userDatumService, ICardService cardService)
[Produces("application/protobuf")] {
public async Task<IActionResult> GetMyDonEntry([FromBody] MydonEntryRequest request) this.userDatumService = userDatumService;
{ this.cardService = cardService;
Logger.LogInformation("MyDonEntry request : {Request}", request.Stringify()); }
var newId = cardService.GetNextBaid(); [HttpPost]
await cardService.AddCard(new Card [Produces("application/protobuf")]
{ public async Task<IActionResult> GetMyDonEntry([FromBody] MydonEntryRequest request)
AccessCode = request.AccessCode, {
Baid = newId Logger.LogInformation("MyDonEntry request : {Request}", request.Stringify());
});
var newUser = new UserDatum var newId = cardService.GetNextBaid();
{ await cardService.AddCard(new Card
Baid = newId, {
MyDonName = request.MydonName, AccessCode = request.WechatQrStr,
DisplayDan = true, Baid = newId,
DisplayAchievement = true, Password = "",
AchievementDisplayDifficulty = Difficulty.None, Salt = ""
ColorFace = 0, });
ColorBody = 1,
ColorLimb = 3,
FavoriteSongsArray = "[]",
ToneFlgArray = "[]",
TitleFlgArray = "[]",
CostumeFlgArray = "[[],[],[],[],[]]",
GenericInfoFlgArray = "[]"
};
await userDatumService.InsertUserDatum(newUser); var newUser = new UserDatum
{
Baid = newId,
MyDonName = request.MydonName,
MyDonNameLanguage = 0,
DisplayDan = true,
DisplayAchievement = true,
AchievementDisplayDifficulty = Difficulty.None,
ColorFace = 0,
ColorBody = 1,
ColorLimb = 3,
FavoriteSongsArray = "[]",
ToneFlgArray = "[0]",
TitleFlgArray = "[]",
CostumeFlgArray = "[[],[],[],[],[]]",
GenericInfoFlgArray = "[]",
TokenCountDict = "{}",
UnlockedSongIdList = "[]"
};
var response = new MydonEntryResponse await userDatumService.InsertUserDatum(newUser);
{
Result = 1,
ComSvrResult = 1,
AccessCode = request.AccessCode,
Accesstoken = "12345",
Baid = newId,
MbId = 1,
MydonName = request.MydonName,
CardOwnNum = 1,
IsPublish = true,
RegCountryId = request.CountryId,
PurposeId = 1,
RegionId = 1
};
return Ok(response); var response = new MydonEntryResponse
} {
Result = 1,
Baid = newId,
MydonName = request.MydonName,
MydonNameLanguage = 0
};
return Ok(response);
}
} }

View File

@ -8,7 +8,7 @@ namespace TaikoLocalServer.Controllers.Game;
using StageData = PlayResultDataRequest.StageData; using StageData = PlayResultDataRequest.StageData;
[Route("/v12r03/chassis/playresult.php")] [Route("/v12r00_cn/chassis/playresult.php")]
[ApiController] [ApiController]
public class PlayResultController : BaseController<PlayResultController> public class PlayResultController : BaseController<PlayResultController>
{ {
@ -21,15 +21,19 @@ public class PlayResultController : BaseController<PlayResultController>
private readonly IDanScoreDatumService danScoreDatumService; private readonly IDanScoreDatumService danScoreDatumService;
private readonly IAiDatumService aiDatumService; private readonly IAiDatumService aiDatumService;
private readonly IGameDataService gameDataService;
public PlayResultController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService, public PlayResultController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService,
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService) ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService,
IGameDataService gameDataService)
{ {
this.userDatumService = userDatumService; this.userDatumService = userDatumService;
this.songPlayDatumService = songPlayDatumService; this.songPlayDatumService = songPlayDatumService;
this.songBestDatumService = songBestDatumService; this.songBestDatumService = songBestDatumService;
this.danScoreDatumService = danScoreDatumService; this.danScoreDatumService = danScoreDatumService;
this.aiDatumService = aiDatumService; this.aiDatumService = aiDatumService;
this.gameDataService = gameDataService;
} }
[HttpPost] [HttpPost]
@ -67,17 +71,32 @@ public class PlayResultController : BaseController<PlayResultController>
var playMode = (PlayMode)playResultData.PlayMode; var playMode = (PlayMode)playResultData.PlayMode;
if (playMode == PlayMode.DanMode) if (playMode is PlayMode.DanMode or PlayMode.GaidenMode)
{ {
await UpdateDanPlayData(request, playResultData); await UpdateDanPlayData(request, playResultData);
return Ok(response); return Ok(response);
} }
var bestData = await songBestDatumService.GetAllSongBestData(request.BaidConf); var bestData = await songBestDatumService.GetAllSongBestData(request.BaidConf);
gameDataService.GetFolderDictionary().TryGetValue(9, out var folder9Data);
var folder9Songs = new List<uint>();
if (folder9Data is not null)
{
folder9Songs.AddRange(folder9Data.SongNoes);
}
for (var songNumber = 0; songNumber < playResultData.AryStageInfoes.Count; songNumber++) for (var songNumber = 0; songNumber < playResultData.AryStageInfoes.Count; songNumber++)
{ {
var stageData = playResultData.AryStageInfoes[songNumber]; var stageData = playResultData.AryStageInfoes[songNumber];
if (folder9Songs.Contains(stageData.SongNo))
{
continue;
}
if (stageData.IsSkipUse) if (stageData.IsSkipUse)
{ {
await UpdatePlayData(request, songNumber, stageData, lastPlayDatetime); await UpdatePlayData(request, songNumber, stageData, lastPlayDatetime);
@ -203,16 +222,17 @@ public class PlayResultController : BaseController<PlayResultController>
}; };
userdata.CostumeData = JsonSerializer.Serialize(costumeData); 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 // Skip user setting saving when in dan mode as dan mode uses its own default setting
if (playMode != PlayMode.DanMode) // if (playMode != PlayMode.DanMode)
{ // {
var lastStage = playResultData.AryStageInfoes.Last(); // var lastStage = playResultData.AryStageInfoes.Last();
var option = BinaryPrimitives.ReadInt16LittleEndian(lastStage.OptionFlg); // var option = BinaryPrimitives.ReadInt16LittleEndian(lastStage.OptionFlg);
userdata.OptionSetting = option; // userdata.OptionSetting = option;
userdata.IsSkipOn = lastStage.IsSkipOn; // userdata.IsSkipOn = lastStage.IsSkipOn;
userdata.IsVoiceOn = !lastStage.IsVoiceOn; // userdata.IsVoiceOn = !lastStage.IsVoiceOn;
userdata.NotesPosition = lastStage.NotesPosition; // userdata.NotesPosition = lastStage.NotesPosition;
} // }
userdata.LastPlayDatetime = lastPlayDatetime; userdata.LastPlayDatetime = lastPlayDatetime;
userdata.LastPlayMode = playResultData.PlayMode; userdata.LastPlayMode = playResultData.PlayMode;
@ -236,6 +256,14 @@ public class PlayResultController : BaseController<PlayResultController>
userdata.GenericInfoFlgArray = userdata.GenericInfoFlgArray =
UpdateJsonUintFlagArray(userdata.GenericInfoFlgArray, playResultData.GetGenericInfoNoes, nameof(userdata.GenericInfoFlgArray)); UpdateJsonUintFlagArray(userdata.GenericInfoFlgArray, playResultData.GetGenericInfoNoes, nameof(userdata.GenericInfoFlgArray));
var difficultyPlayedArray = new List<uint>
{
playResultData.DifficultyPlayedCourse,
playResultData.DifficultyPlayedStar,
playResultData.DifficultyPlayedSort
};
userdata.DifficultyPlayedArray = JsonSerializer.Serialize(difficultyPlayedArray);
userdata.AiWinCount += playResultData.AryStageInfoes.Count(data => data.IsWin); userdata.AiWinCount += playResultData.AryStageInfoes.Count(data => data.IsWin);
await userDatumService.UpdateUserDatum(userdata); await userDatumService.UpdateUserDatum(userdata);
} }

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/rewarditem.php")] [Route("/v12r00_cn/chassis/rewarditem.php")]
[ApiController] [ApiController]
public class RewardItemController : BaseController<RewardItemController> public class RewardItemController : BaseController<RewardItemController>
{ {

View File

@ -3,7 +3,7 @@ using Throw;
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/selfbest.php")] [Route("/v12r00_cn/chassis/selfbest.php")]
[ApiController] [ApiController]
public class SelfBestController : BaseController<SelfBestController> public class SelfBestController : BaseController<SelfBestController>
{ {
@ -39,7 +39,7 @@ public class SelfBestController : BaseController<SelfBestController>
.ToList(); .ToList();
foreach (var songNo in request.ArySongNoes) foreach (var songNo in request.ArySongNoes)
{ {
if (!gameDataService.GetMusicAttributes().ContainsKey(songNo)) if (!gameDataService.GetMusicList().Contains(songNo))
{ {
Logger.LogWarning("Music no {No} is missing!", songNo); Logger.LogWarning("Music no {No} is missing!", songNo);
continue; continue;

View File

@ -0,0 +1,20 @@
namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r00_cn/chassis/setanystring.php")]
[ApiController]
public class SetAnyStringController : BaseController<SetAnyStringController>
{
[HttpPost]
[Produces("application/protobuf")]
public IActionResult SetAnyString([FromBody] SetAnyStringRequest request)
{
Logger.LogInformation("SetAnyString request : {Request}", request.Stringify());
var response = new SetAnyStringResponse
{
Result = 1,
};
return Ok(response);
}
}

View File

@ -1,19 +1,73 @@
namespace TaikoLocalServer.Controllers.Game; using System.Text.Json;
using Throw;
[Route("/v12r03/chassis/songpurchase.php")] namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r00_cn/chassis/songpurchase.php")]
[ApiController] [ApiController]
public class SongPurchaseController : BaseController<SongPurchaseController> public class SongPurchaseController : BaseController<SongPurchaseController>
{ {
private readonly IUserDatumService userDatumService;
public SongPurchaseController(IUserDatumService userDatumService)
{
this.userDatumService = userDatumService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult SongPurchase([FromBody] SongPurchaseRequest request) public async Task<IActionResult> SongPurchase([FromBody] SongPurchaseRequest request)
{ {
Logger.LogInformation("SongPurchase request : {Request}", request.Stringify()); Logger.LogInformation("SongPurchase request : {Request}", request.Stringify());
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
var tokenCountDict = new Dictionary<uint, int>();
try
{
tokenCountDict = !string.IsNullOrEmpty(user.TokenCountDict)
? JsonSerializer.Deserialize<Dictionary<uint, int>>(user.TokenCountDict)
: new Dictionary<uint, int>();
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing TokenCountDict data for user with baid {Request} failed!", request.Baid);
}
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");
Logger.LogInformation("Original UnlockedSongIdList: {UnlockedSongIdList}", user.UnlockedSongIdList);
var unlockedSongIdList = new List<uint>();
try
{
unlockedSongIdList = !string.IsNullOrEmpty(user.UnlockedSongIdList)
? JsonSerializer.Deserialize<List<uint>>(user.UnlockedSongIdList)
: new List<uint>();
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing UnlockedSongIdList data for user with baid {Request} failed!", request.Baid);
}
unlockedSongIdList.ThrowIfNull("UnlockedSongIdList should never be null");
if (tokenCountDict.ContainsKey(request.TokenId)) tokenCountDict[request.TokenId] -= (int)request.Price;
if (!unlockedSongIdList.Contains(request.SongNo)) unlockedSongIdList.Add(request.SongNo);
user.TokenCountDict = JsonSerializer.Serialize(tokenCountDict);
user.UnlockedSongIdList = JsonSerializer.Serialize(unlockedSongIdList);
Logger.LogInformation("Updated UnlockedSongIdList: {UnlockedSongIdList}", user.UnlockedSongIdList);
await userDatumService.UpdateUserDatum(user);
var response = new SongPurchaseResponse var response = new SongPurchaseResponse
{ {
Result = 1, Result = 1,
TokenCount = (int)(10 - request.Price) TokenCount = tokenCountDict[request.TokenId]
}; };
return Ok(response); return Ok(response);

View File

@ -1,6 +1,6 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/tournamentcheck.php")] [Route("/v12r00_cn/chassis/tournamentcheck.php")]
[ApiController] [ApiController]
public class TournamentCheckController : BaseController<TournamentCheckController> public class TournamentCheckController : BaseController<TournamentCheckController>
{ {

View File

@ -1,12 +1,12 @@
using System.Buffers.Binary; using Microsoft.Extensions.Options;
using System.Buffers.Binary;
using System.Text.Json; using System.Text.Json;
using Microsoft.Extensions.Options;
using TaikoLocalServer.Settings; using TaikoLocalServer.Settings;
using Throw; using Throw;
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/userdata.php")] [Route("/v12r00_cn/chassis/userdata.php")]
[ApiController] [ApiController]
public class UserDataController : BaseController<UserDataController> public class UserDataController : BaseController<UserDataController>
{ {
@ -17,8 +17,8 @@ public class UserDataController : BaseController<UserDataController>
private readonly IGameDataService gameDataService; private readonly IGameDataService gameDataService;
private readonly ServerSettings settings; private readonly ServerSettings settings;
public UserDataController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService, public UserDataController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService,
IGameDataService gameDataService, IOptions<ServerSettings> settings) IGameDataService gameDataService, IOptions<ServerSettings> settings)
{ {
this.userDatumService = userDatumService; this.userDatumService = userDatumService;
@ -34,13 +34,34 @@ public class UserDataController : BaseController<UserDataController>
Logger.LogInformation("UserData request : {Request}", request.Stringify()); Logger.LogInformation("UserData request : {Request}", request.Stringify());
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX; var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
var releaseSongArray =
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicList(), songIdMax, Logger);
var uraSongArray =
FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicWithUraList(), songIdMax, Logger);
var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid); var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid);
var unlockedSongIdList = new List<uint>();
try
{
unlockedSongIdList = !string.IsNullOrEmpty(userData.UnlockedSongIdList)
? JsonSerializer.Deserialize<List<uint>>(userData.UnlockedSongIdList)
: new List<uint>();
}
catch (JsonException e)
{
Logger.LogError(e, "Parsing UnlockedSongIdList data for user with baid {Request} failed!", request.Baid);
}
unlockedSongIdList.ThrowIfNull("UnlockedSongIdList should never be null");
var musicList = gameDataService.GetMusicList();
var lockedSongsList = gameDataService.GetLockedSongsList();
lockedSongsList = lockedSongsList.Except(unlockedSongIdList).ToList();
var enabledMusicList = musicList.Except(lockedSongsList);
var releaseSongArray =
FlagCalculator.GetBitArrayFromIds(enabledMusicList, songIdMax, Logger);
var defaultSongWithUraList = gameDataService.GetMusicWithUraList();
var enabledUraMusicList = defaultSongWithUraList.Except(lockedSongsList);
var uraSongArray =
FlagCalculator.GetBitArrayFromIds(enabledUraMusicList, songIdMax, Logger);
var toneFlg = Array.Empty<uint>(); var toneFlg = Array.Empty<uint>();
try try
@ -55,8 +76,16 @@ public class UserDataController : BaseController<UserDataController>
// The only way to get a null is provide string "null" as input, // The only way to get a null is provide string "null" as input,
// which means database content need to be fixed, so better throw // which means database content need to be fixed, so better throw
toneFlg.ThrowIfNull("Tone flg should never be null!"); toneFlg.ThrowIfNull("Tone flg should never be null!");
// If toneFlg is empty, add 0 to it
if (toneFlg.Length == 0)
{
toneFlg = new uint[] { 0 };
userData.ToneFlgArray = JsonSerializer.Serialize(toneFlg);
await userDatumService.UpdateUserDatum(userData);
}
var toneArray = FlagCalculator.GetBitArrayFromIds(toneFlg, Constants.TONE_UID_MAX, Logger); var toneArray = FlagCalculator.GetBitArrayFromIds(toneFlg, gameDataService.GetToneFlagArraySize(), Logger);
var titleFlg = Array.Empty<uint>(); var titleFlg = Array.Empty<uint>();
try try
@ -72,7 +101,7 @@ public class UserDataController : BaseController<UserDataController>
// which means database content need to be fixed, so better throw // which means database content need to be fixed, so better throw
titleFlg.ThrowIfNull("Title flg should never be null!"); titleFlg.ThrowIfNull("Title flg should never be null!");
var titleArray = FlagCalculator.GetBitArrayFromIds(titleFlg, Constants.TITLE_UID_MAX, Logger); var titleArray = FlagCalculator.GetBitArrayFromIds(titleFlg, gameDataService.GetTitleFlagArraySize(), Logger);
var recentSongs = (await songPlayDatumService.GetSongPlayDatumByBaid(request.Baid)) var recentSongs = (await songPlayDatumService.GetSongPlayDatumByBaid(request.Baid))
.AsEnumerable() .AsEnumerable()
@ -80,7 +109,7 @@ public class UserDataController : BaseController<UserDataController>
.ThenByDescending(datum => datum.SongNumber) .ThenByDescending(datum => datum.SongNumber)
.Select(datum => datum.SongId) .Select(datum => datum.SongId)
.ToArray(); .ToArray();
// Use custom implementation as distinctby cannot guarantee preserved element // Use custom implementation as distinctby cannot guarantee preserved element
var recentSet = new OrderedSet<uint>(); var recentSet = new OrderedSet<uint>();
foreach (var id in recentSongs) foreach (var id in recentSongs)
@ -110,7 +139,18 @@ public class UserDataController : BaseController<UserDataController>
var defaultOptions = new byte[2]; var defaultOptions = new byte[2];
BinaryPrimitives.WriteInt16LittleEndian(defaultOptions, userData.OptionSetting); BinaryPrimitives.WriteInt16LittleEndian(defaultOptions, userData.OptionSetting);
var difficultySettingArray = JsonHelper.GetUIntArrayFromJson(userData.DifficultySettingArray, 3, Logger, nameof(userData.DifficultySettingArray));
for (int i = 0; i < 3; i++)
{
if (difficultySettingArray[i] >= 2)
{
difficultySettingArray[i] -= 1;
}
}
var difficultyPlayedArray = JsonHelper.GetUIntArrayFromJson(userData.DifficultyPlayedArray, 3, Logger, nameof(userData.DifficultyPlayedArray));
var response = new UserDataResponse var response = new UserDataResponse
{ {
Result = 1, Result = 1,
@ -118,14 +158,20 @@ public class UserDataController : BaseController<UserDataController>
TitleFlg = titleArray, TitleFlg = titleArray,
ReleaseSongFlg = releaseSongArray, ReleaseSongFlg = releaseSongArray,
UraReleaseSongFlg = uraSongArray, UraReleaseSongFlg = uraSongArray,
DefaultOptionSetting = defaultOptions,
IsVoiceOn = userData.IsVoiceOn,
IsSkipOn = userData.IsSkipOn,
IsChallengecompe = false,
SongRecentCnt = (uint)recentSongs.Length,
AryFavoriteSongNoes = favoriteSongs, AryFavoriteSongNoes = favoriteSongs,
AryRecentSongNoes = recentSongs, AryRecentSongNoes = recentSongs,
NotesPosition = userData.NotesPosition DefaultOptionSetting = defaultOptions,
NotesPosition = userData.NotesPosition,
IsVoiceOn = userData.IsVoiceOn,
IsSkipOn = userData.IsSkipOn,
DifficultySettingCourse = difficultySettingArray[0],
DifficultySettingStar = difficultySettingArray[1],
DifficultySettingSort = difficultySettingArray[2],
DifficultyPlayedCourse = difficultyPlayedArray[0],
DifficultyPlayedStar = difficultyPlayedArray[1],
DifficultyPlayedSort = difficultyPlayedArray[2],
IsChallengecompe = false,
SongRecentCnt = (uint)recentSongs.Length
}; };
return Ok(response); return Ok(response);

View File

@ -1,19 +1,35 @@
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/verifyqrcode.php")] [Route("/v12r00_cn/chassis/verifyqrcode.php")]
[ApiController] [ApiController]
public class VerifyQrCodeController : BaseController<VerifyQrCodeController> public class VerifyQrCodeController : BaseController<VerifyQrCodeController>
{ {
private readonly IGameDataService gameDataService;
public VerifyQrCodeController(IGameDataService gameDataService)
{
this.gameDataService = gameDataService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult VerifyQrCode([FromBody] VerifyQrcodeRequest request) public IActionResult VerifyQrCode([FromBody] VerifyQrcodeRequest request)
{ {
Logger.LogInformation("VerifyQrCode request : {Request}", request.Stringify()); Logger.LogInformation("VerifyQrCode request : {Request}", request.Stringify());
var qrCodeDataDictionary = gameDataService.GetQRCodeDataDictionary();
qrCodeDataDictionary.TryGetValue(request.QrcodeSerial, out var qrCodeId);
if (qrCodeId == 0)
{
Logger.LogWarning("Requested QR code serial {Serial} does not exist!", request.QrcodeSerial);
}
var response = new VerifyQrcodeResponse var response = new VerifyQrcodeResponse
{ {
Result = 1, Result = 1,
QrcodeId = 1 QrcodeId = qrCodeId
}; };
return Ok(response); return Ok(response);

View File

@ -0,0 +1,35 @@
using Serilog.Events;
using Serilog.Formatting;
namespace TaikoLocalServer.Logging;
public class CsvFormatter: ITextFormatter
{
public void Format(LogEvent logEvent, TextWriter output)
{
logEvent.Properties.TryGetValue("ChassisId", out var chassisId);
logEvent.Properties.TryGetValue("ShopId", out var shopId);
logEvent.Properties.TryGetValue("Baid", out var baid);
logEvent.Properties.TryGetValue("PlayedAt", out var playedAt);
logEvent.Properties.TryGetValue("IsRight", out var isRight);
logEvent.Properties.TryGetValue("Type", out var type);
logEvent.Properties.TryGetValue("Amount", out var amount);
output.Write(logEvent.Timestamp.ToString("yyyy-MM-dd"));
output.Write(",");
output.Write(chassisId);
output.Write(",");
output.Write(shopId);
output.Write(",");
output.Write(baid);
output.Write(",");
output.Write(playedAt);
output.Write(",");
output.Write(isRight);
output.Write(",");
output.Write(type);
output.Write(",");
output.Write(amount);
output.WriteLine();
}
}

View File

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class DonCosRewardEntry
{
[JsonPropertyName("cosType")]
public string cosType { get; set; } = null!;
[JsonPropertyName("uniqueId")]
public uint uniqueId { get; set; }
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class DonCosRewards
{
[JsonPropertyName("items")]
public List<DonCosRewardEntry> DonCosRewardEntries { get; set; } = new();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class MusicAttributeEntry
{
[JsonPropertyName("uniqueId")]
public uint MusicId { get; set; }
[JsonPropertyName("canPlayUra")]
public bool HasUra { get; set; }
}

View File

@ -1,9 +0,0 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class MusicAttributes
{
[JsonPropertyName("items")]
public List<MusicAttributeEntry> MusicAttributeEntries { get; set; } = new();
}

View File

@ -0,0 +1,12 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class MusicInfoEntry
{
[JsonPropertyName("uniqueId")]
public uint MusicId { get; set; }
[JsonPropertyName("starUra")]
public uint starUra { get; set; }
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class MusicInfoes
{
[JsonPropertyName("items")]
public List<MusicInfoEntry> MusicInfoEntries { get; set; } = new();
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class NeiroEntry
{
[JsonPropertyName("uniqueId")]
public uint uniqueId { get; set; }
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class Neiros
{
[JsonPropertyName("items")]
public List<NeiroEntry> NeiroEntries { get; set; } = new();
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class ShougouEntry
{
[JsonPropertyName("uniqueId")]
public uint uniqueId { get; set; }
}

View File

@ -0,0 +1,9 @@
using System.Text.Json.Serialization;
namespace TaikoLocalServer.Models;
public class Shougous
{
[JsonPropertyName("items")]
public List<ShougouEntry> ShougouEntries { get; set; } = new();
}

View File

@ -8,249 +8,248 @@
#pragma warning disable CS0612, CS0618, CS1591, CS3021, IDE0079, IDE1006, RCS1036, RCS1057, RCS1085, RCS1192 #pragma warning disable CS0612, CS0618, CS1591, CS3021, IDE0079, IDE1006, RCS1036, RCS1057, RCS1085, RCS1192
namespace taiko.vsinterface namespace taiko.vsinterface
{ {
[global::ProtoBuf.ProtoContract()]
public partial class StartupAuthRequest : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"chassis_id", IsRequired = true)]
public partial class StartupAuthRequest : global::ProtoBuf.IExtensible public string ChassisId { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"chassis_id", IsRequired = true)] [global::ProtoBuf.ProtoMember(2, Name = @"usbmem_key")]
public string ChassisId { get; set; } [global::System.ComponentModel.DefaultValue("")]
public string UsbmemKey
{
get => __pbn__UsbmemKey ?? "";
set => __pbn__UsbmemKey = value;
}
public bool ShouldSerializeUsbmemKey() => __pbn__UsbmemKey != null;
public void ResetUsbmemKey() => __pbn__UsbmemKey = null;
private string __pbn__UsbmemKey;
[global::ProtoBuf.ProtoMember(2, Name = @"usbmem_key")] [global::ProtoBuf.ProtoMember(3, Name = @"hdd_ver", IsRequired = true)]
[global::System.ComponentModel.DefaultValue("")] public uint HddVer { get; set; }
public string UsbmemKey
{
get => __pbn__UsbmemKey ?? "";
set => __pbn__UsbmemKey = value;
}
public bool ShouldSerializeUsbmemKey() => __pbn__UsbmemKey != null;
public void ResetUsbmemKey() => __pbn__UsbmemKey = null;
private string __pbn__UsbmemKey;
[global::ProtoBuf.ProtoMember(3, Name = @"hdd_ver", IsRequired = true)] [global::ProtoBuf.ProtoMember(4, Name = @"usbmem_ver")]
public uint HddVer { get; set; } public uint UsbmemVer
{
get => __pbn__UsbmemVer.GetValueOrDefault();
set => __pbn__UsbmemVer = value;
}
public bool ShouldSerializeUsbmemVer() => __pbn__UsbmemVer != null;
public void ResetUsbmemVer() => __pbn__UsbmemVer = null;
private uint? __pbn__UsbmemVer;
[global::ProtoBuf.ProtoMember(4, Name = @"usbmem_ver")] [global::ProtoBuf.ProtoMember(5, Name = @"shop_id", IsRequired = true)]
public uint UsbmemVer public string ShopId { get; set; }
{
get => __pbn__UsbmemVer.GetValueOrDefault();
set => __pbn__UsbmemVer = value;
}
public bool ShouldSerializeUsbmemVer() => __pbn__UsbmemVer != null;
public void ResetUsbmemVer() => __pbn__UsbmemVer = null;
private uint? __pbn__UsbmemVer;
[global::ProtoBuf.ProtoMember(5, Name = @"shop_id", IsRequired = true)] [global::ProtoBuf.ProtoMember(6, Name = @"rack_id")]
public string ShopId { get; set; } [global::System.ComponentModel.DefaultValue("")]
public string RackId
{
get => __pbn__RackId ?? "";
set => __pbn__RackId = value;
}
public bool ShouldSerializeRackId() => __pbn__RackId != null;
public void ResetRackId() => __pbn__RackId = null;
private string __pbn__RackId;
[global::ProtoBuf.ProtoMember(6, Name = @"rack_id")] [global::ProtoBuf.ProtoMember(7, Name = @"country_id")]
[global::System.ComponentModel.DefaultValue("")] [global::System.ComponentModel.DefaultValue("")]
public string RackId public string CountryId
{ {
get => __pbn__RackId ?? ""; get => __pbn__CountryId ?? "";
set => __pbn__RackId = value; set => __pbn__CountryId = value;
} }
public bool ShouldSerializeRackId() => __pbn__RackId != null; public bool ShouldSerializeCountryId() => __pbn__CountryId != null;
public void ResetRackId() => __pbn__RackId = null; public void ResetCountryId() => __pbn__CountryId = null;
private string __pbn__RackId; private string __pbn__CountryId;
[global::ProtoBuf.ProtoMember(7, Name = @"country_id")] [global::ProtoBuf.ProtoMember(8, Name = @"ary_operation_info")]
[global::System.ComponentModel.DefaultValue("")] public global::System.Collections.Generic.List<OperationData> AryOperationInfoes { get; } = new global::System.Collections.Generic.List<OperationData>();
public string CountryId
{
get => __pbn__CountryId ?? "";
set => __pbn__CountryId = value;
}
public bool ShouldSerializeCountryId() => __pbn__CountryId != null;
public void ResetCountryId() => __pbn__CountryId = null;
private string __pbn__CountryId;
[global::ProtoBuf.ProtoMember(8, Name = @"ary_operation_info")] [global::ProtoBuf.ProtoContract()]
public global::System.Collections.Generic.List<OperationData> AryOperationInfoes { get; } = new global::System.Collections.Generic.List<OperationData>(); public partial class OperationData : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"key_data", IsRequired = true)]
public partial class OperationData : global::ProtoBuf.IExtensible public uint KeyData { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"key_data", IsRequired = true)] [global::ProtoBuf.ProtoMember(2, Name = @"value_data", IsRequired = true)]
public uint KeyData { get; set; } public byte[] ValueData { get; set; }
[global::ProtoBuf.ProtoMember(2, Name = @"value_data", IsRequired = true)] }
public byte[] ValueData { get; set; }
} }
} [global::ProtoBuf.ProtoContract()]
public partial class StartupAuthResponse : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"result", IsRequired = true)]
public partial class StartupAuthResponse : global::ProtoBuf.IExtensible public uint Result { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"result", IsRequired = true)] [global::ProtoBuf.ProtoMember(2, Name = @"ary_movie_info")]
public uint Result { get; set; } public global::System.Collections.Generic.List<MovieData> AryMovieInfoes { get; } = new global::System.Collections.Generic.List<MovieData>();
[global::ProtoBuf.ProtoMember(2, Name = @"ary_movie_info")] [global::ProtoBuf.ProtoMember(3, Name = @"ary_operation_info")]
public global::System.Collections.Generic.List<MovieData> AryMovieInfoes { get; } = new global::System.Collections.Generic.List<MovieData>(); public global::System.Collections.Generic.List<OperationData> AryOperationInfoes { get; } = new global::System.Collections.Generic.List<OperationData>();
[global::ProtoBuf.ProtoMember(3, Name = @"ary_operation_info")] [global::ProtoBuf.ProtoContract()]
public global::System.Collections.Generic.List<OperationData> AryOperationInfoes { get; } = new global::System.Collections.Generic.List<OperationData>(); public partial class MovieData : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"movie_id", IsRequired = true)]
public partial class MovieData : global::ProtoBuf.IExtensible public uint MovieId { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"movie_id", IsRequired = true)] [global::ProtoBuf.ProtoMember(2, Name = @"enable_days", IsRequired = true)]
public uint MovieId { get; set; } public uint EnableDays { get; set; }
[global::ProtoBuf.ProtoMember(2, Name = @"enable_days", IsRequired = true)] }
public uint EnableDays { get; set; }
} [global::ProtoBuf.ProtoContract()]
public partial class OperationData : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"key_data", IsRequired = true)]
public partial class OperationData : global::ProtoBuf.IExtensible public uint KeyData { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"key_data", IsRequired = true)] [global::ProtoBuf.ProtoMember(2, Name = @"value_data", IsRequired = true)]
public uint KeyData { get; set; } public byte[] ValueData { get; set; }
[global::ProtoBuf.ProtoMember(2, Name = @"value_data", IsRequired = true)] }
public byte[] ValueData { get; set; }
} }
} [global::ProtoBuf.ProtoContract()]
public partial class VerupAuthRequest : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"chassis_id", IsRequired = true)]
public partial class VerupAuthRequest : global::ProtoBuf.IExtensible public string ChassisId { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"chassis_id", IsRequired = true)] [global::ProtoBuf.ProtoMember(2, Name = @"usbmem_key", IsRequired = true)]
public string ChassisId { get; set; } public string UsbmemKey { get; set; }
[global::ProtoBuf.ProtoMember(2, Name = @"usbmem_key", IsRequired = true)] [global::ProtoBuf.ProtoMember(3, Name = @"hdd_ver", IsRequired = true)]
public string UsbmemKey { get; set; } public uint HddVer { get; set; }
[global::ProtoBuf.ProtoMember(3, Name = @"hdd_ver", IsRequired = true)] [global::ProtoBuf.ProtoMember(4, Name = @"usbmem_ver", IsRequired = true)]
public uint HddVer { get; set; } public uint UsbmemVer { get; set; }
[global::ProtoBuf.ProtoMember(4, Name = @"usbmem_ver", IsRequired = true)] [global::ProtoBuf.ProtoMember(5, Name = @"shop_id", IsRequired = true)]
public uint UsbmemVer { get; set; } public string ShopId { get; set; }
[global::ProtoBuf.ProtoMember(5, Name = @"shop_id", IsRequired = true)] [global::ProtoBuf.ProtoMember(6, Name = @"rack_id")]
public string ShopId { get; set; } [global::System.ComponentModel.DefaultValue("")]
public string RackId
{
get => __pbn__RackId ?? "";
set => __pbn__RackId = value;
}
public bool ShouldSerializeRackId() => __pbn__RackId != null;
public void ResetRackId() => __pbn__RackId = null;
private string __pbn__RackId;
[global::ProtoBuf.ProtoMember(6, Name = @"rack_id")] [global::ProtoBuf.ProtoMember(7, Name = @"country_id")]
[global::System.ComponentModel.DefaultValue("")] [global::System.ComponentModel.DefaultValue("")]
public string RackId public string CountryId
{ {
get => __pbn__RackId ?? ""; get => __pbn__CountryId ?? "";
set => __pbn__RackId = value; set => __pbn__CountryId = value;
} }
public bool ShouldSerializeRackId() => __pbn__RackId != null; public bool ShouldSerializeCountryId() => __pbn__CountryId != null;
public void ResetRackId() => __pbn__RackId = null; public void ResetCountryId() => __pbn__CountryId = null;
private string __pbn__RackId; private string __pbn__CountryId;
[global::ProtoBuf.ProtoMember(7, Name = @"country_id")] }
[global::System.ComponentModel.DefaultValue("")]
public string CountryId
{
get => __pbn__CountryId ?? "";
set => __pbn__CountryId = value;
}
public bool ShouldSerializeCountryId() => __pbn__CountryId != null;
public void ResetCountryId() => __pbn__CountryId = null;
private string __pbn__CountryId;
} [global::ProtoBuf.ProtoContract()]
public partial class VerupAuthResponse : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"result", IsRequired = true)]
public partial class VerupAuthResponse : global::ProtoBuf.IExtensible public uint Result { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"result", IsRequired = true)] }
public uint Result { get; set; }
} [global::ProtoBuf.ProtoContract()]
public partial class VerupCompleteRequest : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"chassis_id", IsRequired = true)]
public partial class VerupCompleteRequest : global::ProtoBuf.IExtensible public string ChassisId { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"chassis_id", IsRequired = true)] [global::ProtoBuf.ProtoMember(2, Name = @"usbmem_key", IsRequired = true)]
public string ChassisId { get; set; } public string UsbmemKey { get; set; }
[global::ProtoBuf.ProtoMember(2, Name = @"usbmem_key", IsRequired = true)] [global::ProtoBuf.ProtoMember(3, Name = @"hdd_ver", IsRequired = true)]
public string UsbmemKey { get; set; } public uint HddVer { get; set; }
[global::ProtoBuf.ProtoMember(3, Name = @"hdd_ver", IsRequired = true)] [global::ProtoBuf.ProtoMember(4, Name = @"usbmem_ver", IsRequired = true)]
public uint HddVer { get; set; } public uint UsbmemVer { get; set; }
[global::ProtoBuf.ProtoMember(4, Name = @"usbmem_ver", IsRequired = true)] [global::ProtoBuf.ProtoMember(5, Name = @"shop_id", IsRequired = true)]
public uint UsbmemVer { get; set; } public string ShopId { get; set; }
[global::ProtoBuf.ProtoMember(5, Name = @"shop_id", IsRequired = true)] [global::ProtoBuf.ProtoMember(6, Name = @"rack_id")]
public string ShopId { get; set; } [global::System.ComponentModel.DefaultValue("")]
public string RackId
{
get => __pbn__RackId ?? "";
set => __pbn__RackId = value;
}
public bool ShouldSerializeRackId() => __pbn__RackId != null;
public void ResetRackId() => __pbn__RackId = null;
private string __pbn__RackId;
[global::ProtoBuf.ProtoMember(6, Name = @"rack_id")] [global::ProtoBuf.ProtoMember(7, Name = @"country_id")]
[global::System.ComponentModel.DefaultValue("")] [global::System.ComponentModel.DefaultValue("")]
public string RackId public string CountryId
{ {
get => __pbn__RackId ?? ""; get => __pbn__CountryId ?? "";
set => __pbn__RackId = value; set => __pbn__CountryId = value;
} }
public bool ShouldSerializeRackId() => __pbn__RackId != null; public bool ShouldSerializeCountryId() => __pbn__CountryId != null;
public void ResetRackId() => __pbn__RackId = null; public void ResetCountryId() => __pbn__CountryId = null;
private string __pbn__RackId; private string __pbn__CountryId;
[global::ProtoBuf.ProtoMember(7, Name = @"country_id")] }
[global::System.ComponentModel.DefaultValue("")]
public string CountryId
{
get => __pbn__CountryId ?? "";
set => __pbn__CountryId = value;
}
public bool ShouldSerializeCountryId() => __pbn__CountryId != null;
public void ResetCountryId() => __pbn__CountryId = null;
private string __pbn__CountryId;
} [global::ProtoBuf.ProtoContract()]
public partial class VerupCompleteResponse : global::ProtoBuf.IExtensible
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoContract()] [global::ProtoBuf.ProtoMember(1, Name = @"result", IsRequired = true)]
public partial class VerupCompleteResponse : global::ProtoBuf.IExtensible public uint Result { get; set; }
{
private global::ProtoBuf.IExtension __pbn__extensionData;
global::ProtoBuf.IExtension global::ProtoBuf.IExtensible.GetExtensionObject(bool createIfMissing)
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
[global::ProtoBuf.ProtoMember(1, Name = @"result", IsRequired = true)] }
public uint Result { get; set; }
}
} }

View File

@ -1,6 +1,9 @@
using System.Reflection; using System.Reflection;
using System.Security.Authentication; using System.Security.Authentication;
using Serilog.Sinks.File.Header;
using TaikoLocalServer.Logging;
using GameDatabase.Context; using GameDatabase.Context;
using Microsoft.AspNetCore.HttpLogging;
using Microsoft.AspNetCore.HttpOverrides; using Microsoft.AspNetCore.HttpOverrides;
using TaikoLocalServer.Middlewares; using TaikoLocalServer.Middlewares;
using TaikoLocalServer.Services.Extentions; using TaikoLocalServer.Services.Extentions;
@ -23,26 +26,32 @@ try
{ {
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureAppConfiguration((hostingContext, config) => builder.Services.AddHttpLogging(options =>
{ {
const string configurationsDirectory = "Configurations"; options.LoggingFields = HttpLoggingFields.All;
config.AddJsonFile($"{configurationsDirectory}/Kestrel.json", optional: true, reloadOnChange: false); options.RequestBodyLogLimit = 32768;
config.AddJsonFile($"{configurationsDirectory}/Logging.json", optional: false, reloadOnChange: false); options.ResponseBodyLogLimit = 32768;
config.AddJsonFile($"{configurationsDirectory}/Database.json", optional: false, reloadOnChange: false);
config.AddJsonFile($"{configurationsDirectory}/ServerSettings.json", optional: false, reloadOnChange: false);
config.AddJsonFile($"{configurationsDirectory}/DataSettings.json", optional: true, reloadOnChange: false);
}); });
// Manually enable tls 1.0 const string configurationsDirectory = "Configurations";
builder.WebHost.UseKestrel(kestrelOptions => builder.Configuration.AddJsonFile($"{configurationsDirectory}/Kestrel.json", optional: true, reloadOnChange: false);
{ builder.Configuration.AddJsonFile($"{configurationsDirectory}/Logging.json", optional: false, reloadOnChange: false);
kestrelOptions.ConfigureHttpsDefaults(options => builder.Configuration.AddJsonFile($"{configurationsDirectory}/Database.json", optional: false, reloadOnChange: false);
options.SslProtocols = SslProtocols.Tls | SslProtocols.Tls11 | SslProtocols.Tls12 | SslProtocols.Tls13); builder.Configuration.AddJsonFile($"{configurationsDirectory}/ServerSettings.json", optional: false, reloadOnChange: false);
}); builder.Configuration.AddJsonFile($"{configurationsDirectory}/DataSettings.json", optional: true, reloadOnChange: false);
builder.Host.UseSerilog((context, configuration) => builder.Host.UseSerilog((context, configuration) =>
{ {
configuration.WriteTo.Console().ReadFrom.Configuration(context.Configuration); configuration
.WriteTo.Console().ReadFrom.Configuration(context.Configuration)
.WriteTo.Logger(x =>
{
x.WriteTo.File(new CsvFormatter(),
path: "./Logs/HeadClerkLog-.csv",
hooks: new HeaderWriter("Date,ChassisId,ShopId,Baid,PlayedAt,IsRight,Type,Amount"),
rollingInterval: RollingInterval.Day);
x.Filter.ByIncludingOnly("StartsWith(@m, 'CSV WRITE:')");
});
}); });
if (builder.Configuration.GetValue<bool>("ServerSettings:EnableMoreSongs")) if (builder.Configuration.GetValue<bool>("ServerSettings:EnableMoreSongs"))
@ -117,6 +126,16 @@ try
app.UseHttpLogging(); app.UseHttpLogging();
app.Use(async (context, next) =>
{
await next();
if (context.Response.StatusCode >= 400)
{
Log.Error("Unknown request from: {RemoteIpAddress} {Method} {Path} {StatusCode}",
context.Connection.RemoteIpAddress, context.Request.Method, context.Request.Path, context.Response.StatusCode);
}
});
app.MapControllers(); app.MapControllers();
app.MapFallbackToFile("index.html"); app.MapFallbackToFile("index.html");

View File

@ -12,7 +12,7 @@
"TaikoLocalServer": { "TaikoLocalServer": {
"commandName": "Project", "commandName": "Project",
"dotnetRunMessages": true, "dotnetRunMessages": true,
"launchBrowser": true, "launchBrowser": false,
"launchUrl": "", "launchUrl": "",
"applicationUrl": "http://localhost:5000", "applicationUrl": "http://localhost:5000",
"environmentVariables": { "environmentVariables": {
@ -21,7 +21,7 @@
}, },
"IIS Express": { "IIS Express": {
"commandName": "IISExpress", "commandName": "IISExpress",
"launchBrowser": true, "launchBrowser": false,
"launchUrl": "swagger", "launchUrl": "swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"

View File

@ -13,14 +13,14 @@ public class AiDatumService : IAiDatumService
this.context = context; this.context = context;
} }
public async Task<List<AiScoreDatum>> GetAllAiScoreById(uint baid) public async Task<List<AiScoreDatum>> GetAllAiScoreById(ulong baid)
{ {
return await context.AiScoreData.Where(datum => datum.Baid == baid) return await context.AiScoreData.Where(datum => datum.Baid == baid)
.Include(datum => datum.AiSectionScoreData) .Include(datum => datum.AiSectionScoreData)
.ToListAsync(); .ToListAsync();
} }
public async Task<AiScoreDatum?> GetSongAiScore(uint baid, uint songId, Difficulty difficulty) public async Task<AiScoreDatum?> GetSongAiScore(ulong baid, uint songId, Difficulty difficulty)
{ {
return await context.AiScoreData.Where(datum => datum.Baid == baid && return await context.AiScoreData.Where(datum => datum.Baid == baid &&
datum.SongId == songId && datum.SongId == songId &&

View File

@ -7,46 +7,59 @@ namespace TaikoLocalServer.Services;
public class CardService : ICardService public class CardService : ICardService
{ {
private readonly TaikoDbContext context; private readonly TaikoDbContext context;
public CardService(TaikoDbContext context) public CardService(TaikoDbContext context)
{ {
this.context = context; this.context = context;
} }
public async Task<Card?> GetCardByAccessCode(string accessCode) public async Task<Card?> GetCardByAccessCode(string accessCode)
{ {
return await context.Cards.FindAsync(accessCode); return await context.Cards.FindAsync(accessCode);
} }
public uint GetNextBaid() public ulong GetNextBaid()
{ {
return context.Cards.Any() ? context.Cards.Max(card => card.Baid) + 1 : 1; return context.Cards.Any() ? context.Cards.ToList().Max(card => card.Baid) + 1 : 1;
} }
public async Task<List<User>> GetUsersFromCards() public async Task<List<User>> GetUsersFromCards()
{ {
return await context.Cards.Select(card => card.CopyPropertiesToNew<User>(null)).ToListAsync(); return await context.Cards.Select(card => card.CopyPropertiesToNew<User>(null)).ToListAsync();
} }
public async Task AddCard(Card card) public async Task AddCard(Card card)
{ {
context.Add(card); context.Add(card);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
public async Task<bool> DeleteCard(string accessCode) public async Task<bool> DeleteCard(string accessCode)
{ {
var card = await context.Cards.FindAsync(accessCode); var card = await context.Cards.FindAsync(accessCode);
if (card is null) if (card is null)
{ {
return false; return false;
} }
context.Cards.Remove(card); context.Cards.Remove(card);
await context.SaveChangesAsync(); await context.SaveChangesAsync();
return true; return true;
} }
public async Task<bool> UpdatePassword(string accessCode, string password, string salt)
{
var card = await context.Cards.FindAsync(accessCode);
if (card is null) return false;
card.Password = password;
card.Salt = salt;
await context.SaveChangesAsync();
return true;
}
} }

View File

@ -12,14 +12,14 @@ public class DanScoreDatumService : IDanScoreDatumService
this.context = context; this.context = context;
} }
public async Task<List<DanScoreDatum>> GetDanScoreDatumByBaid(uint baid) public async Task<List<DanScoreDatum>> GetDanScoreDatumByBaid(ulong baid)
{ {
return await context.DanScoreData.Where(datum => datum.Baid == baid) return await context.DanScoreData.Where(datum => datum.Baid == baid)
.Include(datum => datum.DanStageScoreData) .Include(datum => datum.DanStageScoreData)
.ToListAsync(); .ToListAsync();
} }
public async Task<DanScoreDatum?> GetSingleDanScoreDatum(uint baid, uint danId) public async Task<DanScoreDatum?> GetSingleDanScoreDatum(ulong baid, uint danId)
{ {
return await context.DanScoreData.Include(datum => datum.DanStageScoreData) return await context.DanScoreData.Include(datum => datum.DanStageScoreData)
.FirstOrDefaultAsync(datum => datum.Baid == baid && .FirstOrDefaultAsync(datum => datum.Baid == baid &&

View File

@ -1,10 +1,12 @@
using System.Collections.Immutable; using ICSharpCode.SharpZipLib.GZip;
using System.Text.Json;
using ICSharpCode.SharpZipLib.GZip;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using SharedProject.Models; using SharedProject.Models;
using SharedProject.Utils; using SharedProject.Utils;
using Swan.Mapping; using Swan.Mapping;
using System.Collections.Immutable;
using System.IO.Compression;
using System.Security.Cryptography;
using System.Text.Json;
using TaikoLocalServer.Settings; using TaikoLocalServer.Settings;
using Throw; using Throw;
@ -12,178 +14,460 @@ namespace TaikoLocalServer.Services;
public class GameDataService : IGameDataService public class GameDataService : IGameDataService
{ {
private ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> danDataDictionary = private ImmutableDictionary<uint, MusicInfoEntry> musicInfoes =
ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData>.Empty; ImmutableDictionary<uint, MusicInfoEntry>.Empty;
private ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> introDataDictionary = private ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> danDataDictionary =
ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData>.Empty; ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData>.Empty;
private ImmutableDictionary<uint, MusicAttributeEntry> musicAttributes =
ImmutableDictionary<uint, MusicAttributeEntry>.Empty;
private ImmutableDictionary<uint, GetfolderResponse.EventfolderData> folderDictionary = private ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> gaidenDataDictionary =
ImmutableDictionary<uint, GetfolderResponse.EventfolderData>.Empty; ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData>.Empty;
private List<uint> musics = new(); private ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> introDataDictionary =
ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData>.Empty;
private List<uint> musicsWithUra = new(); private ImmutableDictionary<uint, InitialdatacheckResponse.MovieData> movieDataDictionary =
ImmutableDictionary<uint, InitialdatacheckResponse.MovieData>.Empty;
private readonly DataSettings settings;
public GameDataService(IOptions<DataSettings> settings) private ImmutableDictionary<uint, GetfolderResponse.EventfolderData> folderDictionary =
{ ImmutableDictionary<uint, GetfolderResponse.EventfolderData>.Empty;
this.settings = settings.Value;
}
public List<uint> GetMusicList() private ImmutableDictionary<string, uint> qrCodeDataDictionary = ImmutableDictionary<string, uint>.Empty;
{
return musics; private List<GetShopFolderResponse.ShopFolderData> shopFolderList = new();
}
public List<uint> GetMusicWithUraList() private List<uint> musics = new();
{
return musicsWithUra;
}
public ImmutableDictionary<uint, MusicAttributeEntry> GetMusicAttributes() private List<uint> musicsWithUra = new();
{
return musicAttributes;
}
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary() private List<uint> lockedSongsList = new();
{
return danDataDictionary; private List<int> costumeFlagArraySizes = new();
}
private int titleFlagArraySize;
public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary()
{ private int toneFlagArraySize;
return introDataDictionary;
}
public ImmutableDictionary<uint, GetfolderResponse.EventfolderData> GetFolderDictionary() private Dictionary<string, int> tokenDataDictionary = new();
{
return folderDictionary;
}
public async Task InitializeAsync() private readonly DataSettings settings;
{
var dataPath = PathHelper.GetDataPath();
var musicAttributePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_FILE_NAME);
var compressedMusicAttributePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_COMPRESSED_FILE_NAME);
var danDataPath = Path.Combine(dataPath, settings.DanDataFileName);
var songIntroDataPath = Path.Combine(dataPath, settings.IntroDataFileName);
var eventFolderDataPath = Path.Combine(dataPath, settings.EventFolderDataFileName);
if (File.Exists(compressedMusicAttributePath)) public GameDataService(IOptions<DataSettings> settings)
{ {
TryDecompressMusicAttribute(); this.settings = settings.Value;
} }
await using var musicAttributeFile = File.OpenRead(musicAttributePath);
await using var danDataFile = File.OpenRead(danDataPath);
await using var songIntroDataFile = File.OpenRead(songIntroDataPath);
await using var eventFolderDataFile = File.OpenRead(eventFolderDataPath);
var attributesData = await JsonSerializer.DeserializeAsync<MusicAttributes>(musicAttributeFile); public List<uint> GetMusicList()
var danData = await JsonSerializer.DeserializeAsync<List<DanData>>(danDataFile); {
var introData = await JsonSerializer.DeserializeAsync<List<SongIntroductionData>>(songIntroDataFile); return musics;
var eventFolderData = await JsonSerializer.DeserializeAsync<List<EventFolderData>>(eventFolderDataFile); }
InitializeMusicAttributes(attributesData); public List<uint> GetMusicWithUraList()
{
return musicsWithUra;
}
InitializeDanData(danData); public ImmutableDictionary<uint, MusicInfoEntry> GetMusicInfoes()
{
return musicInfoes;
}
InitializeIntroData(introData); public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary()
{
return danDataDictionary;
}
InitializeEventFolderData(eventFolderData); public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetGaidenDataDictionary()
} {
return gaidenDataDictionary;
}
private static void TryDecompressMusicAttribute() public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary()
{ {
var dataPath = PathHelper.GetDataPath(); return introDataDictionary;
var musicAttributePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_FILE_NAME); }
var compressedMusicAttributePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_COMPRESSED_FILE_NAME);
using var compressed = File.Open(compressedMusicAttributePath, FileMode.Open);
using var output = File.Create(musicAttributePath);
GZip.Decompress(compressed, output, true);
}
private void InitializeIntroData(List<SongIntroductionData>? introData) public ImmutableDictionary<uint, InitialdatacheckResponse.MovieData> GetMovieDataDictionary()
{ {
introData.ThrowIfNull("Shouldn't happen!"); return movieDataDictionary;
introDataDictionary = introData.ToImmutableDictionary(data => data.SetId, ToResponseIntroData); }
}
private void InitializeDanData(List<DanData>? danData) public ImmutableDictionary<uint, GetfolderResponse.EventfolderData> GetFolderDictionary()
{ {
danData.ThrowIfNull("Shouldn't happen!"); return folderDictionary;
danDataDictionary = danData.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData); }
}
private void InitializeEventFolderData(List<EventFolderData>? eventFolderData) public List<GetShopFolderResponse.ShopFolderData> GetShopFolderList()
{ {
eventFolderData.ThrowIfNull("Shouldn't happen!"); return shopFolderList;
folderDictionary = eventFolderData.ToImmutableDictionary(data => data.FolderId, ToResponseEventFolderData); }
}
private void InitializeMusicAttributes(MusicAttributes? attributesData) public Dictionary<string, int> GetTokenDataDictionary()
{ {
attributesData.ThrowIfNull("Shouldn't happen!"); return tokenDataDictionary;
}
musicAttributes = attributesData.MusicAttributeEntries.ToImmutableDictionary(attribute => attribute.MusicId); public List<uint> GetLockedSongsList()
{
return lockedSongsList;
}
public List<int> GetCostumeFlagArraySizes()
{
return costumeFlagArraySizes;
}
public int GetTitleFlagArraySize()
{
return titleFlagArraySize;
}
public int GetToneFlagArraySize()
{
return toneFlagArraySize;
}
musics = musicAttributes.Select(pair => pair.Key) public ImmutableDictionary<string, uint> GetQRCodeDataDictionary()
.ToList(); {
musics.Sort(); return qrCodeDataDictionary;
}
musicsWithUra = musicAttributes.Where(attribute => attribute.Value.HasUra) public async Task InitializeAsync()
.Select(pair => pair.Key) {
.ToList(); var dataPath = PathHelper.GetDataPath();
musicsWithUra.Sort();
} var musicInfoPath = Path.Combine(dataPath, $"{Constants.MUSIC_INFO_BASE_NAME}.json");
var encryptedInfo = Path.Combine(dataPath, $"{Constants.MUSIC_INFO_BASE_NAME}.bin");
var wordlistPath = Path.Combine(dataPath, $"{Constants.WORDLIST_BASE_NAME}.json");
var encryptedWordlist = Path.Combine(dataPath, $"{Constants.WORDLIST_BASE_NAME}.bin");
var musicOrderPath = Path.Combine(dataPath, $"{Constants.MUSIC_ORDER_BASE_NAME}.json");
var encryptedMusicOrder = Path.Combine(dataPath, $"{Constants.MUSIC_ORDER_BASE_NAME}.bin");
var donCosRewardPath = Path.Combine(dataPath, $"{Constants.DON_COS_REWARD_BASE_NAME}.json");
var encryptedDonCosReward = Path.Combine(dataPath, $"{Constants.DON_COS_REWARD_BASE_NAME}.bin");
var shougouPath = Path.Combine(dataPath, $"{Constants.SHOUGOU_BASE_NAME}.json");
var encryptedShougou = Path.Combine(dataPath, $"{Constants.SHOUGOU_BASE_NAME}.bin");
var neiroPath = Path.Combine(dataPath, $"{Constants.NEIRO_BASE_NAME}.json");
var encryptedNeiro = Path.Combine(dataPath, $"{Constants.NEIRO_BASE_NAME}.bin");
var danDataPath = Path.Combine(dataPath, settings.DanDataFileName);
var gaidenDataPath = Path.Combine(dataPath, settings.GaidenDataFileName);
var songIntroDataPath = Path.Combine(dataPath, settings.IntroDataFileName);
var movieDataPath = Path.Combine(dataPath, settings.MovieDataFileName);
var eventFolderDataPath = Path.Combine(dataPath, settings.EventFolderDataFileName);
var shopFolderDataPath = Path.Combine(dataPath, settings.ShopFolderDataFileName);
var tokenDataPath = Path.Combine(dataPath, settings.TokenDataFileName);
var lockedSongsDataPath = Path.Combine(dataPath, settings.LockedSongsDataFileName);
var qrCodeDataPath = Path.Combine(dataPath, settings.QRCodeDataFileName);
private static GetDanOdaiResponse.OdaiData ToResponseOdaiData(DanData data) if (File.Exists(encryptedInfo))
{ {
var responseOdaiData = new GetDanOdaiResponse.OdaiData DecryptDataTable(encryptedInfo, musicInfoPath);
{ }
DanId = data.DanId, if (File.Exists(encryptedWordlist))
Title = data.Title, {
VerupNo = data.VerupNo DecryptDataTable(encryptedWordlist, wordlistPath);
}; }
if (File.Exists(encryptedMusicOrder))
{
DecryptDataTable(encryptedMusicOrder, musicOrderPath);
}
if (File.Exists(encryptedDonCosReward))
{
DecryptDataTable(encryptedDonCosReward, donCosRewardPath);
}
if (File.Exists(encryptedShougou))
{
DecryptDataTable(encryptedShougou, shougouPath);
}
if (File.Exists(encryptedNeiro))
{
DecryptDataTable(encryptedNeiro, neiroPath);
}
if (!File.Exists(musicInfoPath))
{
throw new FileNotFoundException("Music info file not found!");
}
if (!File.Exists(wordlistPath))
{
throw new FileNotFoundException("Wordlist file not found!");
}
if (!File.Exists(musicOrderPath))
{
throw new FileNotFoundException("Music order file not found!");
}
if (!File.Exists(donCosRewardPath))
{
throw new FileNotFoundException("Don cos reward file not found!");
}
if (!File.Exists(shougouPath))
{
throw new FileNotFoundException("Shougou file not found!");
}
if (!File.Exists(neiroPath))
{
throw new FileNotFoundException("Neiro file not found!");
}
await using var musicInfoFile = File.OpenRead(musicInfoPath);
await using var danDataFile = File.OpenRead(danDataPath);
await using var gaidenDataFile = File.OpenRead(gaidenDataPath);
await using var songIntroDataFile = File.OpenRead(songIntroDataPath);
await using var movieDataFile = File.OpenRead(movieDataPath);
await using var eventFolderDataFile = File.OpenRead(eventFolderDataPath);
await using var shopFolderDataFile = File.OpenRead(shopFolderDataPath);
await using var tokenDataFile = File.OpenRead(tokenDataPath);
await using var lockedSongsDataFile = File.OpenRead(lockedSongsDataPath);
await using var donCosRewardFile = File.OpenRead(donCosRewardPath);
await using var shougouFile = File.OpenRead(shougouPath);
await using var neiroFile = File.OpenRead(neiroPath);
await using var qrCodeDataFile = File.OpenRead(qrCodeDataPath);
var odaiSongs = data.OdaiSongList.Select(song => song.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiSong>()); var infoesData = await JsonSerializer.DeserializeAsync<MusicInfoes>(musicInfoFile);
responseOdaiData.AryOdaiSongs.AddRange(odaiSongs); var danData = await JsonSerializer.DeserializeAsync<List<DanData>>(danDataFile);
var gaidenData = await JsonSerializer.DeserializeAsync<List<DanData>>(gaidenDataFile);
var introData = await JsonSerializer.DeserializeAsync<List<SongIntroductionData>>(songIntroDataFile);
var movieData = await JsonSerializer.DeserializeAsync<List<MovieData>>(movieDataFile);
var eventFolderData = await JsonSerializer.DeserializeAsync<List<EventFolderData>>(eventFolderDataFile);
var shopFolderData = await JsonSerializer.DeserializeAsync<List<ShopFolderData>>(shopFolderDataFile);
var tokenData = await JsonSerializer.DeserializeAsync<Dictionary<string, int>>(tokenDataFile);
var lockedSongsData = await JsonSerializer.DeserializeAsync<Dictionary<string, uint[]>>(lockedSongsDataFile);
var donCosRewardData = await JsonSerializer.DeserializeAsync<DonCosRewards>(donCosRewardFile);
var shougouData = await JsonSerializer.DeserializeAsync<Shougous>(shougouFile);
var neiroData = await JsonSerializer.DeserializeAsync<Neiros>(neiroFile);
var qrCodeData = await JsonSerializer.DeserializeAsync<List<QRCodeData>>(qrCodeDataFile);
var odaiBorders = data.OdaiBorderList.Select(border => border.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiBorder>()); InitializeMusicInfoes(infoesData);
responseOdaiData.AryOdaiBorders.AddRange(odaiBorders);
return responseOdaiData; InitializeDanData(danData);
}
private static GetSongIntroductionResponse.SongIntroductionData ToResponseIntroData(SongIntroductionData data) InitializeGaidenData(gaidenData);
{
var responseOdaiData = new GetSongIntroductionResponse.SongIntroductionData
{
SetId = data.SetId,
VerupNo = data.VerupNo,
MainSongNo = data.MainSongNo,
SubSongNoes = data.SubSongNo
};
return responseOdaiData; InitializeIntroData(introData);
}
private static GetfolderResponse.EventfolderData ToResponseEventFolderData(EventFolderData data) InitializeMovieData(movieData);
{
var responseEventFolderData = new GetfolderResponse.EventfolderData
{
FolderId = data.FolderId,
VerupNo = data.VerupNo,
Priority = data.Priority,
SongNoes = data.SongNo
};
return responseEventFolderData; InitializeEventFolderData(eventFolderData);
}
InitializeShopFolderData(shopFolderData);
InitializeTokenData(tokenData);
InitializeLockedSongsData(lockedSongsData);
InitializeCostumeFlagArraySizes(donCosRewardData);
InitializeTitleFlagArraySize(shougouData);
InitializeToneFlagArraySize(neiroData);
InitializeQrCodeData(qrCodeData);
}
private static void DecryptDataTable(string inputFileName, string outputFileName)
{
var aes = Aes.Create();
aes.Mode = CipherMode.CBC;
aes.KeySize = 256;
aes.Padding = PaddingMode.PKCS7;
aes.Key = Convert.FromHexString("3530304242323633353537423431384139353134383346433246464231354534");
var iv = new byte[16];
using var fs = File.OpenRead(inputFileName);
var count = fs.Read(iv, 0, 16);
count.Throw("Read IV for datatable failed!").IfNotEquals(16);
aes.IV = iv;
using var cs = new CryptoStream(fs, aes.CreateDecryptor(), CryptoStreamMode.Read);
using var ms = new MemoryStream();
cs.CopyTo(ms);
ms.Position = 0;
using var gz = new GZipStream(ms, CompressionMode.Decompress);
using var output = File.Create(outputFileName);
gz.CopyTo(output);
}
private void InitializeIntroData(List<SongIntroductionData>? introData)
{
introData.ThrowIfNull("Shouldn't happen!");
introDataDictionary = introData.ToImmutableDictionary(data => data.SetId, ToResponseIntroData);
}
private void InitializeMovieData(List<MovieData>? movieData)
{
movieData.ThrowIfNull("Shouldn't happen!");
movieDataDictionary = movieData.ToImmutableDictionary(data => data.MovieId, ToResponseMovieData);
}
private void InitializeDanData(List<DanData>? danData)
{
danData.ThrowIfNull("Shouldn't happen!");
danDataDictionary = danData.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData);
}
private void InitializeGaidenData(List<DanData>? gaidenData)
{
gaidenData.ThrowIfNull("Shouldn't happen!");
gaidenDataDictionary = gaidenData.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData);
}
private void InitializeEventFolderData(List<EventFolderData>? eventFolderData)
{
eventFolderData.ThrowIfNull("Shouldn't happen!");
folderDictionary = eventFolderData.ToImmutableDictionary(data => data.FolderId, ToResponseEventFolderData);
}
private void InitializeMusicInfoes(MusicInfoes? infoesData)
{
infoesData.ThrowIfNull("Shouldn't happen!");
musicInfoes = infoesData.MusicInfoEntries.ToImmutableDictionary(info => info.MusicId);
musics = musicInfoes.Select(pair => pair.Key)
.ToList();
musics.Sort();
musicsWithUra = musicInfoes.Where(info => info.Value.starUra > 0)
.Select(pair => pair.Key)
.ToList();
musicsWithUra.Sort();
}
private void InitializeShopFolderData(List<ShopFolderData>? shopFolderData)
{
shopFolderData.ThrowIfNull("Shouldn't happen!");
foreach (var folderData in shopFolderData)
{
shopFolderList.Add(ToResponseShopFolderData(folderData));
}
}
private void InitializeTokenData(Dictionary<string, int>? tokenData)
{
tokenData.ThrowIfNull("Shouldn't happen!");
tokenDataDictionary = tokenData;
}
private void InitializeLockedSongsData(Dictionary<string, uint[]>? lockedSongsData)
{
lockedSongsData.ThrowIfNull("Shouldn't happen!");
lockedSongsList = lockedSongsData["songNo"].ToList();
}
private void InitializeCostumeFlagArraySizes(DonCosRewards? donCosRewardData)
{
donCosRewardData.ThrowIfNull("Shouldn't happen!");
var kigurumiUniqueIdList = donCosRewardData.DonCosRewardEntries
.Where(entry => entry.cosType == "kigurumi")
.Select(entry => entry.uniqueId);
var headUniqueIdList = donCosRewardData.DonCosRewardEntries
.Where(entry => entry.cosType == "head")
.Select(entry => entry.uniqueId);
var bodyUniqueIdList = donCosRewardData.DonCosRewardEntries
.Where(entry => entry.cosType == "body")
.Select(entry => entry.uniqueId);
var faceUniqueIdList = donCosRewardData.DonCosRewardEntries
.Where(entry => entry.cosType == "face")
.Select(entry => entry.uniqueId);
var puchiUniqueIdList = donCosRewardData.DonCosRewardEntries
.Where(entry => entry.cosType == "puchi")
.Select(entry => entry.uniqueId);
costumeFlagArraySizes = new List<int>
{
(int)kigurumiUniqueIdList.Max() + 1,
(int)headUniqueIdList.Max() + 1,
(int)bodyUniqueIdList.Max() + 1,
(int)faceUniqueIdList.Max() + 1,
(int)puchiUniqueIdList.Max() + 1
};
}
private void InitializeTitleFlagArraySize(Shougous? shougouData)
{
shougouData.ThrowIfNull("Shouldn't happen!");
titleFlagArraySize = (int)shougouData.ShougouEntries.Max(entry => entry.uniqueId) + 1;
}
private void InitializeToneFlagArraySize(Neiros? neiroData)
{
neiroData.ThrowIfNull("Shouldn't happen!");
toneFlagArraySize = (int)neiroData.NeiroEntries.Max(entry => entry.uniqueId) + 1;
}
private void InitializeQrCodeData(List<QRCodeData>? qrCodeData)
{
qrCodeData.ThrowIfNull("Shouldn't happen!");
qrCodeDataDictionary = qrCodeData.ToImmutableDictionary(data => data.Serial, data => data.Id);
}
private static GetDanOdaiResponse.OdaiData ToResponseOdaiData(DanData data)
{
var responseOdaiData = new GetDanOdaiResponse.OdaiData
{
DanId = data.DanId,
Title = data.Title,
VerupNo = data.VerupNo
};
var odaiSongs = data.OdaiSongList.Select(song => song.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiSong>());
responseOdaiData.AryOdaiSongs.AddRange(odaiSongs);
var odaiBorders = data.OdaiBorderList.Select(border => border.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiBorder>());
responseOdaiData.AryOdaiBorders.AddRange(odaiBorders);
return responseOdaiData;
}
private static GetSongIntroductionResponse.SongIntroductionData ToResponseIntroData(SongIntroductionData data)
{
var responseIntroData = new GetSongIntroductionResponse.SongIntroductionData
{
SetId = data.SetId,
VerupNo = data.VerupNo,
MainSongNo = data.MainSongNo,
SubSongNoes = data.SubSongNo
};
return responseIntroData;
}
private static InitialdatacheckResponse.MovieData ToResponseMovieData(MovieData data)
{
var responseMovieData = new InitialdatacheckResponse.MovieData
{
MovieId = data.MovieId,
EnableDays = data.EnableDays
};
return responseMovieData;
}
private static GetfolderResponse.EventfolderData ToResponseEventFolderData(EventFolderData data)
{
var responseEventFolderData = new GetfolderResponse.EventfolderData
{
FolderId = data.FolderId,
VerupNo = data.VerupNo,
Priority = data.Priority,
SongNoes = data.SongNo,
ParentFolderId = data.ParentFolderId
};
return responseEventFolderData;
}
private static GetShopFolderResponse.ShopFolderData ToResponseShopFolderData(ShopFolderData data)
{
var responseShopFolderData = new GetShopFolderResponse.ShopFolderData
{
SongNo = data.SongNo,
Price = data.Price
};
return responseShopFolderData;
}
} }

View File

@ -4,9 +4,9 @@ namespace TaikoLocalServer.Services.Interfaces;
public interface IAiDatumService public interface IAiDatumService
{ {
public Task<List<AiScoreDatum>> GetAllAiScoreById(uint baid); public Task<List<AiScoreDatum>> GetAllAiScoreById(ulong baid);
public Task<AiScoreDatum?> GetSongAiScore(uint baid, uint songId, Difficulty difficulty); public Task<AiScoreDatum?> GetSongAiScore(ulong baid, uint songId, Difficulty difficulty);
public Task UpdateSongAiScore(AiScoreDatum datum); public Task UpdateSongAiScore(AiScoreDatum datum);

View File

@ -5,13 +5,15 @@ namespace TaikoLocalServer.Services.Interfaces;
public interface ICardService public interface ICardService
{ {
public Task<Card?> GetCardByAccessCode(string accessCode); public Task<Card?> GetCardByAccessCode(string accessCode);
public uint GetNextBaid(); public ulong GetNextBaid();
public Task<List<User>> GetUsersFromCards(); public Task<List<User>> GetUsersFromCards();
public Task AddCard(Card card); public Task AddCard(Card card);
public Task<bool> DeleteCard(string accessCode); public Task<bool> DeleteCard(string accessCode);
public Task<bool> UpdatePassword(string accessCode, string password, string salt);
} }

View File

@ -4,9 +4,9 @@ namespace TaikoLocalServer.Services.Interfaces;
public interface IDanScoreDatumService public interface IDanScoreDatumService
{ {
public Task<List<DanScoreDatum>> GetDanScoreDatumByBaid(uint baid); public Task<List<DanScoreDatum>> GetDanScoreDatumByBaid(ulong baid);
public Task<DanScoreDatum?> GetSingleDanScoreDatum(uint baid, uint danId); public Task<DanScoreDatum?> GetSingleDanScoreDatum(ulong baid, uint danId);
public Task InsertOrUpdateDanScoreDatum(DanScoreDatum datum); public Task InsertOrUpdateDanScoreDatum(DanScoreDatum datum);
} }

View File

@ -1,21 +1,40 @@
using System.Collections.Immutable; using System.Collections.Immutable;
using SharedProject.Models;
namespace TaikoLocalServer.Services.Interfaces; namespace TaikoLocalServer.Services.Interfaces;
public interface IGameDataService public interface IGameDataService
{ {
public Task InitializeAsync(); public Task InitializeAsync();
public List<uint> GetMusicList();
public List<uint> GetMusicWithUraList(); public List<uint> GetMusicList();
public ImmutableDictionary<uint, MusicAttributeEntry> GetMusicAttributes(); public List<uint> GetMusicWithUraList();
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary(); public ImmutableDictionary<uint, MusicInfoEntry> GetMusicInfoes();
public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary(); public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary();
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetGaidenDataDictionary();
public ImmutableDictionary<uint, GetfolderResponse.EventfolderData> GetFolderDictionary(); public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary();
public ImmutableDictionary<uint, InitialdatacheckResponse.MovieData> GetMovieDataDictionary();
public ImmutableDictionary<uint, GetfolderResponse.EventfolderData> GetFolderDictionary();
public List<GetShopFolderResponse.ShopFolderData> GetShopFolderList();
public Dictionary<string, int> GetTokenDataDictionary();
public List<uint> GetLockedSongsList();
public List<int> GetCostumeFlagArraySizes();
public int GetTitleFlagArraySize();
public int GetToneFlagArraySize();
public ImmutableDictionary<string, uint> GetQRCodeDataDictionary();
} }

View File

@ -5,9 +5,9 @@ namespace TaikoLocalServer.Services.Interfaces;
public interface ISongBestDatumService public interface ISongBestDatumService
{ {
public Task<List<SongBestDatum>> GetAllSongBestData(uint baid); public Task<List<SongBestDatum>> GetAllSongBestData(ulong baid);
public Task UpdateOrInsertSongBestDatum(SongBestDatum datum); public Task UpdateOrInsertSongBestDatum(SongBestDatum datum);
public Task<List<SongBestData>> GetAllSongBestAsModel(uint baid); public Task<List<SongBestData>> GetAllSongBestAsModel(ulong baid);
} }

View File

@ -4,7 +4,7 @@ namespace TaikoLocalServer.Services.Interfaces;
public interface ISongPlayDatumService public interface ISongPlayDatumService
{ {
public Task<List<SongPlayDatum>> GetSongPlayDatumByBaid(uint baid); public Task<List<SongPlayDatum>> GetSongPlayDatumByBaid(ulong baid);
public Task AddSongPlayDatum(SongPlayDatum datum); public Task AddSongPlayDatum(SongPlayDatum datum);
} }

View File

@ -4,21 +4,21 @@ namespace TaikoLocalServer.Services.Interfaces;
public interface IUserDatumService public interface IUserDatumService
{ {
public Task<UserDatum?> GetFirstUserDatumOrNull(uint baid); public Task<UserDatum?> GetFirstUserDatumOrNull(ulong baid);
public Task<UserDatum> GetFirstUserDatumOrDefault(uint baid);
public Task<List<UserDatum>> GetAllUserData(); public Task<UserDatum> GetFirstUserDatumOrDefault(ulong baid);
public Task UpdateOrInsertUserDatum(UserDatum userDatum); public Task<List<UserDatum>> GetAllUserData();
public Task InsertUserDatum(UserDatum userDatum); public Task UpdateOrInsertUserDatum(UserDatum userDatum);
public Task UpdateUserDatum(UserDatum userDatum); public Task InsertUserDatum(UserDatum userDatum);
public Task UpdateUserDatum(UserDatum userDatum);
public Task<List<uint>> GetFavoriteSongIds(ulong baid);
public Task UpdateFavoriteSong(ulong baid, uint songId, bool isFavorite);
public Task<List<uint>> GetFavoriteSongIds(uint baid);
public Task UpdateFavoriteSong(uint baid, uint songId, bool isFavorite);
} }

View File

@ -15,7 +15,7 @@ public class SongBestDatumService : ISongBestDatumService
this.context = context; this.context = context;
} }
public async Task<List<SongBestDatum>> GetAllSongBestData(uint baid) public async Task<List<SongBestDatum>> GetAllSongBestData(ulong baid)
{ {
return await context.SongBestData.Where(datum => datum.Baid == baid).ToListAsync(); return await context.SongBestData.Where(datum => datum.Baid == baid).ToListAsync();
} }
@ -37,7 +37,7 @@ public class SongBestDatumService : ISongBestDatumService
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
public async Task<List<SongBestData>> GetAllSongBestAsModel(uint baid) public async Task<List<SongBestData>> GetAllSongBestAsModel(ulong baid)
{ {
var songbestDbData = await context.SongBestData.Where(datum => datum.Baid == baid) var songbestDbData = await context.SongBestData.Where(datum => datum.Baid == baid)
.ToListAsync(); .ToListAsync();

View File

@ -12,7 +12,7 @@ class SongPlayDatumService : ISongPlayDatumService
this.context = context; this.context = context;
} }
public async Task<List<SongPlayDatum>> GetSongPlayDatumByBaid(uint baid) public async Task<List<SongPlayDatum>> GetSongPlayDatumByBaid(ulong baid)
{ {
return await context.SongPlayData.Where(datum => datum.Baid == baid).ToListAsync(); return await context.SongPlayData.Where(datum => datum.Baid == baid).ToListAsync();
} }

View File

@ -17,12 +17,12 @@ public class UserDatumService : IUserDatumService
this.logger = logger; this.logger = logger;
} }
public async Task<UserDatum?> GetFirstUserDatumOrNull(uint baid) public async Task<UserDatum?> GetFirstUserDatumOrNull(ulong baid)
{ {
return await context.UserData.FindAsync(baid); return await context.UserData.FindAsync(baid);
} }
public async Task<UserDatum> GetFirstUserDatumOrDefault(uint baid) public async Task<UserDatum> GetFirstUserDatumOrDefault(ulong baid)
{ {
return await context.UserData.FindAsync(baid) ?? new UserDatum(); return await context.UserData.FindAsync(baid) ?? new UserDatum();
} }
@ -57,7 +57,7 @@ public class UserDatumService : IUserDatumService
await context.SaveChangesAsync(); await context.SaveChangesAsync();
} }
public async Task<List<uint>> GetFavoriteSongIds(uint baid) public async Task<List<uint>> GetFavoriteSongIds(ulong baid)
{ {
var userDatum = await context.UserData.FindAsync(baid); var userDatum = await context.UserData.FindAsync(baid);
userDatum.ThrowIfNull($"User with baid: {baid} not found!"); userDatum.ThrowIfNull($"User with baid: {baid} not found!");
@ -77,7 +77,7 @@ public class UserDatumService : IUserDatumService
return result; return result;
} }
public async Task UpdateFavoriteSong(uint baid, uint songId, bool isFavorite) public async Task UpdateFavoriteSong(ulong baid, uint songId, bool isFavorite)
{ {
var userDatum = await context.UserData.FindAsync(baid); var userDatum = await context.UserData.FindAsync(baid);
userDatum.ThrowIfNull($"User with baid: {baid} not found!"); userDatum.ThrowIfNull($"User with baid: {baid} not found!");

Some files were not shown because too many files have changed in this diff Show More