commit
c5e6626422
@ -1,491 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using GameDatabase.Context;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GameDatabase.Migrations
|
||||
{
|
||||
[DbContext(typeof(TaikoDbContext))]
|
||||
[Migration("20240203182355_AddUnlockedUraSongIdListToUserDatum")]
|
||||
partial class AddUnlockedUraSongIdListToUserDatum
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "8.0.0-rc.2.23480.1");
|
||||
|
||||
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("Baid");
|
||||
|
||||
b.ToTable("Card", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Password")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Salt")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Baid");
|
||||
|
||||
b.ToTable("Credential", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DanId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DanType")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<uint>("ArrivalSongCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ClearState")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(0u);
|
||||
|
||||
b.Property<uint>("ComboCountTotal")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SoulGaugeTotal")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Baid", "DanId", "DanType");
|
||||
|
||||
b.ToTable("DanScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
|
||||
{
|
||||
b.Property<ulong>("Baid")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DanId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("DanType")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER")
|
||||
.HasDefaultValue(1);
|
||||
|
||||
b.Property<uint>("SongNumber")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("BadCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ComboCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("DrumrollCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("GoodCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("HighScore")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("OkCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("PlayScore")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("TotalHitCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Baid", "DanId", "DanType", "SongNumber");
|
||||
|
||||
b.ToTable("DanStageScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
|
||||
{
|
||||
b.Property<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")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("AchievementDisplayDifficulty")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("AiWinCount")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ColorBody")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ColorFace")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("ColorLimb")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("CostumeData")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("CostumeFlgArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<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>("IsAdmin")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsSkipOn")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsVoiceOn")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("LastPlayDatetime")
|
||||
.HasColumnType("datetime");
|
||||
|
||||
b.Property<uint>("LastPlayMode")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("MyDonName")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("MyDonNameLanguage")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("NotesPosition")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<short>("OptionSetting")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<uint>("SelectedToneId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TitleFlgArray")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<uint>("TitlePlateId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("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.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.AiScoreDatum", "Parent")
|
||||
.WithMany("AiSectionScoreData")
|
||||
.HasForeignKey("Baid", "SongId", "Difficulty")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Parent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Credential", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.DanScoreDatum", "Parent")
|
||||
.WithMany("DanStageScoreData")
|
||||
.HasForeignKey("Baid", "DanId", "DanType")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Parent");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
|
||||
{
|
||||
b.HasOne("GameDatabase.Entities.UserDatum", "Ba")
|
||||
.WithMany()
|
||||
.HasForeignKey("Baid")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Ba");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
|
||||
{
|
||||
b.Navigation("AiSectionScoreData");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanScoreDatum", b =>
|
||||
{
|
||||
b.Navigation("DanStageScoreData");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace GameDatabase.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddUnlockedUraSongIdListToUserDatum : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -40,7 +40,12 @@ namespace GameDatabase.Migrations
|
||||
});
|
||||
foreach (var (baid, tokenCountDict) in tokenJsons)
|
||||
{
|
||||
var tokenDict = JsonSerializer.Deserialize<Dictionary<int, int>>(tokenCountDict);
|
||||
Dictionary<int, int> tokenDict;
|
||||
if (string.IsNullOrEmpty(tokenCountDict)) {
|
||||
tokenDict = new();
|
||||
} else {
|
||||
tokenDict = JsonSerializer.Deserialize<Dictionary<int, int>>(tokenCountDict);
|
||||
}
|
||||
foreach (var (key, value) in tokenDict)
|
||||
{
|
||||
migrationBuilder.InsertData(
|
||||
|
@ -48,11 +48,11 @@ namespace GameDatabase.Migrations
|
||||
// Split the costumeflgarray into separate fields
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE UserData
|
||||
SET UnlockedKigurumi = json_extract(CostumeFlgArray, '$[0]'),
|
||||
UnlockedHead = json_extract(CostumeFlgArray, '$[1]'),
|
||||
UnlockedBody = json_extract(CostumeFlgArray, '$[2]'),
|
||||
UnlockedFace = json_extract(CostumeFlgArray, '$[3]'),
|
||||
UnlockedPuchi = json_extract(CostumeFlgArray, '$[4]')");
|
||||
SET UnlockedKigurumi = coalesce(json_extract(CostumeFlgArray, '$[0]'), '[]'),
|
||||
UnlockedHead = coalesce(json_extract(CostumeFlgArray, '$[1]'), '[]'),
|
||||
UnlockedBody = coalesce(json_extract(CostumeFlgArray, '$[2]'), '[]'),
|
||||
UnlockedFace = coalesce(json_extract(CostumeFlgArray, '$[3]'), '[]'),
|
||||
UnlockedPuchi = coalesce(json_extract(CostumeFlgArray, '$[4]'), '[]')");
|
||||
// Deduplicate values
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE UserData
|
||||
|
@ -47,11 +47,12 @@ namespace GameDatabase.Migrations
|
||||
// Split CostumeData (json array) into the new fields
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE UserData
|
||||
SET CurrentKigurumi = json_extract(CostumeData, '$[0]'),
|
||||
CurrentHead = json_extract(CostumeData, '$[1]'),
|
||||
CurrentBody = json_extract(CostumeData, '$[2]'),
|
||||
CurrentFace = json_extract(CostumeData, '$[3]'),
|
||||
CurrentPuchi = json_extract(CostumeData, '$[4]')");
|
||||
SET CurrentKigurumi = COALESCE(json_extract(CostumeData, '$[0]'), 0),
|
||||
CurrentHead = COALESCE(json_extract(CostumeData, '$[1]'), 0),
|
||||
CurrentBody = COALESCE(json_extract(CostumeData, '$[2]'), 0),
|
||||
CurrentFace = COALESCE(json_extract(CostumeData, '$[3]'), 0),
|
||||
CurrentPuchi = COALESCE(json_extract(CostumeData, '$[4]'), 0);
|
||||
");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
@ -52,15 +52,17 @@ namespace GameDatabase.Migrations
|
||||
nullable: false,
|
||||
defaultValue: 0u);
|
||||
|
||||
|
||||
// Extract from json arrays
|
||||
migrationBuilder.Sql(@"
|
||||
UPDATE UserData
|
||||
SET DifficultyPlayedCourse = json_extract(DifficultyPlayedArray, '$[0]'),
|
||||
DifficultyPlayedStar = json_extract(DifficultyPlayedArray, '$[1]'),
|
||||
DifficultyPlayedSort = json_extract(DifficultyPlayedArray, '$[2]') ,
|
||||
DifficultySettingCourse = json_extract(DifficultySettingArray, '$[0]'),
|
||||
DifficultySettingStar = json_extract(DifficultySettingArray, '$[1]'),
|
||||
DifficultySettingSort = json_extract(DifficultySettingArray, '$[2]');
|
||||
SET
|
||||
DifficultyPlayedCourse = COALESCE(json_extract(DifficultyPlayedArray, '$[0]'), 0),
|
||||
DifficultyPlayedStar = COALESCE(json_extract(DifficultyPlayedArray, '$[1]'), 0),
|
||||
DifficultyPlayedSort = COALESCE(json_extract(DifficultyPlayedArray, '$[2]'), 0),
|
||||
DifficultySettingCourse = COALESCE(json_extract(DifficultySettingArray, '$[0]'), 0),
|
||||
DifficultySettingStar = COALESCE(json_extract(DifficultySettingArray, '$[1]'), 0),
|
||||
DifficultySettingSort = COALESCE(json_extract(DifficultySettingArray, '$[2]'), 0);
|
||||
");
|
||||
}
|
||||
|
||||
|
25
SharedProject/Models/Costume.cs
Normal file
25
SharedProject/Models/Costume.cs
Normal file
@ -0,0 +1,25 @@
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class Costume
|
||||
{
|
||||
public uint CostumeId { get; set; }
|
||||
|
||||
public string CostumeType { get; init; } = string.Empty;
|
||||
|
||||
public string CostumeName { get; init; } = string.Empty;
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
if (obj is Costume costume)
|
||||
{
|
||||
return costume.CostumeName.Equals(CostumeName) && costume.CostumeType.Equals(CostumeType);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return CostumeName.GetHashCode();
|
||||
}
|
||||
}
|
@ -1,4 +1,6 @@
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
using SharedProject.Enums;
|
||||
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class MusicDetail
|
||||
{
|
@ -1,4 +1,4 @@
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class Title
|
||||
{
|
@ -4,6 +4,8 @@ namespace SharedProject.Models;
|
||||
|
||||
public class UserSetting
|
||||
{
|
||||
public uint Baid { get; set; }
|
||||
|
||||
public uint ToneId { get; set; }
|
||||
|
||||
public bool IsDisplayAchievement { get; set; }
|
||||
|
@ -2,27 +2,27 @@
|
||||
|
||||
public static class Constants
|
||||
{
|
||||
public const string DATE_TIME_FORMAT = "yyyyMMddHHmmss";
|
||||
public const string DateTimeFormat = "yyyyMMddHHmmss";
|
||||
|
||||
public const int MUSIC_ID_MAX = 1600;
|
||||
public const int MusicIdMax = 1600;
|
||||
|
||||
public const int MUSIC_ID_MAX_EXPANDED = 9000;
|
||||
public const int MusicIdMaxExpanded = 9000;
|
||||
|
||||
public const string DEFAULT_DB_NAME = "taiko.db3";
|
||||
public const string DefaultDbName = "taiko.db3";
|
||||
|
||||
public const string MUSIC_INFO_BASE_NAME = "musicinfo";
|
||||
public const string WORDLIST_BASE_NAME = "wordlist";
|
||||
public const string MUSIC_ORDER_BASE_NAME = "music_order";
|
||||
public const string DON_COS_REWARD_BASE_NAME = "don_cos_reward";
|
||||
public const string SHOUGOU_BASE_NAME = "shougou";
|
||||
public const string NEIRO_BASE_NAME = "neiro";
|
||||
public const string MusicInfoBaseName = "musicinfo";
|
||||
public const string WordlistBaseName = "wordlist";
|
||||
public const string MusicOrderBaseName = "music_order";
|
||||
public const string DonCosRewardBaseName = "don_cos_reward";
|
||||
public const string ShougouBaseName = "shougou";
|
||||
public const string NeiroBaseName = "neiro";
|
||||
|
||||
public const uint DAN_VERUP_MASTER_TYPE = 101;
|
||||
public const uint GAIDEN_VERUP_MASTER_TYPE = 102;
|
||||
public const uint FOLDER_VERUP_MASTER_TYPE = 103;
|
||||
public const uint INTRO_VERUP_MASTER_TYPE = 105;
|
||||
public const uint DanVerupMasterType = 101;
|
||||
public const uint GaidenVerupMasterType = 102;
|
||||
public const uint FolderVerupMasterType = 103;
|
||||
public const uint IntroVerupMasterType = 105;
|
||||
|
||||
public const uint FUNCTION_ID_DANI_FOLDER_AVAILABLE = 1;
|
||||
public const uint FUNCTION_ID_DANI_AVAILABLE = 2;
|
||||
public const uint FUNCTION_ID_AI_BATTLE_AVAILABLE = 3;
|
||||
public const uint FunctionIdDaniFolderAvailable = 1;
|
||||
public const uint FunctionIdDaniAvailable = 2;
|
||||
public const uint FunctionIdAiBattleAvailable = 3;
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SharedProject.Models.Requests;
|
||||
using TaikoLocalServer.Filters;
|
||||
|
93
TaikoLocalServer/Controllers/Api/GameDataController.cs
Normal file
93
TaikoLocalServer/Controllers/Api/GameDataController.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using TaikoLocalServer.Filters;
|
||||
using TaikoLocalServer.Settings;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class GameDataController(IGameDataService gameDataService, IAuthService authService,
|
||||
IOptions<AuthSettings> settings) : BaseController<UsersController>
|
||||
{
|
||||
private readonly AuthSettings authSettings = settings.Value;
|
||||
|
||||
[HttpGet("MusicDetails")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public IActionResult GetMusicDetails()
|
||||
{
|
||||
if (authSettings.LoginRequired)
|
||||
{
|
||||
var tokenInfo = authService.ExtractTokenInfo(HttpContext);
|
||||
if (tokenInfo is null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(gameDataService.GetMusicDetailDictionary());
|
||||
}
|
||||
|
||||
[HttpGet("Costumes")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public IActionResult GetCostumes()
|
||||
{
|
||||
if (authSettings.LoginRequired)
|
||||
{
|
||||
var tokenInfo = authService.ExtractTokenInfo(HttpContext);
|
||||
if (tokenInfo is null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(gameDataService.GetCostumeList());
|
||||
}
|
||||
|
||||
[HttpGet("Titles")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public IActionResult GetTitles()
|
||||
{
|
||||
if (authSettings.LoginRequired)
|
||||
{
|
||||
var tokenInfo = authService.ExtractTokenInfo(HttpContext);
|
||||
if (tokenInfo is null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(gameDataService.GetTitleDictionary());
|
||||
}
|
||||
|
||||
[HttpGet("LockedCostumes")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public IActionResult GetLockedCostumes()
|
||||
{
|
||||
if (authSettings.LoginRequired)
|
||||
{
|
||||
var tokenInfo = authService.ExtractTokenInfo(HttpContext);
|
||||
if (tokenInfo is null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(gameDataService.GetLockedCostumeDataDictionary());
|
||||
}
|
||||
|
||||
[HttpGet("LockedTitles")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public IActionResult GetLockedTitles()
|
||||
{
|
||||
if (authSettings.LoginRequired)
|
||||
{
|
||||
var tokenInfo = authService.ExtractTokenInfo(HttpContext);
|
||||
if (tokenInfo is null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(gameDataService.GetLockedTitleDataDictionary());
|
||||
}
|
||||
}
|
@ -7,14 +7,93 @@ using TaikoLocalServer.Settings;
|
||||
namespace TaikoLocalServer.Controllers.Api;
|
||||
|
||||
[ApiController]
|
||||
[Route("/api/[controller]/{baid}")]
|
||||
[Route("/api/[controller]")]
|
||||
public class UserSettingsController(IUserDatumService userDatumService, IAuthService authService,
|
||||
IOptions<AuthSettings> settings) : BaseController<UserSettingsController>
|
||||
{
|
||||
private readonly AuthSettings authSettings = settings.Value;
|
||||
|
||||
|
||||
[HttpGet]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public async Task<ActionResult<List<UserSetting>>> GetAllUserSetting()
|
||||
{
|
||||
if (authSettings.LoginRequired)
|
||||
{
|
||||
var tokenInfo = authService.ExtractTokenInfo(HttpContext);
|
||||
if (tokenInfo is null)
|
||||
{
|
||||
return Unauthorized();
|
||||
}
|
||||
|
||||
if (!tokenInfo.Value.isAdmin)
|
||||
{
|
||||
return Forbid();
|
||||
}
|
||||
}
|
||||
|
||||
var users = await userDatumService.GetAllUserDatum();
|
||||
|
||||
var response = new List<UserSetting>();
|
||||
|
||||
foreach (var user in users)
|
||||
{
|
||||
List<List<uint>> costumeUnlockData =
|
||||
[user.UnlockedKigurumi, user.UnlockedHead, user.UnlockedBody, user.UnlockedFace, user.UnlockedPuchi];
|
||||
|
||||
var unlockedTitle = user.TitleFlgArray
|
||||
.ToList();
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
{
|
||||
if (!costumeUnlockData[i].Contains(0))
|
||||
{
|
||||
costumeUnlockData[i].Add(0);
|
||||
}
|
||||
}
|
||||
|
||||
var userSetting = new UserSetting
|
||||
{
|
||||
Baid = user.Baid,
|
||||
AchievementDisplayDifficulty = user.AchievementDisplayDifficulty,
|
||||
IsDisplayAchievement = user.DisplayAchievement,
|
||||
IsDisplayDanOnNamePlate = user.DisplayDan,
|
||||
DifficultySettingCourse = user.DifficultySettingCourse,
|
||||
DifficultySettingStar = user.DifficultySettingStar,
|
||||
DifficultySettingSort = user.DifficultySettingSort,
|
||||
IsVoiceOn = user.IsVoiceOn,
|
||||
IsSkipOn = user.IsSkipOn,
|
||||
NotesPosition = user.NotesPosition,
|
||||
PlaySetting = PlaySettingConverter.ShortToPlaySetting(user.OptionSetting),
|
||||
ToneId = user.SelectedToneId,
|
||||
MyDonName = user.MyDonName,
|
||||
MyDonNameLanguage = user.MyDonNameLanguage,
|
||||
Title = user.Title,
|
||||
TitlePlateId = user.TitlePlateId,
|
||||
Kigurumi = user.CurrentKigurumi,
|
||||
Head = user.CurrentHead,
|
||||
Body = user.CurrentBody,
|
||||
Face = user.CurrentFace,
|
||||
Puchi = user.CurrentPuchi,
|
||||
UnlockedKigurumi = costumeUnlockData[0],
|
||||
UnlockedHead = costumeUnlockData[1],
|
||||
UnlockedBody = costumeUnlockData[2],
|
||||
UnlockedFace = costumeUnlockData[3],
|
||||
UnlockedPuchi = costumeUnlockData[4],
|
||||
UnlockedTitle = unlockedTitle,
|
||||
BodyColor = user.ColorBody,
|
||||
FaceColor = user.ColorFace,
|
||||
LimbColor = user.ColorLimb,
|
||||
LastPlayDateTime = user.LastPlayDatetime
|
||||
};
|
||||
response.Add(userSetting);
|
||||
}
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
|
||||
[HttpGet("{baid}")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public async Task<ActionResult<UserSetting>> GetUserSetting(uint baid)
|
||||
{
|
||||
if (authSettings.LoginRequired)
|
||||
@ -54,6 +133,7 @@ public class UserSettingsController(IUserDatumService userDatumService, IAuthSer
|
||||
|
||||
var response = new UserSetting
|
||||
{
|
||||
Baid = user.Baid,
|
||||
AchievementDisplayDifficulty = user.AchievementDisplayDifficulty,
|
||||
IsDisplayAchievement = user.DisplayAchievement,
|
||||
IsDisplayDanOnNamePlate = user.DisplayDan,
|
||||
@ -88,7 +168,7 @@ public class UserSettingsController(IUserDatumService userDatumService, IAuthSer
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("{baid}")]
|
||||
[ServiceFilter(typeof(AuthorizeIfRequiredAttribute))]
|
||||
public async Task<IActionResult> SaveUserSetting(uint baid, UserSetting userSetting)
|
||||
{
|
||||
|
@ -58,7 +58,7 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
||||
{
|
||||
var songBestData = await songBestDatumService.GetAllSongBestData(baid);
|
||||
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MusicIdMaxExpanded : Constants.MusicIdMax;
|
||||
var crown = new ushort[songIdMax + 1];
|
||||
var dondafulCrown = new byte[songIdMax + 1];
|
||||
|
||||
|
@ -49,7 +49,7 @@ public class GetScoreRankController(ISongBestDatumService songBestDatumService,
|
||||
|
||||
private async Task<ScoreRankData> Handle(uint baid)
|
||||
{
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MusicIdMaxExpanded : Constants.MusicIdMax;
|
||||
var kiwamiScores = new byte[songIdMax + 1];
|
||||
var miyabiScores = new ushort[songIdMax + 1];
|
||||
var ikiScores = new ushort[songIdMax + 1];
|
||||
|
@ -15,8 +15,8 @@ public class GetTelopController : BaseController<GetTelopController>
|
||||
var response = new GettelopResponse
|
||||
{
|
||||
Result = 1,
|
||||
StartDatetime = startDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
EndDatetime = endDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
StartDatetime = startDateTime.ToString(Constants.DateTimeFormat),
|
||||
EndDatetime = endDateTime.ToString(Constants.DateTimeFormat),
|
||||
Telop = "Hello 3906",
|
||||
VerupNo = 1
|
||||
};
|
||||
@ -36,8 +36,8 @@ public class GetTelopController : BaseController<GetTelopController>
|
||||
var response = new Models.v3209.GettelopResponse
|
||||
{
|
||||
Result = 1,
|
||||
StartDatetime = startDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
EndDatetime = endDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
StartDatetime = startDateTime.ToString(Constants.DateTimeFormat),
|
||||
EndDatetime = endDateTime.ToString(Constants.DateTimeFormat),
|
||||
Telop = "Hello 3209",
|
||||
VerupNo = 1
|
||||
};
|
||||
|
@ -127,7 +127,7 @@ public class BaidQueryHandler(
|
||||
GotDanMax = maxDan,
|
||||
GotGaidenFlg = gotGaidenFlagArray,
|
||||
IsDispAchievementOn = userData.DisplayAchievement,
|
||||
LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DateTimeFormat),
|
||||
LastPlayMode = userData.LastPlayMode,
|
||||
SelectedToneId = userData.SelectedToneId,
|
||||
Title = userData.Title,
|
||||
|
@ -17,7 +17,7 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService,
|
||||
|
||||
public Task<CommonInitialDataCheckResponse> Handle(GetInitialDataQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MusicIdMaxExpanded : Constants.MusicIdMax;
|
||||
|
||||
var musicList = gameDataService.GetMusicList();
|
||||
var lockedSongsList = gameDataService.GetLockedSongsList();
|
||||
@ -39,7 +39,7 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService,
|
||||
DefaultSongFlg = defaultSongFlg,
|
||||
AchievementSongBit = enabledArray,
|
||||
UraReleaseBit = uraReleaseBit,
|
||||
SongIntroductionEndDatetime = DateTime.Now.AddYears(10).ToString(Constants.DATE_TIME_FORMAT),
|
||||
SongIntroductionEndDatetime = DateTime.Now.AddYears(10).ToString(Constants.DateTimeFormat),
|
||||
ServerCurrentDatetime = (ulong)DateTimeOffset.Now.ToUnixTimeSeconds()
|
||||
};
|
||||
|
||||
@ -65,18 +65,18 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService,
|
||||
|
||||
CommonInitialDataCheckResponse.VerupNoData2[] verupNo2List =
|
||||
[
|
||||
GetVerupNoData2(Constants.DAN_VERUP_MASTER_TYPE, commonDanDataDictionary),
|
||||
GetVerupNoData2(Constants.GAIDEN_VERUP_MASTER_TYPE, commonGaidenDataDictionary),
|
||||
GetVerupNoData2(Constants.FOLDER_VERUP_MASTER_TYPE, eventFolderDictionary),
|
||||
GetVerupNoData2(Constants.INTRO_VERUP_MASTER_TYPE, songIntroDictionary)
|
||||
GetVerupNoData2(Constants.DanVerupMasterType, commonDanDataDictionary),
|
||||
GetVerupNoData2(Constants.GaidenVerupMasterType, commonGaidenDataDictionary),
|
||||
GetVerupNoData2(Constants.FolderVerupMasterType, eventFolderDictionary),
|
||||
GetVerupNoData2(Constants.IntroVerupMasterType, songIntroDictionary)
|
||||
];
|
||||
response.AryVerupNoData2s.AddRange(verupNo2List);
|
||||
|
||||
response.AryChassisFunctionIds =
|
||||
[
|
||||
Constants.FUNCTION_ID_DANI_AVAILABLE,
|
||||
Constants.FUNCTION_ID_DANI_FOLDER_AVAILABLE,
|
||||
Constants.FUNCTION_ID_AI_BATTLE_AVAILABLE
|
||||
Constants.FunctionIdDaniAvailable,
|
||||
Constants.FunctionIdDaniFolderAvailable,
|
||||
Constants.FunctionIdAiBattleAvailable
|
||||
];
|
||||
|
||||
return Task.FromResult(response);
|
||||
|
@ -5,7 +5,7 @@ namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetSelfBestQuery(uint Baid, uint Difficulty, uint[] SongIdList) : IRequest<CommonSelfBestResponse>;
|
||||
|
||||
public class GetSelfBestQueryHandler(IGameDataService gameDataService, TaikoDbContext context, ILogger<GetSelfBestQueryHandler> logger)
|
||||
public class GetSelfBestQueryHandler(IGameDataService gameDataService, TaikoDbContext context, ILogger<GetSelfBestQueryHandler> logger)
|
||||
: IRequestHandler<GetSelfBestQuery, CommonSelfBestResponse>
|
||||
{
|
||||
public async Task<CommonSelfBestResponse> Handle(GetSelfBestQuery request, CancellationToken cancellationToken)
|
||||
@ -21,28 +21,38 @@ public class GetSelfBestQueryHandler(IGameDataService gameDataService, TaikoDbCo
|
||||
logger.LogWarning("Invalid song IDs: {InvalidSongIds}", invalidSongIds.Stringify());
|
||||
requestSet.ExceptWith(invalidSongIds);
|
||||
}
|
||||
|
||||
var selfbestScores = await context.SongBestData
|
||||
.Where(datum => datum.Baid == request.Baid &&
|
||||
|
||||
var selfBestScores = await context.SongBestData
|
||||
.Where(datum => datum.Baid == request.Baid &&
|
||||
requestSet.Contains(datum.SongId) &&
|
||||
(datum.Difficulty == requestDifficulty ||
|
||||
(datum.Difficulty == requestDifficulty ||
|
||||
(datum.Difficulty == Difficulty.UraOni && requestDifficulty == Difficulty.Oni)))
|
||||
.OrderBy(datum => datum.SongId)
|
||||
.ToListAsync(cancellationToken);
|
||||
var selfBestList = selfbestScores.ConvertAll(datum => new CommonSelfBestResponse.SelfBestData
|
||||
var selfBestList = new List<CommonSelfBestResponse.SelfBestData>();
|
||||
foreach (var songId in request.SongIdList)
|
||||
{
|
||||
SongNo = datum.SongId,
|
||||
SelfBestScore = datum.BestScore,
|
||||
UraBestScore = datum.Difficulty == Difficulty.UraOni ? datum.BestScore : 0,
|
||||
SelfBestScoreRate = datum.BestRate,
|
||||
UraBestScoreRate = datum.Difficulty == Difficulty.UraOni ? datum.BestRate : 0
|
||||
});
|
||||
// For songs that don't have a score, add them to the response with 0s
|
||||
var missingSongs = requestSet.Except(selfBestList.Select(datum => datum.SongNo));
|
||||
selfBestList.AddRange(missingSongs.Select(songNo => new CommonSelfBestResponse.SelfBestData
|
||||
{
|
||||
SongNo = songNo
|
||||
}));
|
||||
var selfBest = new CommonSelfBestResponse.SelfBestData();
|
||||
var selfBestScore = selfBestScores
|
||||
.FirstOrDefault(datum => datum.SongId == songId &&
|
||||
datum.Difficulty == requestDifficulty);
|
||||
var uraSelfBestScore = selfBestScores
|
||||
.FirstOrDefault(datum => datum.SongId == songId &&
|
||||
datum.Difficulty == Difficulty.UraOni && requestDifficulty == Difficulty.Oni);
|
||||
|
||||
selfBest.SongNo = songId;
|
||||
if (selfBestScore is not null)
|
||||
{
|
||||
selfBest.SelfBestScore = selfBestScore.BestScore;
|
||||
selfBest.SelfBestScoreRate = selfBestScore.BestRate;
|
||||
}
|
||||
if (uraSelfBestScore is not null)
|
||||
{
|
||||
selfBest.UraBestScore = uraSelfBestScore.BestScore;
|
||||
selfBest.UraBestScoreRate = uraSelfBestScore.BestRate;
|
||||
}
|
||||
|
||||
selfBestList.Add(selfBest);
|
||||
}
|
||||
|
||||
var response = new CommonSelfBestResponse
|
||||
{
|
||||
|
@ -18,7 +18,7 @@ public class UpdatePlayResultCommandHandler(TaikoDbContext context, ILogger<Upda
|
||||
var user = await context.UserData.FindAsync([request.Baid], cancellationToken);
|
||||
if (user is null)
|
||||
{
|
||||
logger.LogWarning("Game uploading a non exisiting user with baid {Baid}", request.Baid);
|
||||
logger.LogWarning("Game uploading a non existing user with baid {Baid}", request.Baid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -29,6 +29,11 @@ public class UpdatePlayResultCommandHandler(TaikoDbContext context, ILogger<Upda
|
||||
var playMode = (PlayMode)playResultData.PlayMode;
|
||||
if (playMode is PlayMode.DanMode or PlayMode.GaidenMode)
|
||||
{
|
||||
if (playResultData.IsNotRecordedDan)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
var danType = playMode == PlayMode.DanMode ? DanType.Normal : DanType.Gaiden;
|
||||
var danPlayData = await context.DanScoreData
|
||||
.Include(datum => datum.DanStageScoreData)
|
||||
|
@ -22,12 +22,12 @@ public class UserDataQueryHandler(TaikoDbContext context, IGameDataService gameD
|
||||
lockedSongsList = lockedSongsList.Except(unlockedSongIdList).ToList();
|
||||
var enabledMusicList = musicList.Except(lockedSongsList);
|
||||
var releaseSongArray =
|
||||
FlagCalculator.GetBitArrayFromIds(enabledMusicList, Constants.MUSIC_ID_MAX, logger);
|
||||
FlagCalculator.GetBitArrayFromIds(enabledMusicList, Constants.MusicIdMax, logger);
|
||||
|
||||
var defaultSongWithUraList = gameDataService.GetMusicWithUraList();
|
||||
var enabledUraMusicList = defaultSongWithUraList.Except(lockedSongsList);
|
||||
var uraSongArray =
|
||||
FlagCalculator.GetBitArrayFromIds(enabledUraMusicList, Constants.MUSIC_ID_MAX, logger);
|
||||
FlagCalculator.GetBitArrayFromIds(enabledUraMusicList, Constants.MusicIdMax, logger);
|
||||
|
||||
if (userData.ToneFlgArray.Count == 0)
|
||||
{
|
||||
|
@ -16,7 +16,7 @@ public class CommonBaidResponse
|
||||
public List<byte[]> CostumeFlagArrays { get; set; }
|
||||
= new() { Array.Empty<byte>(), Array.Empty<byte>(), Array.Empty<byte>(), Array.Empty<byte>(), Array.Empty<byte>() };
|
||||
|
||||
public string LastPlayDatetime { get; set; } = DateTime.Now.ToString(Constants.DATE_TIME_FORMAT);
|
||||
public string LastPlayDatetime { get; set; } = DateTime.Now.ToString(Constants.DateTimeFormat);
|
||||
public bool DisplayDan { get; set; }
|
||||
public uint GotDanMax { get; set; }
|
||||
public byte[] GotDanFlg { get; set; } = Array.Empty<byte>();
|
||||
|
@ -10,7 +10,7 @@ public class CommonInitialDataCheckResponse
|
||||
public byte[] UraReleaseBit { get; set; } = [];
|
||||
|
||||
public string SongIntroductionEndDatetime { get; set; } =
|
||||
DateTime.Now.AddYears(10).ToString(Constants.DATE_TIME_FORMAT);
|
||||
DateTime.Now.AddYears(10).ToString(Constants.DateTimeFormat);
|
||||
|
||||
public List<MovieData> AryMovieInfoes { get; set; } = [];
|
||||
public List<AiEventData> AryAiEventDatas { get; set; } = [];
|
||||
|
@ -4,9 +4,27 @@ namespace TaikoLocalServer.Models;
|
||||
|
||||
public class MusicInfoEntry
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("uniqueId")]
|
||||
public uint MusicId { get; set; }
|
||||
|
||||
[JsonPropertyName("genreNo")]
|
||||
public SongGenre Genre { get; set; }
|
||||
|
||||
[JsonPropertyName("starEasy")]
|
||||
public int StarEasy { get; set; }
|
||||
|
||||
[JsonPropertyName("starNormal")]
|
||||
public int StarNormal { get; set; }
|
||||
|
||||
[JsonPropertyName("starHard")]
|
||||
public int StarHard { get; set; }
|
||||
|
||||
[JsonPropertyName("starMania")]
|
||||
public int StarOni { get; set; }
|
||||
|
||||
[JsonPropertyName("starUra")]
|
||||
public uint StarUra { get; set; }
|
||||
public int StarUra { get; set; }
|
||||
}
|
@ -15,6 +15,8 @@ using Serilog;
|
||||
using SharedProject.Utils;
|
||||
using TaikoLocalServer.Controllers.Api;
|
||||
using TaikoLocalServer.Filters;
|
||||
using Microsoft.AspNetCore.ResponseCompression;
|
||||
using System.IO.Compression;
|
||||
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.WriteTo.Console()
|
||||
@ -29,14 +31,14 @@ Log.Information("Server starting up...");
|
||||
try
|
||||
{
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
|
||||
builder.Services.AddHttpLogging(options =>
|
||||
{
|
||||
options.LoggingFields = HttpLoggingFields.All;
|
||||
options.RequestBodyLogLimit = 32768;
|
||||
options.ResponseBodyLogLimit = 32768;
|
||||
});
|
||||
|
||||
|
||||
const string configurationsDirectory = "Configurations";
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/Kestrel.json", optional: true, reloadOnChange: false);
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/Logging.json", optional: false, reloadOnChange: false);
|
||||
@ -44,8 +46,8 @@ try
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/ServerSettings.json", optional: false, reloadOnChange: false);
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/DataSettings.json", optional: true, reloadOnChange: false);
|
||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/AuthSettings.json", optional: true, reloadOnChange: false);
|
||||
builder.Configuration.AddJsonFile("wwwroot/appsettings.json", optional: true, reloadOnChange: true); // Add appsettings.json
|
||||
|
||||
builder.Configuration.AddJsonFile("wwwroot/appsettings.json", optional: false, reloadOnChange: false);
|
||||
|
||||
builder.Host.UseSerilog((context, configuration) =>
|
||||
{
|
||||
configuration
|
||||
@ -65,6 +67,19 @@ try
|
||||
Log.Warning("Song limit expanded! Use at your own risk!");
|
||||
}
|
||||
|
||||
// Add response compression services
|
||||
builder.Services.AddResponseCompression(options =>
|
||||
{
|
||||
options.EnableForHttps = true;
|
||||
options.Providers.Add<GzipCompressionProvider>();
|
||||
options.Providers.Add<BrotliCompressionProvider>();
|
||||
});
|
||||
|
||||
builder.Services.Configure<GzipCompressionProviderOptions>(options =>
|
||||
{
|
||||
options.Level = CompressionLevel.Fastest;
|
||||
});
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
|
||||
builder.Services.AddOptions();
|
||||
@ -73,39 +88,38 @@ try
|
||||
builder.Services.Configure<DataSettings>(builder.Configuration.GetSection(nameof(DataSettings)));
|
||||
builder.Services.Configure<AuthSettings>(builder.Configuration.GetSection(nameof(AuthSettings)));
|
||||
|
||||
// Read LoginRequired setting from appsettings.json
|
||||
var loginRequired = builder.Configuration.GetValue<bool>("LoginRequired");
|
||||
var loginRequired = builder.Configuration.GetSection("WebUiSettings").GetValue<bool>("LoginRequired");
|
||||
builder.Services.Configure<AuthSettings>(options => { options.LoginRequired = loginRequired; });
|
||||
|
||||
// Add Authentication with JWT
|
||||
builder.Services.AddAuthentication(options =>
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||
})
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = builder.Configuration.GetSection(nameof(AuthSettings))["JwtIssuer"],
|
||||
ValidAudience = builder.Configuration.GetSection(nameof(AuthSettings))["JwtAudience"],
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration.GetSection(nameof(AuthSettings))["JwtKey"] ?? throw new InvalidOperationException()))
|
||||
};
|
||||
});
|
||||
ValidateIssuer = true,
|
||||
ValidateAudience = true,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidIssuer = builder.Configuration.GetSection(nameof(AuthSettings))["JwtIssuer"],
|
||||
ValidAudience = builder.Configuration.GetSection(nameof(AuthSettings))["JwtAudience"],
|
||||
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration.GetSection(nameof(AuthSettings))["JwtKey"] ?? throw new InvalidOperationException()))
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddScoped<AuthorizeIfRequiredAttribute>(); // Register the custom attribute
|
||||
|
||||
|
||||
builder.Services.AddControllers().AddProtoBufNet();
|
||||
builder.Services.AddDbContext<TaikoDbContext>(option =>
|
||||
{
|
||||
var dbName = builder.Configuration["DbFileName"];
|
||||
if (string.IsNullOrEmpty(dbName))
|
||||
{
|
||||
dbName = Constants.DEFAULT_DB_NAME;
|
||||
dbName = Constants.DefaultDbName;
|
||||
}
|
||||
|
||||
var path = Path.Combine(PathHelper.GetRootPath(), dbName);
|
||||
@ -148,6 +162,9 @@ try
|
||||
gameDataService.ThrowIfNull();
|
||||
await gameDataService.InitializeAsync();
|
||||
|
||||
// Use response compression
|
||||
app.UseResponseCompression();
|
||||
|
||||
// For reverse proxy
|
||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||
{
|
||||
@ -159,22 +176,28 @@ try
|
||||
app.UseBlazorFrameworkFiles();
|
||||
app.UseStaticFiles();
|
||||
app.UseRouting();
|
||||
|
||||
|
||||
// Enable Authentication and Authorization middleware
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
|
||||
app.UseHttpLogging();
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
await next();
|
||||
|
||||
if (context.Response.StatusCode >= 400)
|
||||
|
||||
if (context.Response.StatusCode == StatusCodes.Status404NotFound)
|
||||
{
|
||||
Log.Error("Unknown request from: {RemoteIpAddress} {Method} {Path} {StatusCode}",
|
||||
context.Connection.RemoteIpAddress, context.Request.Method, context.Request.Path, context.Response.StatusCode);
|
||||
Log.Error("Request headers: {Headers}", context.Request.Headers);
|
||||
}
|
||||
else if (context.Response.StatusCode != StatusCodes.Status200OK)
|
||||
{
|
||||
Log.Warning("Unsuccessful request from: {RemoteIpAddress} {Method} {Path} {StatusCode}",
|
||||
context.Connection.RemoteIpAddress, context.Request.Method, context.Request.Path, context.Response.StatusCode);
|
||||
Log.Warning("Request headers: {Headers}", context.Request.Headers);
|
||||
}
|
||||
});
|
||||
app.MapControllers();
|
||||
app.MapFallbackToFile("index.html");
|
||||
|
@ -6,11 +6,12 @@ using System.IO.Compression;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text.Json;
|
||||
using TaikoLocalServer.Settings;
|
||||
using TaikoWebUI.Shared.Models;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Services;
|
||||
|
||||
public class GameDataService : IGameDataService
|
||||
public class GameDataService(IOptions<DataSettings> dataSettings) : IGameDataService
|
||||
{
|
||||
private ImmutableDictionary<uint, DanData> commonDanDataDictionary =
|
||||
ImmutableDictionary<uint, DanData>.Empty;
|
||||
@ -18,7 +19,7 @@ public class GameDataService : IGameDataService
|
||||
private ImmutableDictionary<uint, DanData> commonGaidenDataDictionary =
|
||||
ImmutableDictionary<uint, DanData>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, MusicInfoEntry> musicInfoes =
|
||||
private ImmutableDictionary<uint, MusicInfoEntry> musicInfos =
|
||||
ImmutableDictionary<uint, MusicInfoEntry>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, MovieData> movieDataDictionary =
|
||||
@ -32,37 +33,42 @@ public class GameDataService : IGameDataService
|
||||
private ImmutableDictionary<uint, EventFolderData> eventFolderDictionary =
|
||||
ImmutableDictionary<uint, EventFolderData>.Empty;
|
||||
|
||||
private List<ShopFolderData> shopFolderList = new();
|
||||
private List<ShopFolderData> shopFolderList = [];
|
||||
|
||||
private List<uint> musics = new();
|
||||
private List<uint> musicUniqueIdList = [];
|
||||
|
||||
private List<uint> musicsWithUra = new();
|
||||
private List<uint> musicWithUraUniqueIdList = [];
|
||||
|
||||
private List<uint> lockedSongsList = new();
|
||||
private List<uint> lockedSongsList = [];
|
||||
|
||||
private readonly Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||
|
||||
private List<int> costumeFlagArraySizes = new();
|
||||
private readonly List<Costume> costumeList = [];
|
||||
|
||||
private readonly Dictionary<uint, Title> titleDictionary = new();
|
||||
|
||||
private Dictionary<string, List<uint>> lockedCostumeDataDictionary = new();
|
||||
|
||||
private Dictionary<string, List<uint>> lockedTitleDataDictionary = new();
|
||||
|
||||
private List<int> costumeFlagArraySize = [];
|
||||
|
||||
private int titleFlagArraySize;
|
||||
|
||||
private int toneFlagArraySize;
|
||||
|
||||
private Dictionary<string, int> tokenDataDictionary = new();
|
||||
|
||||
private readonly DataSettings settings;
|
||||
|
||||
public GameDataService(IOptions<DataSettings> settings)
|
||||
{
|
||||
this.settings = settings.Value;
|
||||
}
|
||||
private readonly DataSettings settings = dataSettings.Value;
|
||||
|
||||
public List<uint> GetMusicList()
|
||||
{
|
||||
return musics;
|
||||
return musicUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetMusicWithUraList()
|
||||
{
|
||||
return musicsWithUra;
|
||||
return musicWithUraUniqueIdList;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, MovieData> GetMovieDataDictionary()
|
||||
@ -104,10 +110,35 @@ public class GameDataService : IGameDataService
|
||||
{
|
||||
return lockedSongsList;
|
||||
}
|
||||
|
||||
public Dictionary<uint, MusicDetail> GetMusicDetailDictionary()
|
||||
{
|
||||
return musicDetailDictionary;
|
||||
}
|
||||
|
||||
public List<Costume> GetCostumeList()
|
||||
{
|
||||
return costumeList;
|
||||
}
|
||||
|
||||
public Dictionary<uint, Title> GetTitleDictionary()
|
||||
{
|
||||
return titleDictionary;
|
||||
}
|
||||
|
||||
public Dictionary<string, List<uint>> GetLockedCostumeDataDictionary()
|
||||
{
|
||||
return lockedCostumeDataDictionary;
|
||||
}
|
||||
|
||||
public Dictionary<string, List<uint>> GetLockedTitleDataDictionary()
|
||||
{
|
||||
return lockedTitleDataDictionary;
|
||||
}
|
||||
|
||||
public List<int> GetCostumeFlagArraySizes()
|
||||
{
|
||||
return costumeFlagArraySizes;
|
||||
return costumeFlagArraySize;
|
||||
}
|
||||
|
||||
public int GetTitleFlagArraySize()
|
||||
@ -130,23 +161,23 @@ public class GameDataService : IGameDataService
|
||||
var dataPath = PathHelper.GetDataPath();
|
||||
var datatablePath = PathHelper.GetDatatablePath();
|
||||
|
||||
var musicInfoPath = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.json");
|
||||
var encryptedInfo = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.bin");
|
||||
var musicInfoPath = Path.Combine(datatablePath, $"{Constants.MusicInfoBaseName}.json");
|
||||
var encryptedInfo = Path.Combine(datatablePath, $"{Constants.MusicInfoBaseName}.bin");
|
||||
|
||||
var wordlistPath = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.json");
|
||||
var encryptedWordlist = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.bin");
|
||||
var wordlistPath = Path.Combine(datatablePath, $"{Constants.WordlistBaseName}.json");
|
||||
var encryptedWordlist = Path.Combine(datatablePath, $"{Constants.WordlistBaseName}.bin");
|
||||
|
||||
var musicOrderPath = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.json");
|
||||
var encryptedMusicOrder = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.bin");
|
||||
var musicOrderPath = Path.Combine(datatablePath, $"{Constants.MusicOrderBaseName}.json");
|
||||
var encryptedMusicOrder = Path.Combine(datatablePath, $"{Constants.MusicOrderBaseName}.bin");
|
||||
|
||||
var donCosRewardPath = Path.Combine(datatablePath, $"{Constants.DON_COS_REWARD_BASE_NAME}.json");
|
||||
var encryptedDonCosReward = Path.Combine(datatablePath, $"{Constants.DON_COS_REWARD_BASE_NAME}.bin");
|
||||
var donCosRewardPath = Path.Combine(datatablePath, $"{Constants.DonCosRewardBaseName}.json");
|
||||
var encryptedDonCosReward = Path.Combine(datatablePath, $"{Constants.DonCosRewardBaseName}.bin");
|
||||
|
||||
var shougouPath = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.json");
|
||||
var encryptedShougou = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.bin");
|
||||
var shougouPath = Path.Combine(datatablePath, $"{Constants.ShougouBaseName}.json");
|
||||
var encryptedShougou = Path.Combine(datatablePath, $"{Constants.ShougouBaseName}.bin");
|
||||
|
||||
var neiroPath = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.json");
|
||||
var encryptedNeiro = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.bin");
|
||||
var neiroPath = Path.Combine(datatablePath, $"{Constants.NeiroBaseName}.json");
|
||||
var encryptedNeiro = Path.Combine(datatablePath, $"{Constants.NeiroBaseName}.bin");
|
||||
|
||||
var danDataPath = Path.Combine(dataPath, settings.DanDataFileName);
|
||||
var gaidenDataPath = Path.Combine(dataPath, settings.GaidenDataFileName);
|
||||
@ -157,6 +188,8 @@ public class GameDataService : IGameDataService
|
||||
var tokenDataPath = Path.Combine(dataPath, settings.TokenDataFileName);
|
||||
var lockedSongsDataPath = Path.Combine(dataPath, settings.LockedSongsDataFileName);
|
||||
var qrCodeDataPath = Path.Combine(dataPath, settings.QrCodeDataFileName);
|
||||
var lockedCostumeDataPath = Path.Combine(dataPath, settings.LockedCostumeDataFileName);
|
||||
var lockedTitleDataPath = Path.Combine(dataPath, settings.LockedTitleDataFileName);
|
||||
|
||||
var encryptedFiles = new List<string>
|
||||
{
|
||||
@ -186,12 +219,9 @@ public class GameDataService : IGameDataService
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var filePath in outputPaths)
|
||||
foreach (var filePath in outputPaths.Where(filePath => !File.Exists(filePath)))
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
throw new FileNotFoundException($"{Path.GetFileName(filePath)} file not found!");
|
||||
}
|
||||
throw new FileNotFoundException($"{Path.GetFileName(filePath)} file not found!");
|
||||
}
|
||||
|
||||
await using var musicInfoFile = File.OpenRead(musicInfoPath);
|
||||
@ -207,8 +237,12 @@ public class GameDataService : IGameDataService
|
||||
await using var shougouFile = File.OpenRead(shougouPath);
|
||||
await using var neiroFile = File.OpenRead(neiroPath);
|
||||
await using var qrCodeDataFile = File.OpenRead(qrCodeDataPath);
|
||||
await using var wordlistFile = File.OpenRead(wordlistPath);
|
||||
await using var musicOrderFile = File.OpenRead(musicOrderPath);
|
||||
await using var lockedCostumeDataFile = File.OpenRead(lockedCostumeDataPath);
|
||||
await using var lockedTitleDataFile = File.OpenRead(lockedTitleDataPath);
|
||||
|
||||
var infosData = await JsonSerializer.DeserializeAsync<MusicInfos>(musicInfoFile);
|
||||
var musicInfoData = await JsonSerializer.DeserializeAsync<MusicInfos>(musicInfoFile);
|
||||
var danData = await JsonSerializer.DeserializeAsync<List<DanData>>(danDataFile);
|
||||
var gaidenData = await JsonSerializer.DeserializeAsync<List<DanData>>(gaidenDataFile);
|
||||
var introData = await JsonSerializer.DeserializeAsync<List<SongIntroductionData>>(songIntroDataFile);
|
||||
@ -221,8 +255,12 @@ public class GameDataService : IGameDataService
|
||||
var shougouData = await JsonSerializer.DeserializeAsync<Shougous>(shougouFile);
|
||||
var neiroData = await JsonSerializer.DeserializeAsync<Neiros>(neiroFile);
|
||||
var qrCodeData = await JsonSerializer.DeserializeAsync<List<QRCodeData>>(qrCodeDataFile);
|
||||
var wordlistData = await JsonSerializer.DeserializeAsync<WordList>(wordlistFile);
|
||||
var musicOrderData = await JsonSerializer.DeserializeAsync<MusicOrder>(musicOrderFile);
|
||||
var lockedCostumeData = await JsonSerializer.DeserializeAsync<Dictionary<string, uint[]>>(lockedCostumeDataFile);
|
||||
var lockedTitleData = await JsonSerializer.DeserializeAsync<Dictionary<string, uint[]>>(lockedTitleDataFile);
|
||||
|
||||
InitializeMusicInfos(infosData);
|
||||
InitializeMusicInfos(musicInfoData);
|
||||
|
||||
InitializeDanData(danData);
|
||||
|
||||
@ -239,10 +277,16 @@ public class GameDataService : IGameDataService
|
||||
InitializeTokenData(tokenData);
|
||||
|
||||
InitializeLockedSongsData(lockedSongsData);
|
||||
|
||||
InitializeMusicDetails(musicInfoData, musicOrderData, wordlistData);
|
||||
|
||||
InitializeCostumeFlagArraySizes(donCosRewardData);
|
||||
InitializeCostumes(donCosRewardData, wordlistData);
|
||||
|
||||
InitializeTitleFlagArraySize(shougouData);
|
||||
InitializeTitles(shougouData, wordlistData);
|
||||
|
||||
InitializeLockedCostumeData(lockedCostumeData);
|
||||
|
||||
InitializeLockedTitleData(lockedTitleData);
|
||||
|
||||
InitializeToneFlagArraySize(neiroData);
|
||||
|
||||
@ -304,16 +348,16 @@ public class GameDataService : IGameDataService
|
||||
{
|
||||
infosData.ThrowIfNull("Shouldn't happen!");
|
||||
|
||||
musicInfoes = infosData.MusicInfoEntries.ToImmutableDictionary(info => info.MusicId);
|
||||
musicInfos = infosData.MusicInfoEntries.ToImmutableDictionary(info => info.MusicId);
|
||||
|
||||
musics = musicInfoes.Select(pair => pair.Key)
|
||||
musicUniqueIdList = musicInfos.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
musics.Sort();
|
||||
musicUniqueIdList.Sort();
|
||||
|
||||
musicsWithUra = musicInfoes.Where(info => info.Value.StarUra > 0)
|
||||
musicWithUraUniqueIdList = musicInfos.Where(info => info.Value.StarUra > 0)
|
||||
.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
musicsWithUra.Sort();
|
||||
musicWithUraUniqueIdList.Sort();
|
||||
}
|
||||
|
||||
private void InitializeShopFolderData(List<ShopFolderData>? shopFolderData)
|
||||
@ -333,40 +377,132 @@ public class GameDataService : IGameDataService
|
||||
lockedSongsData.ThrowIfNull("Shouldn't happen!");
|
||||
lockedSongsList = lockedSongsData["songNo"].ToList();
|
||||
}
|
||||
|
||||
private void InitializeCostumeFlagArraySizes(DonCosRewards? donCosRewardData)
|
||||
|
||||
private void InitializeMusicDetails(MusicInfos? musicInfoData, MusicOrder? musicOrderData, WordList? wordlistData)
|
||||
{
|
||||
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>
|
||||
musicInfoData.ThrowIfNull("Shouldn't happen!");
|
||||
musicOrderData.ThrowIfNull("Shouldn't happen!");
|
||||
wordlistData.ThrowIfNull("Shouldn't happen!");
|
||||
|
||||
foreach (var musicInfo in musicInfoData.MusicInfoEntries)
|
||||
{
|
||||
(int)kigurumiUniqueIdList.Max() + 1,
|
||||
(int)headUniqueIdList.Max() + 1,
|
||||
(int)bodyUniqueIdList.Max() + 1,
|
||||
(int)faceUniqueIdList.Max() + 1,
|
||||
(int)puchiUniqueIdList.Max() + 1
|
||||
};
|
||||
var musicUniqueId = musicInfo.MusicId;
|
||||
if (musicUniqueId == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var musicId = musicInfo.Id;
|
||||
var musicNameKey = $"song_{musicId}";
|
||||
var musicArtistKey = $"song_sub_{musicId}";
|
||||
var musicName = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).JapaneseText;
|
||||
var musicArtist = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).JapaneseText;
|
||||
var musicNameEn = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).EnglishUsText;
|
||||
var musicArtistEn = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).EnglishUsText;
|
||||
var musicNameCn = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).ChineseTText;
|
||||
var musicArtistCn = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).ChineseTText;
|
||||
var musicNameKo = wordlistData.WordListEntries.First(entry => entry.Key == musicNameKey).KoreanText;
|
||||
var musicArtistKo = wordlistData.WordListEntries.First(entry => entry.Key == musicArtistKey).KoreanText;
|
||||
var musicGenre = musicInfo.Genre;
|
||||
var musicStarEasy = musicInfo.StarEasy;
|
||||
var musicStarNormal = musicInfo.StarNormal;
|
||||
var musicStarHard = musicInfo.StarHard;
|
||||
var musicStarOni = musicInfo.StarOni;
|
||||
var musicStarUra = musicInfo.StarUra;
|
||||
var musicDetail = new MusicDetail
|
||||
{
|
||||
SongId = musicUniqueId,
|
||||
SongName = musicName,
|
||||
SongNameEN = musicNameEn,
|
||||
SongNameCN = musicNameCn,
|
||||
SongNameKO = musicNameKo,
|
||||
ArtistName = musicArtist,
|
||||
ArtistNameEN = musicArtistEn,
|
||||
ArtistNameCN = musicArtistCn,
|
||||
ArtistNameKO = musicArtistKo,
|
||||
Genre = musicGenre,
|
||||
StarEasy = musicStarEasy,
|
||||
StarNormal = musicStarNormal,
|
||||
StarHard = musicStarHard,
|
||||
StarOni = musicStarOni,
|
||||
StarUra = musicStarUra
|
||||
};
|
||||
musicDetailDictionary.TryAdd(musicUniqueId, musicDetail);
|
||||
}
|
||||
|
||||
for (var index = 0; index < musicOrderData.Order.Count; index++)
|
||||
{
|
||||
var musicOrderEntry = musicOrderData.Order[index];
|
||||
var musicUniqueId = musicOrderEntry.SongId;
|
||||
if (musicDetailDictionary.TryGetValue(musicUniqueId, out var musicDetail))
|
||||
{
|
||||
musicDetail.Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeTitleFlagArraySize(Shougous? shougouData)
|
||||
private void InitializeCostumes(DonCosRewards? donCosRewardData, WordList? wordlistData)
|
||||
{
|
||||
donCosRewardData.ThrowIfNull("Shouldn't happen!");
|
||||
wordlistData.ThrowIfNull("Shouldn't happen!");
|
||||
|
||||
foreach (var donCosReward in donCosRewardData.DonCosRewardEntries)
|
||||
{
|
||||
var cosType = donCosReward.CosType;
|
||||
var costumeId = donCosReward.UniqueId;
|
||||
|
||||
var costumeNameKey = $"costume_{cosType}_{costumeId}";
|
||||
var costumeName = wordlistData.WordListEntries.First(entry => entry.Key == costumeNameKey).JapaneseText;
|
||||
var costume = new Costume
|
||||
{
|
||||
CostumeId = costumeId,
|
||||
CostumeType = cosType,
|
||||
CostumeName = costumeName
|
||||
};
|
||||
costumeList.Add(costume);
|
||||
}
|
||||
|
||||
var kigurumiMaxArraySize = (int)costumeList.Where(costume => costume.CostumeType == "kigurumi").Max(costume => costume.CostumeId) + 1;
|
||||
var headMaxArraySize = (int)costumeList.Where(costume => costume.CostumeType == "head").Max(costume => costume.CostumeId) + 1;
|
||||
var bodyMaxArraySize = (int)costumeList.Where(costume => costume.CostumeType == "body").Max(costume => costume.CostumeId) + 1;
|
||||
var faceMaxArraySize = (int)costumeList.Where(costume => costume.CostumeType == "face").Max(costume => costume.CostumeId) + 1;
|
||||
var puchiMaxArraySize = (int)costumeList.Where(costume => costume.CostumeType == "puchi").Max(costume => costume.CostumeId) + 1;
|
||||
costumeFlagArraySize =
|
||||
[kigurumiMaxArraySize, headMaxArraySize, bodyMaxArraySize, faceMaxArraySize, puchiMaxArraySize];
|
||||
}
|
||||
|
||||
private void InitializeTitles(Shougous? shougouData, WordList? wordlistData)
|
||||
{
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
titleFlagArraySize = (int)shougouData.ShougouEntries.Max(entry => entry.UniqueId) + 1;
|
||||
wordlistData.ThrowIfNull("Shouldn't happen!");
|
||||
|
||||
foreach (var shougou in shougouData.ShougouEntries)
|
||||
{
|
||||
var titleId = shougou.UniqueId;
|
||||
var titleNameKey = $"syougou_{titleId}";
|
||||
var titleName = wordlistData.WordListEntries.First(entry => entry.Key == titleNameKey).JapaneseText;
|
||||
var title = new Title
|
||||
{
|
||||
TitleId = titleId,
|
||||
TitleName = titleName,
|
||||
TitleRarity = shougou.Rarity
|
||||
};
|
||||
titleDictionary.TryAdd(titleId, title);
|
||||
}
|
||||
|
||||
titleFlagArraySize = (int)titleDictionary.Max(title => title.Key) + 1;
|
||||
}
|
||||
|
||||
private void InitializeLockedCostumeData(Dictionary<string, uint[]>? lockedCostumeData)
|
||||
{
|
||||
lockedCostumeData.ThrowIfNull("Shouldn't happen!");
|
||||
lockedCostumeDataDictionary = lockedCostumeData.ToDictionary(pair => pair.Key, pair => pair.Value.ToList());
|
||||
}
|
||||
|
||||
private void InitializeLockedTitleData(Dictionary<string, uint[]>? lockedTitleData)
|
||||
{
|
||||
lockedTitleData.ThrowIfNull("Shouldn't happen!");
|
||||
lockedTitleDataDictionary = lockedTitleData.ToDictionary(pair => pair.Key, pair => pair.Value.ToList());
|
||||
}
|
||||
|
||||
private void InitializeToneFlagArraySize(Neiros? neiroData)
|
||||
|
@ -26,9 +26,19 @@ public interface IGameDataService
|
||||
public Dictionary<string, int> GetTokenDataDictionary();
|
||||
|
||||
public List<uint> GetLockedSongsList();
|
||||
|
||||
public Dictionary<uint, MusicDetail> GetMusicDetailDictionary();
|
||||
|
||||
public List<Costume> GetCostumeList();
|
||||
|
||||
public Dictionary<uint, Title> GetTitleDictionary();
|
||||
|
||||
public Dictionary<string, List<uint>> GetLockedCostumeDataDictionary();
|
||||
|
||||
public Dictionary<string, List<uint>> GetLockedTitleDataDictionary();
|
||||
|
||||
public List<int> GetCostumeFlagArraySizes();
|
||||
|
||||
|
||||
public int GetTitleFlagArraySize();
|
||||
|
||||
public int GetToneFlagArraySize();
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
public interface IUserDatumService
|
||||
{
|
||||
public Task<List<UserDatum>> GetAllUserDatum();
|
||||
|
||||
public Task<UserDatum?> GetFirstUserDatumOrNull(uint baid);
|
||||
|
||||
public Task UpdateUserDatum(UserDatum userDatum);
|
||||
|
@ -5,6 +5,11 @@ namespace TaikoLocalServer.Services;
|
||||
|
||||
public class UserDatumService(TaikoDbContext context) : IUserDatumService
|
||||
{
|
||||
public async Task<List<UserDatum>> GetAllUserDatum()
|
||||
{
|
||||
return await context.UserData.Include(d => d.Tokens).ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<UserDatum?> GetFirstUserDatumOrNull(uint baid)
|
||||
{
|
||||
return await context.UserData
|
||||
|
@ -19,6 +19,7 @@
|
||||
<PackageReference Include="MediatR" Version="12.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.ResponseCompression" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.4">
|
||||
|
@ -1,17 +1,17 @@
|
||||
{
|
||||
"Kigurumi": [
|
||||
"kigurumi": [
|
||||
|
||||
],
|
||||
"Head": [
|
||||
"head": [
|
||||
|
||||
],
|
||||
"Body": [
|
||||
"body": [
|
||||
|
||||
],
|
||||
"Face": [
|
||||
"face": [
|
||||
|
||||
],
|
||||
"Puchi": [
|
||||
"puchi": [
|
||||
|
||||
]
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
{
|
||||
"TitleNo": [
|
||||
"title": [
|
||||
|
||||
],
|
||||
"TitlePlateNo": [
|
||||
"titlePlate": [
|
||||
|
||||
]
|
||||
}
|
54
TaikoWebUI/Components/ChooseSongNameLanguage.razor
Normal file
54
TaikoWebUI/Components/ChooseSongNameLanguage.razor
Normal file
@ -0,0 +1,54 @@
|
||||
@using Blazored.LocalStorage
|
||||
@using Microsoft.Extensions.Options
|
||||
@using TaikoWebUI.Settings
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IOptions<WebUiSettings> Settings
|
||||
@inject ILocalStorageService LocalStorage
|
||||
|
||||
<MudMenu Icon="@Icons.Material.Filled.Translate" Color="Color.Inherit" Size="Size.Small" Dense="true" AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopCenter">
|
||||
<MudText Align="Align.Center" GutterBottom="true">@Localizer["Song Name"]</MudText>
|
||||
<MudDivider />
|
||||
@foreach (var culture in supportedCultures)
|
||||
{
|
||||
<MudMenuItem OnClick="() => RequestCultureChange(culture.Key)" OnTouch="() => RequestCultureChange(culture.Key)">@culture.Value</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
|
||||
@code {
|
||||
private readonly Dictionary<CultureInfo, string> supportedCultures = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
foreach (var language in Settings.Value.SupportedLanguages)
|
||||
{
|
||||
supportedCultures.Add(new CultureInfo(language.CultureCode), language.DisplayName);
|
||||
}
|
||||
|
||||
if (supportedCultures.Count == 0)
|
||||
{
|
||||
supportedCultures.Add(new CultureInfo("en-US"), "English");
|
||||
}
|
||||
|
||||
var currentSongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
|
||||
|
||||
if (string.IsNullOrEmpty(currentSongNameLanguage))
|
||||
{
|
||||
await LocalStorage.SetItemAsync("songNameLanguage", "en-US");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task RequestCultureChange(CultureInfo newCulture)
|
||||
{
|
||||
var currentSongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
|
||||
|
||||
if (currentSongNameLanguage == newCulture.Name)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
await LocalStorage.SetItemAsync("songNameLanguage", newCulture.Name);
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
}
|
||||
}
|
@ -1,31 +1,32 @@
|
||||
@using System.Globalization;
|
||||
@using Microsoft.Extensions.Options
|
||||
@using Microsoft.Extensions.Options
|
||||
@using TaikoWebUI.Settings
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject IOptions<WebUiSettings> Settings
|
||||
|
||||
<MudMenu Icon="@Icons.Material.Filled.Translate" Color="Color.Inherit" Size="Size.Small" Dense="true">
|
||||
@foreach (var culture in SupportedCultures)
|
||||
<MudMenu Icon="@Icons.Material.Filled.Language" Color="Color.Inherit" Size="Size.Small" Dense="true" AnchorOrigin="Origin.BottomCenter" TransformOrigin="Origin.TopCenter">
|
||||
<MudText Align="Align.Center" GutterBottom="true">@Localizer["UI"]</MudText>
|
||||
<MudDivider />
|
||||
@foreach (var culture in supportedCultures)
|
||||
{
|
||||
<MudMenuItem OnClick="() => RequestCultureChange(culture.Key)" OnTouch="() => RequestCultureChange(culture.Key)">@culture.Value</MudMenuItem>
|
||||
}
|
||||
</MudMenu>
|
||||
|
||||
@code {
|
||||
public Dictionary<CultureInfo, string> SupportedCultures = new();
|
||||
private Dictionary<CultureInfo, string> supportedCultures = new();
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
foreach (var language in Settings.Value.SupportedLanguages)
|
||||
{
|
||||
SupportedCultures.Add(new CultureInfo(language.CultureCode), language.DisplayName);
|
||||
supportedCultures.Add(new CultureInfo(language.CultureCode), language.DisplayName);
|
||||
}
|
||||
|
||||
if (SupportedCultures.Count == 0)
|
||||
if (supportedCultures.Count == 0)
|
||||
{
|
||||
SupportedCultures.Add(new CultureInfo("en-US"), "English");
|
||||
supportedCultures.Add(new CultureInfo("en-US"), "English");
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,9 +37,8 @@
|
||||
return;
|
||||
}
|
||||
|
||||
var js = (IJSInProcessRuntime)JSRuntime;
|
||||
var js = (IJSInProcessRuntime)JsRuntime;
|
||||
js.InvokeVoid("blazorCulture.set", newCulture.Name);
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
@inherits LayoutComponentBase
|
||||
@inject Blazored.LocalStorage.ILocalStorageService LocalStorage
|
||||
@inject HttpClient Client
|
||||
@inject AuthService AuthService
|
||||
|
||||
<MudThemeProvider IsDarkMode="@isDarkMode" Theme="@taikoWebUiTheme" />
|
||||
@ -11,9 +10,10 @@
|
||||
<MudAppBar Elevation="0">
|
||||
<MudIconButton Icon="@Icons.Material.Filled.Menu" Color="Color.Inherit" Edge="Edge.Start" OnClick="DrawerToggle" Size="Size.Small" />
|
||||
<MudSpacer />
|
||||
<MudStack Spacing="2" Row="true">
|
||||
<MudStack Spacing="3" Row="true">
|
||||
<ChooseUILanguage />
|
||||
<ChooseSongNameLanguage />
|
||||
<MudIconButton Icon="@DarkModeIcon" Size="Size.Small" Color="Color.Inherit" OnClick="ToggleDarkMode" />
|
||||
<ChooseLanguage />
|
||||
</MudStack>
|
||||
</MudAppBar>
|
||||
<MudDrawer Elevation="0" Style="border-right:1px solid #ededf0" @bind-Open="drawerOpen">
|
||||
@ -53,7 +53,7 @@
|
||||
isDarkMode = await LocalStorage.GetItemAsync<bool>("isDarkMode");
|
||||
}
|
||||
|
||||
if (AuthService.LoginRequired)
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
// If not logged in, attempt to use JwtToken from local storage to log in
|
||||
await AuthService.LoginWithAuthToken();
|
||||
|
@ -7,7 +7,7 @@
|
||||
<MudText Typo="Typo.h6">@Localizer["Play History"]</MudText>
|
||||
</MudItem>
|
||||
<MudItem xs="12" md="8">
|
||||
<MudText Typo="Typo.h6">@Localizer["Total Plays"]:@Items.Count</MudText>
|
||||
<MudText Typo="Typo.h6">@Localizer["Total Credits Played"]:@Items.Count</MudText>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudCardHeader>
|
||||
|
@ -13,9 +13,9 @@
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<div style="display:flex;flex-wrap:wrap;align-items:center;gap:5px;">
|
||||
@if (userSetting is not null)
|
||||
@if (UserSetting is not null)
|
||||
{
|
||||
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@userSetting?.MyDonName</MudText>
|
||||
<MudText Typo="Typo.h6" Style="font-weight:bold;word-break:break-all">@UserSetting?.MyDonName</MudText>
|
||||
} else
|
||||
{
|
||||
<MudSkeleton Width="35%" Height="32px" />
|
||||
@ -137,14 +137,11 @@
|
||||
|
||||
@code {
|
||||
[Parameter] public User? User { get; set; }
|
||||
private UserSetting? userSetting;
|
||||
[Parameter] public UserSetting? UserSetting { get; set; }
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
if (User is not null)
|
||||
{
|
||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{User.Baid}");
|
||||
}
|
||||
await base.OnInitializedAsync();
|
||||
}
|
||||
|
||||
private Task ShowQrCode(User user)
|
||||
|
@ -113,6 +113,15 @@ namespace TaikoWebUI.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Add {
|
||||
get {
|
||||
return ResourceManager.GetString("Add", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
@ -815,6 +824,24 @@ namespace TaikoWebUI.Localization {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string Total_Credits_Played {
|
||||
get {
|
||||
return ResourceManager.GetString("Total Credits Played", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
internal static string UI {
|
||||
get {
|
||||
return ResourceManager.GetString("UI", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to .
|
||||
/// </summary>
|
||||
|
@ -192,7 +192,7 @@
|
||||
<data name="Last Played" xml:space="preserve">
|
||||
<value>Last Played</value>
|
||||
</data>
|
||||
<data name="Total Plays" xml:space="preserve">
|
||||
<data name="Total Credits Played" xml:space="preserve">
|
||||
<value>Total Plays</value>
|
||||
</data>
|
||||
<data name="Total Clears" xml:space="preserve">
|
||||
@ -594,4 +594,10 @@
|
||||
<data name="Rows Per Page:" xml:space="preserve">
|
||||
<value>Rows Per Page:</value>
|
||||
</data>
|
||||
<data name="UI" xml:space="preserve">
|
||||
<value>UI</value>
|
||||
</data>
|
||||
<data name="Add" xml:space="preserve">
|
||||
<value>Add</value>
|
||||
</data>
|
||||
</root>
|
@ -192,7 +192,7 @@
|
||||
<data name="Last Played" xml:space="preserve">
|
||||
<value>ラストプレイ</value>
|
||||
</data>
|
||||
<data name="Total Plays" xml:space="preserve">
|
||||
<data name="Total Credits Played" xml:space="preserve">
|
||||
<value>プレイ回数</value>
|
||||
</data>
|
||||
<data name="Total Clears" xml:space="preserve">
|
||||
@ -594,4 +594,10 @@
|
||||
<data name="Rows Per Page:" xml:space="preserve">
|
||||
<value>1ページ当たりの行数</value>
|
||||
</data>
|
||||
<data name="UI" xml:space="preserve">
|
||||
<value>UI</value>
|
||||
</data>
|
||||
<data name="Add" xml:space="preserve">
|
||||
<value>追加</value>
|
||||
</data>
|
||||
</root>
|
@ -387,4 +387,13 @@
|
||||
<data name="Rows Per Page:" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Total Credits Played" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="UI" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
<data name="Add" xml:space="preserve">
|
||||
<value />
|
||||
</data>
|
||||
</root>
|
@ -192,7 +192,7 @@
|
||||
<data name="Last Played" xml:space="preserve">
|
||||
<value>最后游玩时间</value>
|
||||
</data>
|
||||
<data name="Total Plays" xml:space="preserve">
|
||||
<data name="Total Credits Played" xml:space="preserve">
|
||||
<value>总游玩次数</value>
|
||||
</data>
|
||||
<data name="Total Clears" xml:space="preserve">
|
||||
@ -591,4 +591,10 @@
|
||||
<data name="Rows Per Page:" xml:space="preserve">
|
||||
<value>每页行数</value>
|
||||
</data>
|
||||
<data name="UI" xml:space="preserve">
|
||||
<value>界面</value>
|
||||
</data>
|
||||
<data name="Add" xml:space="preserve">
|
||||
<value>添加</value>
|
||||
</data>
|
||||
</root>
|
@ -192,7 +192,7 @@
|
||||
<data name="Last Played" xml:space="preserve">
|
||||
<value>最後遊玩時間</value>
|
||||
</data>
|
||||
<data name="Total Plays" xml:space="preserve">
|
||||
<data name="Total Credits Played" xml:space="preserve">
|
||||
<value>總遊玩次數</value>
|
||||
</data>
|
||||
<data name="Total Clears" xml:space="preserve">
|
||||
@ -591,4 +591,10 @@
|
||||
<data name="Rows Per Page:" xml:space="preserve">
|
||||
<value>每頁行數</value>
|
||||
</data>
|
||||
<data name="UI" xml:space="preserve">
|
||||
<value>界面</value>
|
||||
</data>
|
||||
<data name="Add" xml:space="preserve">
|
||||
<value>添加</value>
|
||||
</data>
|
||||
</root>
|
@ -19,6 +19,12 @@ public partial class AccessCode
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
await InitializeUser();
|
||||
|
||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||
|
@ -11,6 +11,11 @@ public partial class ChangePassword
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnChangePassword()
|
||||
|
@ -1,8 +1,11 @@
|
||||
@inject IGameDataService GameDataService
|
||||
@using Blazored.LocalStorage
|
||||
|
||||
@inject IGameDataService GameDataService
|
||||
@inject HttpClient Client
|
||||
@inject AuthService AuthService
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ILocalStorageService LocalStorage
|
||||
|
||||
@page "/Users/{baid:int}/DaniDojo"
|
||||
|
||||
@ -143,17 +146,17 @@ else
|
||||
</MudTooltip>
|
||||
<MudStack Row="true" Spacing="1" Justify="Justify.Center" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Star" Size="Size.Small" />
|
||||
<MudText Typo="Typo.caption" Style="line-height:1;margin-top:2px;margin-right:2px;">@GameDataService.GetMusicStarLevel(danDataOdaiSong.SongNo, difficulty)</MudText>
|
||||
<MudText Typo="Typo.caption" Style="line-height:1;margin-top:2px;margin-right:2px;">@GameDataService.GetMusicStarLevel(musicDetailDictionary, danDataOdaiSong.SongNo, difficulty)</MudText>
|
||||
</MudStack>
|
||||
</MudItem>
|
||||
|
||||
<MudItem xs="9" md="4" Style="display:flex;flex-direction:column;" Class="pl-4">
|
||||
<MudText Typo="Typo.body1" Style="font-weight: bold;">@GameDataService.GetMusicNameBySongId(danDataOdaiSong.SongNo, @CurrentLanguage)</MudText>
|
||||
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(danDataOdaiSong.SongNo, @CurrentLanguage)</MudText>
|
||||
<MudText Typo="Typo.body1" Style="font-weight: bold;">@GameDataService.GetMusicNameBySongId(musicDetailDictionary, danDataOdaiSong.SongNo, SongNameLanguage)</MudText>
|
||||
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(musicDetailDictionary, danDataOdaiSong.SongNo, SongNameLanguage)</MudText>
|
||||
</MudItem>
|
||||
|
||||
|
||||
@if (bestDataMap.TryGetValue(danId, out var danBestData))
|
||||
@if (_bestDataMap.TryGetValue(danId, out var danBestData))
|
||||
{
|
||||
if (danBestData.DanBestStageDataList.Count > index)
|
||||
{
|
||||
@ -218,7 +221,7 @@ else
|
||||
}
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2" Style="font-weight:bold;">@Localizer["Result"]</MudText>
|
||||
@if (bestDataMap.TryGetValue(danId, out var danBestData))
|
||||
@if (_bestDataMap.TryGetValue(danId, out var danBestData))
|
||||
{
|
||||
if (danBestData.SoulGaugeTotal >= redRequirement) {
|
||||
barClass = "bar-pass-red";
|
||||
@ -288,7 +291,7 @@ else
|
||||
}
|
||||
<MudStack Spacing="1">
|
||||
<MudText Typo="Typo.subtitle2" Style="font-weight:bold;">@Localizer["Result"]</MudText>
|
||||
@if (bestDataMap.TryGetValue(danId, out var danBestData))
|
||||
@if (_bestDataMap.TryGetValue(danId, out var danBestData))
|
||||
{
|
||||
var bestData = GetAllBestFromData((DanConditionType)border.OdaiType, danBestData);
|
||||
|
||||
@ -381,7 +384,7 @@ else
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudText Typo="Typo.subtitle2" Style="font-weight:bold;">@Localizer["Result"]</MudText>
|
||||
@if (bestDataMap.TryGetValue(danId, out var danBestData) && (danBestData.DanBestStageDataList.Count > songNumber))
|
||||
@if (_bestDataMap.TryGetValue(danId, out var danBestData) && (danBestData.DanBestStageDataList.Count > songNumber))
|
||||
{
|
||||
var bestData = GetSongBestFromData((DanConditionType)border.OdaiType, danBestData, songNumber);
|
||||
if ((DanConditionType)border.OdaiType is DanConditionType.BadCount or DanConditionType.OkCount)
|
||||
|
@ -6,28 +6,37 @@ public partial class DaniDojo
|
||||
{
|
||||
[Parameter]
|
||||
public int Baid { get; set; }
|
||||
public string CurrentLanguage { get; set; } = "ja";
|
||||
|
||||
private string? SongNameLanguage { get; set; }
|
||||
|
||||
private DanBestDataResponse? response;
|
||||
private UserSetting? userSetting;
|
||||
|
||||
private static Dictionary<uint, DanBestData> bestDataMap = new();
|
||||
private static Dictionary<uint, DanBestData> _bestDataMap = new();
|
||||
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
response = await Client.GetFromJsonAsync<DanBestDataResponse>($"api/DanBestData/{Baid}");
|
||||
response.ThrowIfNull();
|
||||
response.DanBestDataList.ForEach(data => data.DanBestStageDataList
|
||||
.Sort((stageData, otherStageData) => stageData.SongNumber.CompareTo(otherStageData.SongNumber)));
|
||||
bestDataMap = response.DanBestDataList.ToDictionary(data => data.DanId);
|
||||
_bestDataMap = response.DanBestDataList.ToDictionary(data => data.DanId);
|
||||
|
||||
CurrentLanguage = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||
SongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
|
||||
|
||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||
|
||||
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||
|
||||
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
||||
{
|
||||
@ -168,12 +177,12 @@ public partial class DaniDojo
|
||||
string icon;
|
||||
const string notClearIcon = "<image href='/images/dani_NotClear.png' width='24' height='24' style='filter: contrast(0.65)'/>";
|
||||
|
||||
if (!bestDataMap.ContainsKey(danId))
|
||||
if (!_bestDataMap.ContainsKey(danId))
|
||||
{
|
||||
return notClearIcon;
|
||||
}
|
||||
|
||||
var state = bestDataMap[danId].ClearState;
|
||||
var state = _bestDataMap[danId].ClearState;
|
||||
|
||||
icon = state is DanClearState.NotClear ? notClearIcon : $"<image href='/images/dani_{state}.png' width='24' height='24' />";
|
||||
|
||||
@ -182,7 +191,7 @@ public partial class DaniDojo
|
||||
|
||||
private DanClearState GetDanResultState(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].ClearState : DanClearState.NotClear;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].ClearState : DanClearState.NotClear;
|
||||
}
|
||||
|
||||
private static uint GetSoulGauge(DanData data, bool isGold)
|
||||
@ -209,36 +218,36 @@ public partial class DaniDojo
|
||||
|
||||
private static long GetTotalScore(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.HighScore) : 0;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.HighScore) : 0;
|
||||
}
|
||||
|
||||
private static long GetTotalGoodHits(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.GoodCount) : 0;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.GoodCount) : 0;
|
||||
}
|
||||
|
||||
private static long GetTotalOkHits(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.OkCount) : 0;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.OkCount) : 0;
|
||||
}
|
||||
|
||||
private static long GetTotalBadHits(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.BadCount) : 0;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.BadCount) : 0;
|
||||
}
|
||||
|
||||
private static long GetTotalDrumrollHits(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.DrumrollCount) : 0;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.DrumrollCount) : 0;
|
||||
}
|
||||
|
||||
private static long GetTotalMaxCombo(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.ComboCount) : 0;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.ComboCount) : 0;
|
||||
}
|
||||
|
||||
private static long GetTotalHits(uint danId)
|
||||
{
|
||||
return bestDataMap.ContainsKey(danId) ? bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.TotalHitCount) : 0;
|
||||
return _bestDataMap.ContainsKey(danId) ? _bestDataMap[danId].DanBestStageDataList.Sum(stageData => stageData.TotalHitCount) : 0;
|
||||
}
|
||||
}
|
@ -1,11 +1,10 @@
|
||||
@using TaikoWebUI.Shared.Models
|
||||
@using System.Collections.Immutable
|
||||
@using System.Collections.Immutable
|
||||
@inject IGameDataService GameDataService
|
||||
@inject IJSRuntime Js
|
||||
|
||||
<MudDialog>
|
||||
<DialogContent>
|
||||
<MudTable Items="@titles" Filter="@Filter" @bind-SelectedItem="@selectedTitle" Height="40vh" Hover="true">
|
||||
<MudTable Items="@Titles" Filter="@Filter" @bind-SelectedItem="@selectedTitle" Height="40vh" Hover="true">
|
||||
<ColGroup>
|
||||
<col style="width: 50px;" />
|
||||
<col />
|
||||
@ -66,9 +65,7 @@
|
||||
public bool AllowFreeProfileEditing { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public List<uint> TitleUniqueIdList { get; set; } = new();
|
||||
|
||||
private IEnumerable<Title> titles = new List<Title>();
|
||||
public List<Title> Titles { get; set; } = new();
|
||||
|
||||
private Title? selectedTitle;
|
||||
|
||||
@ -77,28 +74,13 @@
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
base.OnInitialized();
|
||||
var titleSet = GameDataService.GetTitles();
|
||||
if (!AllowFreeProfileEditing)
|
||||
{
|
||||
var unlockedTitle = UserSetting.UnlockedTitle;
|
||||
titleSet = titleSet.Where(title => unlockedTitle.Contains(title.TitleId)).ToImmutableHashSet();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only allow titles in titleUniqueIdList
|
||||
titleSet = titleSet.Where(title => TitleUniqueIdList.Contains(title.TitleId)).ToImmutableHashSet();
|
||||
}
|
||||
titles = titleSet.ToImmutableList().Sort((title, title1) => title.TitleId.CompareTo(title1.TitleId));
|
||||
var currentTitle = new Title
|
||||
{
|
||||
TitleName = UserSetting.Title
|
||||
};
|
||||
if (titleSet.Contains(currentTitle))
|
||||
if (Titles.Contains(currentTitle))
|
||||
{
|
||||
titleSet.TryGetValue(new Title
|
||||
{
|
||||
TitleName = UserSetting.Title
|
||||
}, out selectedTitle);
|
||||
selectedTitle = currentTitle;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
@inject IGameDataService GameDataService
|
||||
@using TaikoWebUI.Utilities;
|
||||
|
||||
@inject IGameDataService GameDataService
|
||||
@inject HttpClient Client
|
||||
@inject AuthService AuthService
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject Blazored.LocalStorage.ILocalStorageService LocalStorage
|
||||
@using TaikoWebUI.Utilities;
|
||||
|
||||
@page "/Users/{baid:int}/HighScores"
|
||||
|
||||
@ -22,14 +22,7 @@
|
||||
{
|
||||
@if (AuthService.LoginRequired && (!AuthService.IsLoggedIn || (AuthService.GetLoggedInBaid() != Baid && !AuthService.IsAdmin)))
|
||||
{
|
||||
if (!AuthService.IsLoggedIn)
|
||||
{
|
||||
NavigationManager.NavigateTo("/Login");
|
||||
}
|
||||
else
|
||||
{
|
||||
NavigationManager.NavigateTo("/");
|
||||
}
|
||||
NavigationManager.NavigateTo(AuthService.IsLoggedIn ? "/" : "/Login");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -50,7 +43,7 @@
|
||||
<MudText Typo="Typo.body2" Style="font-weight:bold">@Localizer["Song Name"]</MudText>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongBestData" SortBy="x => GameDataService.GetMusicStarLevel(x.SongId, difficulty)">
|
||||
<MudTableSortLabel T="SongBestData" SortBy="x => GameDataService.GetMusicStarLevel(musicDetailDictionary, x.SongId, difficulty)">
|
||||
<MudText>@Localizer["Level"]</MudText>
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
@ -106,7 +99,7 @@
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="SongBestData" SortBy="x => x.PlayCount">
|
||||
<MudText>@Localizer["Total Plays"]</MudText>
|
||||
<MudText>@Localizer["Total Credits Played"]</MudText>
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
@ -148,7 +141,7 @@
|
||||
<MudTd>
|
||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||
<MudIcon Icon="@Icons.Material.Filled.Star" Size="Size.Small" />
|
||||
<MudText Typo="Typo.caption" Style="line-height:1;margin-top:2px;margin-right:2px;">@GameDataService.GetMusicStarLevel(context.SongId, difficulty)</MudText>
|
||||
<MudText Typo="Typo.caption" Style="line-height:1;margin-top:2px;margin-right:2px;">@GameDataService.GetMusicStarLevel(musicDetailDictionary, context.SongId, difficulty)</MudText>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
<MudTd>
|
||||
|
@ -1,9 +1,4 @@
|
||||
using static MudBlazor.Colors;
|
||||
using System;
|
||||
using Microsoft.JSInterop;
|
||||
|
||||
|
||||
namespace TaikoWebUI.Pages;
|
||||
namespace TaikoWebUI.Pages;
|
||||
|
||||
public partial class HighScores
|
||||
{
|
||||
@ -15,24 +10,32 @@ public partial class HighScores
|
||||
private Dictionary<Difficulty, List<SongBestData>> songBestDataMap = new();
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||
private int selectedDifficultyTab = 0;
|
||||
private int selectedDifficultyTab;
|
||||
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
||||
response.ThrowIfNull();
|
||||
|
||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||
|
||||
var language = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||
var songNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
|
||||
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||
|
||||
response.SongBestData.ForEach(data =>
|
||||
{
|
||||
var songId = data.SongId;
|
||||
data.Genre = GameDataService.GetMusicGenreBySongId(songId);
|
||||
data.MusicName = GameDataService.GetMusicNameBySongId(songId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(songId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||
data.Genre = GameDataService.GetMusicGenreBySongId(musicDetailDictionary, songId);
|
||||
data.MusicName = GameDataService.GetMusicNameBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(songNameLanguage) ? "ja" : songNameLanguage);
|
||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(songNameLanguage) ? "ja" : songNameLanguage);
|
||||
});
|
||||
|
||||
songBestDataMap = response.SongBestData.GroupBy(data => data.Difficulty)
|
||||
@ -40,8 +43,8 @@ public partial class HighScores
|
||||
data => data.ToList());
|
||||
foreach (var songBestDataList in songBestDataMap.Values)
|
||||
{
|
||||
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(data1.SongId)
|
||||
.CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId)));
|
||||
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data1.SongId)
|
||||
.CompareTo(GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data2.SongId)));
|
||||
}
|
||||
|
||||
// Set last selected tab from local storage
|
||||
|
@ -9,6 +9,11 @@ public partial class Login
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task OnLogin()
|
||||
|
@ -1,11 +1,11 @@
|
||||
@using Blazored.LocalStorage
|
||||
|
||||
@inject IGameDataService GameDataService
|
||||
@inject HttpClient Client
|
||||
@inject AuthService AuthService
|
||||
@inject IJSRuntime JSRuntime
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject NavigationManager NavigationManager
|
||||
@using TaikoWebUI.Utilities;
|
||||
@using TaikoWebUI.Shared.Models;
|
||||
@using SharedProject.Enums;
|
||||
@inject ILocalStorageService LocalStorage
|
||||
|
||||
@page "/Users/{baid:int}/PlayHistory"
|
||||
|
||||
@ -113,7 +113,7 @@
|
||||
ToggledSize="Size.Small"
|
||||
Title="Add to favorites" ToggledTitle="Remove from favorites" />
|
||||
</div>
|
||||
</MudStack>
|
||||
</MudStack>
|
||||
</MudTd>
|
||||
|
||||
@* Genre display *@
|
||||
|
@ -1,9 +1,5 @@
|
||||
using static MudBlazor.Colors;
|
||||
using System;
|
||||
using static MudBlazor.CategoryTypes;
|
||||
using System.Globalization;
|
||||
using System.Globalization;
|
||||
using Microsoft.JSInterop;
|
||||
using TaikoWebUI.Shared.Models;
|
||||
|
||||
namespace TaikoWebUI.Pages;
|
||||
|
||||
@ -16,7 +12,7 @@ public partial class PlayHistory
|
||||
|
||||
private string Search { get; set; } = string.Empty;
|
||||
|
||||
private string? currentLanguage;
|
||||
private string? songNameLanguage;
|
||||
|
||||
private SongHistoryResponse? response;
|
||||
|
||||
@ -24,22 +20,32 @@ public partial class PlayHistory
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||
|
||||
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
||||
response.ThrowIfNull();
|
||||
|
||||
currentLanguage = await JSRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||
songNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
|
||||
|
||||
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||
|
||||
response.SongHistoryData.ForEach(data =>
|
||||
{
|
||||
var songId = data.SongId;
|
||||
data.Genre = GameDataService.GetMusicGenreBySongId(songId);
|
||||
data.MusicName = GameDataService.GetMusicNameBySongId(songId, string.IsNullOrEmpty(currentLanguage) ? "ja" : currentLanguage);
|
||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(songId, string.IsNullOrEmpty(currentLanguage) ? "ja" : currentLanguage);
|
||||
data.Stars = GameDataService.GetMusicStarLevel(songId, data.Difficulty);
|
||||
data.Genre = GameDataService.GetMusicGenreBySongId(musicDetailDictionary, songId);
|
||||
data.MusicName = GameDataService.GetMusicNameBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(songNameLanguage) ? "ja" : songNameLanguage);
|
||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(songNameLanguage) ? "ja" : songNameLanguage);
|
||||
data.Stars = GameDataService.GetMusicStarLevel(musicDetailDictionary, songId, data.Difficulty);
|
||||
data.ShowDetails = false;
|
||||
});
|
||||
|
||||
@ -134,7 +140,7 @@ public partial class PlayHistory
|
||||
return true;
|
||||
}
|
||||
|
||||
var language = currentLanguage ?? "ja";
|
||||
var language = songNameLanguage ?? "ja";
|
||||
|
||||
if (songHistoryDataList[0].PlayTime
|
||||
.ToString("dddd d MMMM yyyy - HH:mm", CultureInfo.CreateSpecificCulture(language))
|
||||
|
@ -126,35 +126,35 @@
|
||||
<MudSelect @bind-Value="@response.Head" Label=@Localizer["Head"]>
|
||||
@foreach (var index in headUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetHeadTitle(index);
|
||||
var costumeTitle = GameDataService.GetHeadTitle(costumeList, index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Body" Label=@Localizer["Body"]>
|
||||
@foreach (var index in bodyUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetBodyTitle(index);
|
||||
var costumeTitle = GameDataService.GetBodyTitle(costumeList, index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Face" Label=@Localizer["Face"]>
|
||||
@foreach (var index in faceUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetFaceTitle(index);
|
||||
var costumeTitle = GameDataService.GetFaceTitle(costumeList, index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Kigurumi" Label=@Localizer["Kigurumi"]>
|
||||
@foreach (var index in kigurumiUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetKigurumiTitle(index);
|
||||
var costumeTitle = GameDataService.GetKigurumiTitle(costumeList, index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSelect @bind-Value="@response.Puchi" Label=@Localizer["Puchi"]>
|
||||
@foreach (var index in puchiUniqueIdList)
|
||||
{
|
||||
var costumeTitle = GameDataService.GetPuchiTitle(index);
|
||||
var costumeTitle = GameDataService.GetPuchiTitle(costumeList, index);
|
||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
|
@ -179,15 +179,31 @@ public partial class Profile
|
||||
private List<uint> puchiUniqueIdList = new();
|
||||
private List<uint> titleUniqueIdList = new();
|
||||
private List<uint> titlePlateIdList = new();
|
||||
|
||||
private List<Costume> costumeList = new();
|
||||
private Dictionary<uint, Title> titleDictionary = new();
|
||||
private Dictionary<string, List<uint>> lockedCostumeDataDictionary = new();
|
||||
private Dictionary<string, List<uint>> lockedTitleDataDictionary = new();
|
||||
private List<Title> unlockedTitles = new();
|
||||
|
||||
private int[] scoresArray = new int[10];
|
||||
|
||||
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
isSavingOptions = false;
|
||||
response = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||
response.ThrowIfNull();
|
||||
|
||||
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||
|
||||
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
||||
{
|
||||
@ -196,10 +212,15 @@ public partial class Profile
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
}
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{response.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Profile"], href: $"/Users/{Baid}/Profile", disabled: false));
|
||||
|
||||
costumeList = await GameDataService.GetCostumeList();
|
||||
titleDictionary = await GameDataService.GetTitleDictionary();
|
||||
lockedCostumeDataDictionary = await GameDataService.GetLockedCostumeDataDictionary();
|
||||
lockedTitleDataDictionary = await GameDataService.GetLockedTitleDataDictionary();
|
||||
|
||||
InitializeAvailableCostumes();
|
||||
InitializeAvailableTitles();
|
||||
|
||||
@ -209,9 +230,9 @@ public partial class Profile
|
||||
songresponse.SongBestData.ForEach(data =>
|
||||
{
|
||||
var songId = data.SongId;
|
||||
data.Genre = GameDataService.GetMusicGenreBySongId(songId);
|
||||
data.MusicName = GameDataService.GetMusicNameBySongId(songId);
|
||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(songId);
|
||||
data.Genre = GameDataService.GetMusicGenreBySongId(musicDetailDictionary, songId);
|
||||
data.MusicName = GameDataService.GetMusicNameBySongId(musicDetailDictionary, songId);
|
||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, songId);
|
||||
});
|
||||
|
||||
songBestDataMap = songresponse.SongBestData.GroupBy(data => data.Difficulty)
|
||||
@ -219,12 +240,12 @@ public partial class Profile
|
||||
data => data.ToList());
|
||||
foreach (var songBestDataList in songBestDataMap.Values)
|
||||
{
|
||||
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(data1.SongId)
|
||||
.CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId)));
|
||||
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data1.SongId)
|
||||
.CompareTo(GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data2.SongId)));
|
||||
}
|
||||
|
||||
for (var i = 0; i < (int)Difficulty.UraOni; i++)
|
||||
if (songBestDataMap.TryGetValue((Difficulty)i, out var values))
|
||||
if (songBestDataMap.ContainsKey((Difficulty)i) && songBestDataMap[(Difficulty)i].Count > 0)
|
||||
{
|
||||
highestDifficulty = (Difficulty)i;
|
||||
}
|
||||
@ -242,18 +263,30 @@ public partial class Profile
|
||||
|
||||
if (AuthService.AllowFreeProfileEditing)
|
||||
{
|
||||
kigurumiUniqueIdList = GameDataService.GetKigurumiUniqueIdList();
|
||||
headUniqueIdList = GameDataService.GetHeadUniqueIdList();
|
||||
bodyUniqueIdList = GameDataService.GetBodyUniqueIdList();
|
||||
faceUniqueIdList = GameDataService.GetFaceUniqueIdList();
|
||||
puchiUniqueIdList = GameDataService.GetPuchiUniqueIdList();
|
||||
kigurumiUniqueIdList = costumeList.Where(costume => costume.CostumeType == "kigurumi").Select(costume => costume.CostumeId).ToList();
|
||||
headUniqueIdList = costumeList.Where(costume => costume.CostumeType == "head").Select(costume => costume.CostumeId).ToList();
|
||||
bodyUniqueIdList = costumeList.Where(costume => costume.CostumeType == "body").Select(costume => costume.CostumeId).ToList();
|
||||
faceUniqueIdList = costumeList.Where(costume => costume.CostumeType == "face").Select(costume => costume.CostumeId).ToList();
|
||||
puchiUniqueIdList = costumeList.Where(costume => costume.CostumeType == "puchi").Select(costume => costume.CostumeId).ToList();
|
||||
|
||||
// Lock costumes in LockedCostumesList but not in UnlockedCostumesList
|
||||
var lockedKigurumiUniqueIdList = GameDataService.GetLockedKigurumiUniqueIdList().Except(unlockedKigurumi).ToList();
|
||||
var lockedHeadUniqueIdList = GameDataService.GetLockedHeadUniqueIdList().Except(unlockedHead).ToList();
|
||||
var lockedBodyUniqueIdList = GameDataService.GetLockedBodyUniqueIdList().Except(unlockedBody).ToList();
|
||||
var lockedFaceUniqueIdList = GameDataService.GetLockedFaceUniqueIdList().Except(unlockedFace).ToList();
|
||||
var lockedPuchiUniqueIdList = GameDataService.GetLockedPuchiUniqueIdList().Except(unlockedPuchi).ToList();
|
||||
lockedCostumeDataDictionary.TryGetValue("kigurumi", out var lockedKigurumiUniqueIdList);
|
||||
lockedCostumeDataDictionary.TryGetValue("head", out var lockedHeadUniqueIdList);
|
||||
lockedCostumeDataDictionary.TryGetValue("body", out var lockedBodyUniqueIdList);
|
||||
lockedCostumeDataDictionary.TryGetValue("face", out var lockedFaceUniqueIdList);
|
||||
lockedCostumeDataDictionary.TryGetValue("puchi", out var lockedPuchiUniqueIdList);
|
||||
|
||||
lockedKigurumiUniqueIdList ??= new List<uint>();
|
||||
lockedHeadUniqueIdList ??= new List<uint>();
|
||||
lockedBodyUniqueIdList ??= new List<uint>();
|
||||
lockedFaceUniqueIdList ??= new List<uint>();
|
||||
lockedPuchiUniqueIdList ??= new List<uint>();
|
||||
|
||||
unlockedKigurumi.ForEach(id => kigurumiUniqueIdList.Add(id));
|
||||
unlockedHead.ForEach(id => headUniqueIdList.Add(id));
|
||||
unlockedBody.ForEach(id => bodyUniqueIdList.Add(id));
|
||||
unlockedFace.ForEach(id => faceUniqueIdList.Add(id));
|
||||
unlockedPuchi.ForEach(id => puchiUniqueIdList.Add(id));
|
||||
|
||||
lockedKigurumiUniqueIdList.ForEach(id => kigurumiUniqueIdList.Remove(id));
|
||||
lockedHeadUniqueIdList.ForEach(id => headUniqueIdList.Remove(id));
|
||||
@ -264,19 +297,33 @@ public partial class Profile
|
||||
else
|
||||
{
|
||||
// Only unlock costumes that are in both UnlockedCostumesList and CostumeList
|
||||
kigurumiUniqueIdList = GameDataService.GetKigurumiUniqueIdList().Intersect(unlockedKigurumi).ToList();
|
||||
headUniqueIdList = GameDataService.GetHeadUniqueIdList().Intersect(unlockedHead).ToList();
|
||||
bodyUniqueIdList = GameDataService.GetBodyUniqueIdList().Intersect(unlockedBody).ToList();
|
||||
faceUniqueIdList = GameDataService.GetFaceUniqueIdList().Intersect(unlockedFace).ToList();
|
||||
puchiUniqueIdList = GameDataService.GetPuchiUniqueIdList().Intersect(unlockedPuchi).ToList();
|
||||
kigurumiUniqueIdList = costumeList.Where(costume => costume.CostumeType == "kigurumi").Select(costume => costume.CostumeId).Intersect(unlockedKigurumi).ToList();
|
||||
headUniqueIdList = costumeList.Where(costume => costume.CostumeType == "head").Select(costume => costume.CostumeId).Intersect(unlockedHead).ToList();
|
||||
bodyUniqueIdList = costumeList.Where(costume => costume.CostumeType == "body").Select(costume => costume.CostumeId).Intersect(unlockedBody).ToList();
|
||||
faceUniqueIdList = costumeList.Where(costume => costume.CostumeType == "face").Select(costume => costume.CostumeId).Intersect(unlockedFace).ToList();
|
||||
puchiUniqueIdList = costumeList.Where(costume => costume.CostumeType == "puchi").Select(costume => costume.CostumeId).Intersect(unlockedPuchi).ToList();
|
||||
}
|
||||
|
||||
// Take unique values and sort
|
||||
kigurumiUniqueIdList = kigurumiUniqueIdList.Distinct().OrderBy(id => id).ToList();
|
||||
headUniqueIdList = headUniqueIdList.Distinct().OrderBy(id => id).ToList();
|
||||
bodyUniqueIdList = bodyUniqueIdList.Distinct().OrderBy(id => id).ToList();
|
||||
faceUniqueIdList = faceUniqueIdList.Distinct().OrderBy(id => id).ToList();
|
||||
puchiUniqueIdList = puchiUniqueIdList.Distinct().OrderBy(id => id).ToList();
|
||||
}
|
||||
|
||||
private void InitializeAvailableTitlePlates()
|
||||
{
|
||||
titlePlateIdList = GameDataService.GetTitlePlateIdList().ToList();
|
||||
titlePlateIdList = titleDictionary.Values.Select(title => title.TitleRarity).ToList();
|
||||
|
||||
lockedTitleDataDictionary.TryGetValue("titlePlate", out var lockedTitlePlateIdList);
|
||||
lockedTitlePlateIdList ??= new List<uint>();
|
||||
|
||||
// Cut off ids longer than TitlePlateStrings
|
||||
titlePlateIdList = titlePlateIdList.Where(id => id < TitlePlateStrings.Length).Except(GameDataService.GetLockedTitlePlateIdList()).ToList();
|
||||
titlePlateIdList = titlePlateIdList.Where(id => id < TitlePlateStrings.Length).Except(lockedTitlePlateIdList).ToList();
|
||||
|
||||
// Take unique values and sort
|
||||
titlePlateIdList = titlePlateIdList.Distinct().OrderBy(id => id).ToList();
|
||||
}
|
||||
|
||||
private void InitializeAvailableTitles()
|
||||
@ -287,23 +334,32 @@ public partial class Profile
|
||||
|
||||
if (AuthService.AllowFreeProfileEditing)
|
||||
{
|
||||
titleUniqueIdList = GameDataService.GetTitleUniqueIdList();
|
||||
titleUniqueIdList = titleDictionary.Values.Select(title => title.TitleId).ToList();
|
||||
|
||||
var titles = GameDataService.GetTitles();
|
||||
// Lock titles in LockedTitlesList but not in UnlockedTitle
|
||||
var lockedTitleUniqueIdList = GameDataService.GetLockedTitleUniqueIdList().ToList();
|
||||
var lockedTitlePlateIdList = GameDataService.GetLockedTitlePlateIdList().ToList();
|
||||
lockedTitleDataDictionary.TryGetValue("title", out var lockedTitleUniqueIdList);
|
||||
lockedTitleDataDictionary.TryGetValue("titlePlate", out var lockedTitlePlateIdList);
|
||||
|
||||
lockedTitleUniqueIdList ??= new List<uint>();
|
||||
lockedTitlePlateIdList ??= new List<uint>();
|
||||
|
||||
// Unlock titles in UnlockedTitlesList
|
||||
lockedTitleUniqueIdList = lockedTitleUniqueIdList.Except(unlockedTitle).ToList();
|
||||
// Find uniqueIds of titles with rarity in lockedTitlePlateIdList
|
||||
lockedTitleUniqueIdList.AddRange(titles.Where(title => lockedTitlePlateIdList.Contains(title.TitleRarity)).Select(title => title.TitleId));
|
||||
lockedTitleUniqueIdList.AddRange(titleDictionary.Values.Where(title => lockedTitlePlateIdList.Contains(title.TitleRarity)).Select(title => title.TitleId));
|
||||
titleUniqueIdList = titleUniqueIdList.Except(lockedTitleUniqueIdList).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only unlock titles that are in both UnlockedTitlesList and TitleList
|
||||
titleUniqueIdList = GameDataService.GetTitleUniqueIdList().Intersect(unlockedTitle).ToList();
|
||||
titleUniqueIdList = titleDictionary.Values.Select(title => title.TitleId).ToList();
|
||||
titleUniqueIdList = titleUniqueIdList.Intersect(unlockedTitle).ToList();
|
||||
}
|
||||
|
||||
unlockedTitles = titleDictionary.Values.Where(title => titleUniqueIdList.Contains(title.TitleId)).ToList();
|
||||
|
||||
// Take unique values and sort
|
||||
titleUniqueIdList = titleUniqueIdList.Distinct().OrderBy(id => id).ToList();
|
||||
}
|
||||
|
||||
private async Task SaveOptions()
|
||||
@ -405,7 +461,7 @@ public partial class Profile
|
||||
{
|
||||
{x => x.UserSetting, response},
|
||||
{x => x.AllowFreeProfileEditing, AuthService.AllowFreeProfileEditing},
|
||||
{x => x.TitleUniqueIdList, titleUniqueIdList}
|
||||
{x => x.Titles, unlockedTitles},
|
||||
};
|
||||
var dialog = DialogService.Show<ChooseTitleDialog>("Player Titles", parameters, options);
|
||||
var result = await dialog.Result;
|
||||
|
@ -1,5 +1,4 @@
|
||||
@inject HttpClient Client
|
||||
@inject IDialogService DialogService
|
||||
@inject IDialogService DialogService
|
||||
@inject AuthService AuthService
|
||||
@inject NavigationManager NavigationManager
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
@page "/Users/{baid:int}/Songs/{songId:int}"
|
||||
|
||||
@using Blazored.LocalStorage
|
||||
@using TaikoWebUI.Components.Song
|
||||
|
||||
@inject IGameDataService GameDataService
|
||||
@inject HttpClient Client
|
||||
@inject AuthService AuthService
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject IJSRuntime JsRuntime
|
||||
|
||||
@using TaikoWebUI.Components.Song;
|
||||
@inject ILocalStorageService LocalStorage
|
||||
|
||||
@if (AuthService.LoginRequired && (!AuthService.IsLoggedIn || (AuthService.GetLoggedInBaid() != Baid && !AuthService.IsAdmin)))
|
||||
{
|
||||
|
@ -1,58 +1,62 @@
|
||||
using Microsoft.JSInterop;
|
||||
namespace TaikoWebUI.Pages;
|
||||
|
||||
namespace TaikoWebUI.Pages
|
||||
public partial class Song
|
||||
{
|
||||
public partial class Song
|
||||
[Parameter]
|
||||
public int SongId { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int Baid { get; set; }
|
||||
|
||||
private UserSetting? userSetting;
|
||||
private SongHistoryResponse? response;
|
||||
private List<SongHistoryData>? songHistoryData;
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||
|
||||
private string songTitle = string.Empty;
|
||||
private string songArtist = string.Empty;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
[Parameter]
|
||||
public int SongId { get; set; }
|
||||
|
||||
[Parameter]
|
||||
public int Baid { get; set; }
|
||||
|
||||
private UserSetting? userSetting;
|
||||
private SongHistoryResponse? response;
|
||||
private List<SongHistoryData>? songHistoryData;
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||
|
||||
private string songTitle = string.Empty;
|
||||
private string songArtist = string.Empty;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
||||
response.ThrowIfNull();
|
||||
// Get all song best data with SongId
|
||||
songHistoryData = response.SongHistoryData.Where(data => data.SongId == (uint)SongId).ToList();
|
||||
|
||||
// Get user settings
|
||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||
|
||||
// Get song title and artist
|
||||
var language = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||
songTitle = GameDataService.GetMusicNameBySongId((uint)SongId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||
songArtist = GameDataService.GetMusicArtistBySongId((uint)SongId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||
|
||||
// Breadcrumbs
|
||||
var formattedSongTitle = songTitle;
|
||||
if (formattedSongTitle.Length > 20)
|
||||
{
|
||||
formattedSongTitle = string.Concat(formattedSongTitle.AsSpan(0, 20), "...");
|
||||
}
|
||||
|
||||
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{userSetting?.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Song List"], href: $"/Users/{Baid}/Songs", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(formattedSongTitle, href: $"/Users/{Baid}/Songs/{SongId}", disabled: false));
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
||||
response.ThrowIfNull();
|
||||
// Get all song best data with SongId
|
||||
songHistoryData = response.SongHistoryData.Where(data => data.SongId == (uint)SongId).ToList();
|
||||
|
||||
// Get user settings
|
||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||
|
||||
var musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||
|
||||
// Get song title and artist
|
||||
var songNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
|
||||
songTitle = GameDataService.GetMusicNameBySongId(musicDetailDictionary, (uint)SongId, string.IsNullOrEmpty(songNameLanguage) ? "ja" : songNameLanguage);
|
||||
songArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, (uint)SongId, string.IsNullOrEmpty(songNameLanguage) ? "ja" : songNameLanguage);
|
||||
|
||||
// Breadcrumbs
|
||||
var formattedSongTitle = songTitle;
|
||||
if (formattedSongTitle.Length > 20)
|
||||
{
|
||||
formattedSongTitle = string.Concat(formattedSongTitle.AsSpan(0, 20), "...");
|
||||
}
|
||||
|
||||
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Dashboard"], href: "/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||
};
|
||||
breadcrumbs.Add(new BreadcrumbItem($"{userSetting?.MyDonName}", href: null, disabled: true));
|
||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Song List"], href: $"/Users/{Baid}/Songs", disabled: false));
|
||||
breadcrumbs.Add(new BreadcrumbItem(formattedSongTitle, href: $"/Users/{Baid}/Songs/{SongId}", disabled: false));
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
@inject IGameDataService GameDataService
|
||||
@using Blazored.LocalStorage
|
||||
@using TaikoWebUI.Utilities;
|
||||
|
||||
@inject IGameDataService GameDataService
|
||||
@inject HttpClient Client
|
||||
@inject AuthService AuthService
|
||||
@inject IJSRuntime JsRuntime
|
||||
@inject ILocalStorageService LocalStorage
|
||||
@inject NavigationManager NavigationManager
|
||||
@using TaikoWebUI.Utilities;
|
||||
@using TaikoWebUI.Shared.Models;
|
||||
|
||||
@page "/Users/{baid:int}/Songs"
|
||||
|
||||
@ -27,7 +28,7 @@
|
||||
else
|
||||
{
|
||||
<MudItem xs="12">
|
||||
<MudTable Items="musicMap" Elevation="0" Outlined="true" Filter="@FilterSongs">
|
||||
<MudTable Items="musicDetailDictionary.Values" Elevation="0" Outlined="true" Filter="@FilterSongs">
|
||||
<ToolBarContent>
|
||||
<MudGrid Spacing="2">
|
||||
<MudItem xs="12" md="8">
|
||||
@ -56,7 +57,7 @@
|
||||
</ToolBarContent>
|
||||
<HeaderContent>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicNameBySongId(context.SongId, CurrentLanguage)">
|
||||
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicNameBySongId(musicDetailDictionary, context.SongId, SongNameLanguage)">
|
||||
@Localizer["Song Title / Artist"]
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
@ -70,7 +71,7 @@
|
||||
@if (difficulty is not Difficulty.None)
|
||||
{
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicStarLevel(context.SongId, difficulty)">
|
||||
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicStarLevel(musicDetailDictionary, context.SongId, difficulty)">
|
||||
<img src="@ScoreUtils.GetDifficultyIcon(difficulty)" alt="@ScoreUtils.GetDifficultyTitle(difficulty)" style="@Constants.ICON_STYLE" />
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
@ -83,10 +84,10 @@
|
||||
<div>
|
||||
<a href="@($"/Users/{Baid}/Songs/{context.SongId}")">
|
||||
<MudText Typo="Typo.body2" Style="font-weight:bold">
|
||||
@GameDataService.GetMusicNameBySongId(context.SongId, CurrentLanguage)
|
||||
@GameDataService.GetMusicNameBySongId(musicDetailDictionary, context.SongId, SongNameLanguage)
|
||||
</MudText>
|
||||
<MudText Typo="Typo.caption">
|
||||
@GameDataService.GetMusicArtistBySongId(context.SongId, CurrentLanguage)
|
||||
@GameDataService.GetMusicArtistBySongId(musicDetailDictionary, context.SongId, SongNameLanguage)
|
||||
</MudText>
|
||||
</a>
|
||||
</div>
|
||||
@ -110,7 +111,7 @@
|
||||
{
|
||||
@if (difficulty is not Difficulty.None)
|
||||
{
|
||||
var starLevel = GameDataService.GetMusicStarLevel(context.SongId, difficulty);
|
||||
var starLevel = GameDataService.GetMusicStarLevel(musicDetailDictionary, context.SongId, difficulty);
|
||||
<MudTd>
|
||||
@if (starLevel > 0)
|
||||
{
|
||||
|
@ -1,9 +1,4 @@
|
||||
using System.Reflection.Emit;
|
||||
using Microsoft.JSInterop;
|
||||
using TaikoWebUI.Shared.Models;
|
||||
|
||||
|
||||
namespace TaikoWebUI.Pages;
|
||||
namespace TaikoWebUI.Pages;
|
||||
|
||||
public partial class SongList
|
||||
{
|
||||
@ -12,25 +7,33 @@ public partial class SongList
|
||||
|
||||
private string Search { get; set; } = string.Empty;
|
||||
private string GenreFilter { get; set; } = string.Empty;
|
||||
private string CurrentLanguage { get; set; } = "ja";
|
||||
private string? SongNameLanguage { get; set; }
|
||||
|
||||
private SongBestResponse? response;
|
||||
private UserSetting? userSetting;
|
||||
|
||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||
|
||||
private List<MusicDetail> musicMap = new();
|
||||
|
||||
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
||||
response.ThrowIfNull();
|
||||
|
||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||
musicMap = GameDataService.GetMusicList();
|
||||
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||
|
||||
CurrentLanguage = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||
SongNameLanguage = await LocalStorage.GetItemAsync<string>("songNameLanguage");
|
||||
|
||||
Console.WriteLine("Language: " + SongNameLanguage);
|
||||
|
||||
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
||||
{
|
||||
|
@ -9,7 +9,7 @@
|
||||
<MudText Typo="Typo.h4">@Localizer["Users"]</MudText>
|
||||
<MudGrid Class="my-8">
|
||||
@if (!AuthService.LoginRequired || (AuthService.LoginRequired && AuthService.IsAdmin)) {
|
||||
if (users == null) {
|
||||
if (usersWithSettings == null) {
|
||||
// Loading...
|
||||
for (uint i = 0; i < 6; i++) {
|
||||
<MudItem xs="12" md="6" lg="4">
|
||||
@ -28,11 +28,11 @@
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
}
|
||||
} else if (users.Count > 0) {
|
||||
foreach (var user in users)
|
||||
} else if (usersWithSettings.Count > 0) {
|
||||
foreach (var (user, userSetting) in usersWithSettings)
|
||||
{
|
||||
<MudItem xs="12" md="6" lg="4">
|
||||
<UserCard User="user" />
|
||||
<UserCard User="user" UserSetting="userSetting" />
|
||||
</MudItem>
|
||||
}
|
||||
} else { // No users in the database
|
||||
|
@ -2,14 +2,30 @@
|
||||
|
||||
public partial class Users
|
||||
{
|
||||
private List<User>? users;
|
||||
// Tuple of User and UserSetting
|
||||
private List<(User, UserSetting)>? usersWithSettings;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||
{
|
||||
await AuthService.LoginWithAuthToken();
|
||||
}
|
||||
|
||||
if (AuthService.IsAdmin || !AuthService.LoginRequired)
|
||||
{
|
||||
users = await Client.GetFromJsonAsync<List<User>>("api/Users");
|
||||
var users = await Client.GetFromJsonAsync<List<User>>("api/Users");
|
||||
var userSettings = await Client.GetFromJsonAsync<List<UserSetting>>("api/UserSettings");
|
||||
if (users != null && userSettings != null)
|
||||
{
|
||||
// Combine User and UserSetting with the same Baid
|
||||
usersWithSettings = users.Join(userSettings,
|
||||
user => user.Baid,
|
||||
setting => setting.Baid,
|
||||
(user, setting) => (user, setting))
|
||||
.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,16 @@ var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
||||
builder.RootComponents.Add<App>("#app");
|
||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
||||
|
||||
// Create a temporary HttpClient to fetch the appsettings.json file
|
||||
using var httpClient = new HttpClient();
|
||||
httpClient.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
|
||||
var configurationStream = await httpClient.GetStreamAsync("appsettings.json");
|
||||
|
||||
// Load the configuration from the stream
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddJsonStream(configurationStream)
|
||||
.Build();
|
||||
|
||||
builder.Services.AddSingleton(sp => new HttpClient
|
||||
{
|
||||
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
|
||||
@ -17,18 +27,16 @@ builder.Services.AddSingleton(sp => new HttpClient
|
||||
builder.Services.AddMudServices();
|
||||
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
||||
|
||||
builder.Services.Configure<WebUiSettings>(builder.Configuration.GetSection(nameof(WebUiSettings)));
|
||||
// Configure WebUiSettings using the loaded configuration
|
||||
builder.Services.Configure<WebUiSettings>(configuration.GetSection(nameof(WebUiSettings)));
|
||||
|
||||
builder.Services.AddScoped<AuthService>();
|
||||
builder.Services.AddLocalization();
|
||||
builder.Services.AddSingleton<MudLocalizer, ResXMudLocalizer>();
|
||||
builder.Services.AddSingleton<ScoreUtils>();
|
||||
builder.Services.AddSingleton<StringUtil>();
|
||||
|
||||
|
||||
builder.Services.AddBlazoredLocalStorage();
|
||||
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
var gameDataService = host.Services.GetRequiredService<IGameDataService>();
|
||||
@ -51,4 +59,4 @@ else
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
|
||||
await host.RunAsync();
|
||||
await host.RunAsync();
|
||||
|
@ -1,5 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Security.Claims;
|
||||
using System.Text.Json;
|
||||
@ -23,8 +22,10 @@ public sealed class AuthService
|
||||
public bool IsAdmin { get; private set; }
|
||||
private readonly ILocalStorageService localStorage;
|
||||
private readonly HttpClient client;
|
||||
private readonly NavigationManager navigationManager;
|
||||
|
||||
public AuthService(IOptions<WebUiSettings> settings, ILocalStorageService localStorage, HttpClient client)
|
||||
public AuthService(IOptions<WebUiSettings> settings, ILocalStorageService localStorage, HttpClient client,
|
||||
NavigationManager navigationManager)
|
||||
{
|
||||
this.localStorage = localStorage;
|
||||
IsLoggedIn = false;
|
||||
@ -37,6 +38,7 @@ public sealed class AuthService
|
||||
AllowUserDelete = webUiSettings.AllowUserDelete;
|
||||
AllowFreeProfileEditing = webUiSettings.AllowFreeProfileEditing;
|
||||
this.client = client;
|
||||
this.navigationManager = navigationManager;
|
||||
}
|
||||
|
||||
private void OnLoginStatusChanged()
|
||||
@ -105,11 +107,19 @@ public sealed class AuthService
|
||||
public async Task LoginWithAuthToken()
|
||||
{
|
||||
var hasAuthToken = await localStorage.ContainKeyAsync("authToken");
|
||||
if (!hasAuthToken) return;
|
||||
if (!hasAuthToken)
|
||||
{
|
||||
navigationManager.NavigateTo("/Login");
|
||||
return;
|
||||
}
|
||||
|
||||
// Attempt to get JWT token from local storage
|
||||
var authToken = await localStorage.GetItemAsync<string>("authToken");
|
||||
if (authToken == null) return;
|
||||
if (authToken == null)
|
||||
{
|
||||
navigationManager.NavigateTo("/Login");
|
||||
return;
|
||||
}
|
||||
|
||||
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
|
||||
var responseMessage = await client.PostAsync("api/Auth/LoginWithToken", null);
|
||||
@ -117,6 +127,7 @@ public sealed class AuthService
|
||||
{
|
||||
// Clear JWT token
|
||||
await localStorage.RemoveItemAsync("authToken");
|
||||
navigationManager.NavigateTo("/Login");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1,38 +1,21 @@
|
||||
using System.Collections.Immutable;
|
||||
using Swan.Mapping;
|
||||
using TaikoWebUI.Shared.Models;
|
||||
|
||||
namespace TaikoWebUI.Services;
|
||||
|
||||
public class GameDataService : IGameDataService
|
||||
{
|
||||
private readonly HttpClient client;
|
||||
private readonly Dictionary<uint, MusicDetail> musicMap = new();
|
||||
private ImmutableDictionary<uint, DanData> danMap = ImmutableDictionary<uint, DanData>.Empty;
|
||||
private ImmutableHashSet<Title> titles = ImmutableHashSet<Title>.Empty;
|
||||
|
||||
private string[] bodyTitles = { };
|
||||
private string[] faceTitles = { };
|
||||
private string[] headTitles = { };
|
||||
private string[] kigurumiTitles = { };
|
||||
private string[] puchiTitles = { };
|
||||
private Dictionary<uint, MusicDetail>? musicDetailDictionary = new();
|
||||
private List<Costume>? costumeList;
|
||||
private Dictionary<uint,Title>? titleDictionary = new();
|
||||
|
||||
private List<uint> kigurumiUniqueIdList = new();
|
||||
private List<uint> headUniqueIdList = new();
|
||||
private List<uint> bodyUniqueIdList = new();
|
||||
private List<uint> faceUniqueIdList = new();
|
||||
private List<uint> puchiUniqueIdList = new();
|
||||
|
||||
private List<uint> titleUniqueIdList = new();
|
||||
private List<uint> titlePlateIdList = new();
|
||||
private bool musicDetailInitialized;
|
||||
private bool costumesInitialized;
|
||||
private bool titlesInitialized;
|
||||
|
||||
private List<uint> lockedKigurumiUniqueIdList = new();
|
||||
private List<uint> lockedHeadUniqueIdList = new();
|
||||
private List<uint> lockedBodyUniqueIdList = new();
|
||||
private List<uint> lockedFaceUniqueIdList = new();
|
||||
private List<uint> lockedPuchiUniqueIdList = new();
|
||||
private List<uint> lockedTitleUniqueIdList = new();
|
||||
private List<uint> lockedTitlePlateIdList = new();
|
||||
private Dictionary<string, List<uint>>? lockedCostumeDataDictionary = new();
|
||||
private Dictionary<string, List<uint>>? lockedTitleDataDictionary = new();
|
||||
|
||||
public GameDataService(HttpClient client)
|
||||
{
|
||||
@ -42,58 +25,64 @@ public class GameDataService : IGameDataService
|
||||
public async Task InitializeAsync(string dataBaseUrl)
|
||||
{
|
||||
dataBaseUrl = dataBaseUrl.TrimEnd('/');
|
||||
var musicInfo = await GetData<MusicInfo>(dataBaseUrl, Constants.MUSIC_INFO_BASE_NAME);
|
||||
var wordList = await GetData<WordList>(dataBaseUrl, Constants.WORDLIST_BASE_NAME);
|
||||
var musicOrder = await GetData<MusicOrder>(dataBaseUrl, Constants.MUSIC_ORDER_BASE_NAME);
|
||||
var donCosRewardData = await GetData<DonCosRewards>(dataBaseUrl, Constants.DON_COS_REWARD_BASE_NAME);
|
||||
var shougouData = await GetData<Shougous>(dataBaseUrl, Constants.SHOUGOU_BASE_NAME);
|
||||
var danData = await client.GetFromJsonAsync<List<DanData>>($"{dataBaseUrl}/data/dan_data.json");
|
||||
|
||||
danData.ThrowIfNull();
|
||||
danMap = danData.ToImmutableDictionary(data => data.DanId);
|
||||
}
|
||||
|
||||
public async Task<Dictionary<uint, MusicDetail>> GetMusicDetailDictionary()
|
||||
{
|
||||
if (!musicDetailInitialized)
|
||||
{
|
||||
await InitializeMusicDetailAsync();
|
||||
}
|
||||
|
||||
// To prevent duplicate entries in wordlist
|
||||
var wordlistDict = wordList.WordListEntries.GroupBy(entry => entry.Key)
|
||||
.ToImmutableDictionary(group => group.Key, group => group.First());
|
||||
await Task.Run(() => InitializeMusicMap(musicInfo, wordlistDict, musicOrder));
|
||||
return musicDetailDictionary ?? new Dictionary<uint, MusicDetail>();
|
||||
}
|
||||
|
||||
public async Task<List<Costume>> GetCostumeList()
|
||||
{
|
||||
if (!costumesInitialized)
|
||||
{
|
||||
await InitializeCostumesAsync();
|
||||
}
|
||||
|
||||
await Task.Run(() => InitializeCostumeIdLists(donCosRewardData));
|
||||
await Task.Run(() => InitializeTitleIdList(shougouData));
|
||||
|
||||
await Task.Run(() => InitializeHeadTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeFaceTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeBodyTitles(wordlistDict));
|
||||
await Task.Run(() => InitializePuchiTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeKigurumiTitles(wordlistDict));
|
||||
await Task.Run(() => InitializeTitles(wordlistDict, shougouData));
|
||||
return costumeList ?? new List<Costume>();
|
||||
}
|
||||
|
||||
public async Task<Dictionary<uint, Title>> GetTitleDictionary()
|
||||
{
|
||||
if (!titlesInitialized)
|
||||
{
|
||||
await InitializeTitlesAsync();
|
||||
}
|
||||
|
||||
var lockedCostumeDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>($"{dataBaseUrl}/data/locked_costume_data.json") ?? throw new InvalidOperationException();
|
||||
lockedKigurumiUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Kigurumi") ?? new List<uint>();
|
||||
lockedHeadUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Head") ?? new List<uint>();
|
||||
lockedBodyUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Body") ?? new List<uint>();
|
||||
lockedFaceUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Face") ?? new List<uint>();
|
||||
lockedPuchiUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Puchi") ?? new List<uint>();
|
||||
return titleDictionary ?? new Dictionary<uint, Title>();
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, List<uint>>> GetLockedCostumeDataDictionary()
|
||||
{
|
||||
if (!costumesInitialized)
|
||||
{
|
||||
await InitializeCostumesAsync();
|
||||
}
|
||||
|
||||
var lockedTitleDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>($"{dataBaseUrl}/data/locked_title_data.json") ?? throw new InvalidOperationException();
|
||||
lockedTitleUniqueIdList = lockedTitleDataDictionary.GetValueOrDefault("TitleNo") ?? new List<uint>();
|
||||
lockedTitlePlateIdList = lockedTitleDataDictionary.GetValueOrDefault("TitlePlateNo") ?? new List<uint>();
|
||||
return lockedCostumeDataDictionary ?? new Dictionary<string, List<uint>>();
|
||||
}
|
||||
|
||||
public async Task<Dictionary<string, List<uint>>> GetLockedTitleDataDictionary()
|
||||
{
|
||||
if (!titlesInitialized)
|
||||
{
|
||||
await InitializeTitlesAsync();
|
||||
}
|
||||
|
||||
return lockedTitleDataDictionary ?? new Dictionary<string, List<uint>>();
|
||||
}
|
||||
|
||||
private async Task<T> GetData<T>(string dataBaseUrl, string fileBaseName) where T : notnull
|
||||
public string GetMusicNameBySongId(Dictionary<uint, MusicDetail> musicDetails, uint songId, string? language = "ja")
|
||||
{
|
||||
var data = await client.GetFromJsonAsync<T>($"{dataBaseUrl}/data/datatable/{fileBaseName}.json");
|
||||
data.ThrowIfNull();
|
||||
return data;
|
||||
}
|
||||
|
||||
public List<MusicDetail> GetMusicList()
|
||||
{
|
||||
return musicMap.Values.Where(musicDetail => musicDetail.SongId != 0).ToList();
|
||||
}
|
||||
|
||||
public string GetMusicNameBySongId(uint songId, string? language = "ja")
|
||||
{
|
||||
return musicMap.TryGetValue(songId, out var musicDetail) ? language switch
|
||||
return musicDetails.TryGetValue(songId, out var musicDetail) ? language switch
|
||||
{
|
||||
"ja" => musicDetail.SongName,
|
||||
"en-US" => musicDetail.SongNameEN,
|
||||
@ -104,9 +93,9 @@ public class GameDataService : IGameDataService
|
||||
} : string.Empty;
|
||||
}
|
||||
|
||||
public string GetMusicArtistBySongId(uint songId, string? language = "ja")
|
||||
public string GetMusicArtistBySongId(Dictionary<uint, MusicDetail> musicDetails, uint songId, string? language = "ja")
|
||||
{
|
||||
return musicMap.TryGetValue(songId, out var musicDetail) ? language switch
|
||||
return musicDetails.TryGetValue(songId, out var musicDetail) ? language switch
|
||||
{
|
||||
"jp" => musicDetail.ArtistName,
|
||||
"en-US" => musicDetail.ArtistNameEN,
|
||||
@ -117,14 +106,14 @@ public class GameDataService : IGameDataService
|
||||
} : string.Empty;
|
||||
}
|
||||
|
||||
public SongGenre GetMusicGenreBySongId(uint songId)
|
||||
public SongGenre GetMusicGenreBySongId(Dictionary<uint, MusicDetail> musicDetails, uint songId)
|
||||
{
|
||||
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.Genre : SongGenre.Variety;
|
||||
return musicDetails.TryGetValue(songId, out var musicDetail) ? musicDetail.Genre : SongGenre.Variety;
|
||||
}
|
||||
|
||||
public int GetMusicIndexBySongId(uint songId)
|
||||
public int GetMusicIndexBySongId(Dictionary<uint, MusicDetail> musicDetails, uint songId)
|
||||
{
|
||||
return musicMap.TryGetValue(songId, out var musicDetail) ? musicDetail.Index : int.MaxValue;
|
||||
return musicDetails.TryGetValue(songId, out var musicDetail) ? musicDetail.Index : int.MaxValue;
|
||||
}
|
||||
|
||||
public DanData GetDanDataById(uint danId)
|
||||
@ -132,9 +121,9 @@ public class GameDataService : IGameDataService
|
||||
return danMap.GetValueOrDefault(danId, new DanData());
|
||||
}
|
||||
|
||||
public int GetMusicStarLevel(uint songId, Difficulty difficulty)
|
||||
public int GetMusicStarLevel(Dictionary<uint, MusicDetail> musicDetails, uint songId, Difficulty difficulty)
|
||||
{
|
||||
var success = musicMap.TryGetValue(songId, out var musicDetail);
|
||||
var success = musicDetails.TryGetValue(songId, out var musicDetail);
|
||||
return difficulty switch
|
||||
{
|
||||
Difficulty.None => throw new ArgumentException("Difficulty cannot be none"),
|
||||
@ -147,261 +136,48 @@ public class GameDataService : IGameDataService
|
||||
};
|
||||
}
|
||||
|
||||
public string GetHeadTitle(uint index)
|
||||
public string GetHeadTitle(IEnumerable<Costume> costumes, uint index)
|
||||
{
|
||||
return index < headTitles.Length ? headTitles[index] : string.Empty;
|
||||
return costumes.FirstOrDefault(costume => costume.CostumeType == "head" && costume.CostumeId == index)?.CostumeName ?? string.Empty;
|
||||
}
|
||||
|
||||
public string GetKigurumiTitle(uint index)
|
||||
public string GetKigurumiTitle(IEnumerable<Costume> costumes, uint index)
|
||||
{
|
||||
return index < kigurumiTitles.Length ? kigurumiTitles[index] : string.Empty;
|
||||
return costumes.FirstOrDefault(costume => costume.CostumeType == "kigurumi" && costume.CostumeId == index)?.CostumeName ?? string.Empty;
|
||||
}
|
||||
|
||||
public string GetBodyTitle(uint index)
|
||||
public string GetBodyTitle(IEnumerable<Costume> costumes, uint index)
|
||||
{
|
||||
return index < bodyTitles.Length ? bodyTitles[index] : string.Empty;
|
||||
return costumes.FirstOrDefault(costume => costume.CostumeType == "body" && costume.CostumeId == index)?.CostumeName ?? string.Empty;
|
||||
}
|
||||
|
||||
public string GetFaceTitle(uint index)
|
||||
public string GetFaceTitle(IEnumerable<Costume> costumes, uint index)
|
||||
{
|
||||
return index < faceTitles.Length ? faceTitles[index] : string.Empty;
|
||||
return costumes.FirstOrDefault(costume => costume.CostumeType == "face" && costume.CostumeId == index)?.CostumeName ?? string.Empty;
|
||||
}
|
||||
|
||||
public string GetPuchiTitle(uint index)
|
||||
public string GetPuchiTitle(IEnumerable<Costume> costumes, uint index)
|
||||
{
|
||||
return index < puchiTitles.Length ? puchiTitles[index] : string.Empty;
|
||||
}
|
||||
|
||||
public ImmutableHashSet<Title> GetTitles()
|
||||
{
|
||||
return titles;
|
||||
return costumes.FirstOrDefault(costume => costume.CostumeType == "puchi" && costume.CostumeId == index)?.CostumeName ?? string.Empty;
|
||||
}
|
||||
|
||||
public List<uint> GetKigurumiUniqueIdList()
|
||||
private async Task InitializeMusicDetailAsync()
|
||||
{
|
||||
return kigurumiUniqueIdList;
|
||||
musicDetailDictionary = await client.GetFromJsonAsync<Dictionary<uint, MusicDetail>>("api/GameData/MusicDetails");
|
||||
musicDetailInitialized = true;
|
||||
}
|
||||
|
||||
public List<uint> GetHeadUniqueIdList()
|
||||
private async Task InitializeCostumesAsync()
|
||||
{
|
||||
return headUniqueIdList;
|
||||
costumeList = await client.GetFromJsonAsync<List<Costume>>("api/GameData/Costumes");
|
||||
lockedCostumeDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>("api/GameData/LockedCostumes");
|
||||
costumesInitialized = true;
|
||||
}
|
||||
|
||||
public List<uint> GetBodyUniqueIdList()
|
||||
private async Task InitializeTitlesAsync()
|
||||
{
|
||||
return bodyUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetFaceUniqueIdList()
|
||||
{
|
||||
return faceUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetPuchiUniqueIdList()
|
||||
{
|
||||
return puchiUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetTitleUniqueIdList()
|
||||
{
|
||||
return titleUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetTitlePlateIdList()
|
||||
{
|
||||
return titlePlateIdList;
|
||||
}
|
||||
|
||||
private void InitializeTitleIdList(Shougous? shougouData)
|
||||
{
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
titleUniqueIdList = shougouData.ShougouEntries.Select(entry => entry.UniqueId).ToList();
|
||||
}
|
||||
|
||||
private void InitializeTitles(ImmutableDictionary<string, WordListEntry> dict, Shougous? shougouData)
|
||||
{
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
|
||||
var set = ImmutableHashSet.CreateBuilder<Title>();
|
||||
foreach (var i in titleUniqueIdList)
|
||||
{
|
||||
var key = $"syougou_{i}";
|
||||
|
||||
var titleWordlistItem = dict.GetValueOrDefault(key, new WordListEntry());
|
||||
|
||||
var titleRarity = shougouData.ShougouEntries
|
||||
.Where(entry => entry.UniqueId == i)
|
||||
.Select(entry => entry.Rarity)
|
||||
.FirstOrDefault();
|
||||
|
||||
if (!titlePlateIdList.Contains(titleRarity))
|
||||
{
|
||||
titlePlateIdList.Add(titleRarity);
|
||||
}
|
||||
|
||||
set.Add(new Title
|
||||
{
|
||||
TitleName = titleWordlistItem.JapaneseText,
|
||||
TitleId = i,
|
||||
TitleRarity = titleRarity
|
||||
});
|
||||
}
|
||||
|
||||
titles = set.ToImmutable();
|
||||
}
|
||||
|
||||
private void InitializeCostumeIdLists(DonCosRewards? donCosRewardData)
|
||||
{
|
||||
donCosRewardData.ThrowIfNull("Shouldn't happen!");
|
||||
kigurumiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "kigurumi")
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
headUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "head")
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
bodyUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "body")
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
faceUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "face")
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
puchiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "puchi")
|
||||
.Select(entry => entry.UniqueId).ToList();
|
||||
}
|
||||
|
||||
private void InitializeKigurumiTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
kigurumiTitles = new string[kigurumiUniqueIdList.Max() + 1];
|
||||
foreach (var i in kigurumiUniqueIdList)
|
||||
{
|
||||
var key = $"costume_kigurumi_{i}";
|
||||
|
||||
var costumeWordlistItem = dict.GetValueOrDefault(key, new WordListEntry());
|
||||
kigurumiTitles[i] = costumeWordlistItem.JapaneseText;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeHeadTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
headTitles = new string[headUniqueIdList.Max() + 1];
|
||||
foreach (var i in headUniqueIdList)
|
||||
{
|
||||
var key = $"costume_head_{i}";
|
||||
|
||||
var costumeWordlistItem = dict.GetValueOrDefault(key, new WordListEntry());
|
||||
headTitles[i] = costumeWordlistItem.JapaneseText;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeBodyTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
bodyTitles = new string[bodyUniqueIdList.Max() + 1];
|
||||
foreach (var i in bodyUniqueIdList)
|
||||
{
|
||||
var key = $"costume_body_{i}";
|
||||
|
||||
var costumeWordlistItem = dict.GetValueOrDefault(key, new WordListEntry());
|
||||
bodyTitles[i] = costumeWordlistItem.JapaneseText;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeFaceTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
faceTitles = new string[faceUniqueIdList.Max() + 1];
|
||||
foreach (var i in faceUniqueIdList)
|
||||
{
|
||||
var key = $"costume_face_{i}";
|
||||
|
||||
var costumeWordlistItem = dict.GetValueOrDefault(key, new WordListEntry());
|
||||
faceTitles[i] = costumeWordlistItem.JapaneseText;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializePuchiTitles(ImmutableDictionary<string, WordListEntry> dict)
|
||||
{
|
||||
puchiTitles = new string[puchiUniqueIdList.Max() + 1];
|
||||
foreach (var i in puchiUniqueIdList)
|
||||
{
|
||||
var key = $"costume_puchi_{i}";
|
||||
|
||||
var costumeWordlistItem = dict.GetValueOrDefault(key, new WordListEntry());
|
||||
puchiTitles[i] = costumeWordlistItem.JapaneseText;
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeMusicMap(MusicInfo musicInfo, ImmutableDictionary<string, WordListEntry> dict,
|
||||
MusicOrder musicOrder)
|
||||
{
|
||||
foreach (var music in musicInfo.Items)
|
||||
{
|
||||
var songNameKey = $"song_{music.Id}";
|
||||
var songArtistKey = $"song_sub_{music.Id}";
|
||||
|
||||
var musicName = dict.GetValueOrDefault(songNameKey, new WordListEntry());
|
||||
var musicArtist = dict.GetValueOrDefault(songArtistKey, new WordListEntry());
|
||||
|
||||
var musicSongId = music.SongId;
|
||||
var musicDetail = music.CopyPropertiesToNew<MusicDetail>();
|
||||
musicDetail.SongName = musicName.JapaneseText;
|
||||
musicDetail.ArtistName = musicArtist.JapaneseText;
|
||||
|
||||
// Add localized names
|
||||
musicDetail.SongNameEN = musicName.EnglishUsText;
|
||||
musicDetail.ArtistNameEN = musicArtist.EnglishUsText;
|
||||
|
||||
musicDetail.SongNameCN = musicName.ChineseTText;
|
||||
musicDetail.ArtistNameCN = musicArtist.ChineseTText;
|
||||
|
||||
musicDetail.SongNameKO = musicName.KoreanText;
|
||||
musicDetail.ArtistNameKO = musicArtist.KoreanText;
|
||||
|
||||
musicMap.TryAdd(musicSongId, musicDetail);
|
||||
}
|
||||
|
||||
for (var index = 0; index < musicOrder.Order.Count; index++)
|
||||
{
|
||||
var musicOrderEntry = musicOrder.Order[index];
|
||||
var songId = musicOrderEntry.SongId;
|
||||
if (musicMap.TryGetValue(songId, out var value))
|
||||
{
|
||||
value.Index = index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<uint> GetLockedKigurumiUniqueIdList()
|
||||
{
|
||||
return lockedKigurumiUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedHeadUniqueIdList()
|
||||
{
|
||||
return lockedHeadUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedBodyUniqueIdList()
|
||||
{
|
||||
return lockedBodyUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedFaceUniqueIdList()
|
||||
{
|
||||
return lockedFaceUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedPuchiUniqueIdList()
|
||||
{
|
||||
return lockedPuchiUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedTitleUniqueIdList()
|
||||
{
|
||||
return lockedTitleUniqueIdList;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedTitlePlateIdList()
|
||||
{
|
||||
return lockedTitlePlateIdList;
|
||||
titleDictionary = await client.GetFromJsonAsync<Dictionary<uint, Title>>("api/GameData/Titles");
|
||||
lockedTitleDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>("api/GameData/LockedTitles");
|
||||
titlesInitialized = true;
|
||||
}
|
||||
}
|
@ -1,47 +1,34 @@
|
||||
using System.Collections.Immutable;
|
||||
using TaikoWebUI.Shared.Models;
|
||||
|
||||
namespace TaikoWebUI.Services;
|
||||
namespace TaikoWebUI.Services;
|
||||
|
||||
public interface IGameDataService
|
||||
{
|
||||
public Task InitializeAsync(string dataBaseUrl);
|
||||
|
||||
public List<MusicDetail> GetMusicList();
|
||||
public Task<Dictionary<uint, MusicDetail>> GetMusicDetailDictionary();
|
||||
|
||||
public Task<Dictionary<uint, Title>> GetTitleDictionary();
|
||||
|
||||
public Task<List<Costume>> GetCostumeList();
|
||||
|
||||
public Task<Dictionary<string, List<uint>>> GetLockedCostumeDataDictionary();
|
||||
|
||||
public Task<Dictionary<string, List<uint>>> GetLockedTitleDataDictionary();
|
||||
|
||||
public string GetMusicNameBySongId(uint songId, string? language = null);
|
||||
public string GetMusicNameBySongId(Dictionary<uint, MusicDetail> musicDetails,uint songId, string? language = null);
|
||||
|
||||
public string GetMusicArtistBySongId(uint songId, string? language = null);
|
||||
public string GetMusicArtistBySongId(Dictionary<uint, MusicDetail> musicDetails,uint songId, string? language = null);
|
||||
|
||||
public SongGenre GetMusicGenreBySongId(uint songId);
|
||||
public SongGenre GetMusicGenreBySongId(Dictionary<uint, MusicDetail> musicDetails,uint songId);
|
||||
|
||||
public int GetMusicIndexBySongId(uint songId);
|
||||
public int GetMusicIndexBySongId(Dictionary<uint, MusicDetail> musicDetails,uint songId);
|
||||
|
||||
public DanData GetDanDataById(uint danId);
|
||||
|
||||
public int GetMusicStarLevel(uint songId, Difficulty difficulty);
|
||||
public int GetMusicStarLevel(Dictionary<uint, MusicDetail> musicDetails, uint songId, Difficulty difficulty);
|
||||
|
||||
public string GetHeadTitle(uint index);
|
||||
public string GetKigurumiTitle(uint index);
|
||||
public string GetBodyTitle(uint index);
|
||||
public string GetFaceTitle(uint index);
|
||||
public string GetPuchiTitle(uint index);
|
||||
|
||||
public List<uint> GetKigurumiUniqueIdList();
|
||||
public List<uint> GetHeadUniqueIdList();
|
||||
public List<uint> GetBodyUniqueIdList();
|
||||
public List<uint> GetFaceUniqueIdList();
|
||||
public List<uint> GetPuchiUniqueIdList();
|
||||
public List<uint> GetTitleUniqueIdList();
|
||||
public List<uint> GetTitlePlateIdList();
|
||||
|
||||
public List<uint> GetLockedKigurumiUniqueIdList();
|
||||
public List<uint> GetLockedHeadUniqueIdList();
|
||||
public List<uint> GetLockedBodyUniqueIdList();
|
||||
public List<uint> GetLockedFaceUniqueIdList();
|
||||
public List<uint> GetLockedPuchiUniqueIdList();
|
||||
public List<uint> GetLockedTitleUniqueIdList();
|
||||
public List<uint> GetLockedTitlePlateIdList();
|
||||
|
||||
public ImmutableHashSet<Title> GetTitles();
|
||||
public string GetHeadTitle(IEnumerable<Costume> costumes, uint index);
|
||||
public string GetKigurumiTitle(IEnumerable<Costume> costumes, uint index);
|
||||
public string GetBodyTitle(IEnumerable<Costume> costumes, uint index);
|
||||
public string GetFaceTitle(IEnumerable<Costume> costumes, uint index);
|
||||
public string GetPuchiTitle(IEnumerable<Costume> costumes, uint index);
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class DonCosRewardEntry
|
||||
{
|
||||
[JsonPropertyName("cosType")]
|
||||
public string CosType { get; set; } = null!;
|
||||
|
||||
[JsonPropertyName("uniqueId")]
|
||||
public uint UniqueId { get; set; }
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class DonCosRewards
|
||||
{
|
||||
[JsonPropertyName("items")]
|
||||
public List<DonCosRewardEntry> DonCosRewardEntries { get; set; } = new();
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class MusicInfo
|
||||
{
|
||||
[JsonPropertyName("items")]
|
||||
public List<MusicInfoEntry> Items { get; set; } = new();
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class MusicInfoEntry
|
||||
{
|
||||
[JsonPropertyName("id")]
|
||||
public string Id { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("uniqueId")]
|
||||
public uint SongId { get; set; }
|
||||
|
||||
[JsonPropertyName("genreNo")]
|
||||
public SongGenre Genre { get; set; }
|
||||
|
||||
[JsonPropertyName("starEasy")]
|
||||
public int StarEasy { get; set; }
|
||||
|
||||
[JsonPropertyName("starNormal")]
|
||||
public int StarNormal { get; set; }
|
||||
|
||||
[JsonPropertyName("starHard")]
|
||||
public int StarHard { get; set; }
|
||||
|
||||
[JsonPropertyName("starMania")]
|
||||
public int StarOni { get; set; }
|
||||
|
||||
[JsonPropertyName("starUra")]
|
||||
public int StarUra { get; set; }
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class NeiroEntry
|
||||
{
|
||||
[JsonPropertyName("uniqueId")]
|
||||
public uint UniqueId { get; set; }
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class Neiros
|
||||
{
|
||||
[JsonPropertyName("items")]
|
||||
public List<NeiroEntry> NeiroEntries { get; set; } = new();
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class ShougouEntry
|
||||
{
|
||||
[JsonPropertyName("uniqueId")]
|
||||
public uint UniqueId { get; set; }
|
||||
|
||||
[JsonPropertyName("rarity")]
|
||||
public uint Rarity { get; set; }
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace TaikoWebUI.Shared.Models;
|
||||
|
||||
public class Shougous
|
||||
{
|
||||
[JsonPropertyName("items")]
|
||||
public List<ShougouEntry> ShougouEntries { get; set; } = new();
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
namespace TaikoWebUI.Shared.Models
|
||||
{
|
||||
public class SongListEntry
|
||||
{
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user