Major refactors including frontend requests refactors, authentication refactors and request compressions
This commit is contained in:
parent
75e90d9aa2
commit
2069681390
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
|
public class MusicDetail
|
||||||
{
|
{
|
@ -1,4 +1,4 @@
|
|||||||
namespace TaikoWebUI.Shared.Models;
|
namespace SharedProject.Models;
|
||||||
|
|
||||||
public class Title
|
public class Title
|
||||||
{
|
{
|
@ -2,27 +2,27 @@
|
|||||||
|
|
||||||
public static class Constants
|
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 MusicInfoBaseName = "musicinfo";
|
||||||
public const string WORDLIST_BASE_NAME = "wordlist";
|
public const string WordlistBaseName = "wordlist";
|
||||||
public const string MUSIC_ORDER_BASE_NAME = "music_order";
|
public const string MusicOrderBaseName = "music_order";
|
||||||
public const string DON_COS_REWARD_BASE_NAME = "don_cos_reward";
|
public const string DonCosRewardBaseName = "don_cos_reward";
|
||||||
public const string SHOUGOU_BASE_NAME = "shougou";
|
public const string ShougouBaseName = "shougou";
|
||||||
public const string NEIRO_BASE_NAME = "neiro";
|
public const string NeiroBaseName = "neiro";
|
||||||
|
|
||||||
public const uint DAN_VERUP_MASTER_TYPE = 101;
|
public const uint DanVerupMasterType = 101;
|
||||||
public const uint GAIDEN_VERUP_MASTER_TYPE = 102;
|
public const uint GaidenVerupMasterType = 102;
|
||||||
public const uint FOLDER_VERUP_MASTER_TYPE = 103;
|
public const uint FolderVerupMasterType = 103;
|
||||||
public const uint INTRO_VERUP_MASTER_TYPE = 105;
|
public const uint IntroVerupMasterType = 105;
|
||||||
|
|
||||||
public const uint FUNCTION_ID_DANI_FOLDER_AVAILABLE = 1;
|
public const uint FunctionIdDaniFolderAvailable = 1;
|
||||||
public const uint FUNCTION_ID_DANI_AVAILABLE = 2;
|
public const uint FunctionIdDaniAvailable = 2;
|
||||||
public const uint FUNCTION_ID_AI_BATTLE_AVAILABLE = 3;
|
public const uint FunctionIdAiBattleAvailable = 3;
|
||||||
}
|
}
|
@ -1,6 +1,4 @@
|
|||||||
using System.IdentityModel.Tokens.Jwt;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using System.Security.Claims;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using SharedProject.Models.Requests;
|
using SharedProject.Models.Requests;
|
||||||
using TaikoLocalServer.Filters;
|
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());
|
||||||
|
}
|
||||||
|
}
|
@ -58,7 +58,7 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
|||||||
{
|
{
|
||||||
var songBestData = await songBestDatumService.GetAllSongBestData(baid);
|
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 crown = new ushort[songIdMax + 1];
|
||||||
var dondafulCrown = new byte[songIdMax + 1];
|
var dondafulCrown = new byte[songIdMax + 1];
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ public class GetScoreRankController(ISongBestDatumService songBestDatumService,
|
|||||||
|
|
||||||
private async Task<ScoreRankData> Handle(uint baid)
|
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 kiwamiScores = new byte[songIdMax + 1];
|
||||||
var miyabiScores = new ushort[songIdMax + 1];
|
var miyabiScores = new ushort[songIdMax + 1];
|
||||||
var ikiScores = new ushort[songIdMax + 1];
|
var ikiScores = new ushort[songIdMax + 1];
|
||||||
|
@ -15,8 +15,8 @@ public class GetTelopController : BaseController<GetTelopController>
|
|||||||
var response = new GettelopResponse
|
var response = new GettelopResponse
|
||||||
{
|
{
|
||||||
Result = 1,
|
Result = 1,
|
||||||
StartDatetime = startDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
StartDatetime = startDateTime.ToString(Constants.DateTimeFormat),
|
||||||
EndDatetime = endDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
EndDatetime = endDateTime.ToString(Constants.DateTimeFormat),
|
||||||
Telop = "Hello 3906",
|
Telop = "Hello 3906",
|
||||||
VerupNo = 1
|
VerupNo = 1
|
||||||
};
|
};
|
||||||
@ -36,8 +36,8 @@ public class GetTelopController : BaseController<GetTelopController>
|
|||||||
var response = new Models.v3209.GettelopResponse
|
var response = new Models.v3209.GettelopResponse
|
||||||
{
|
{
|
||||||
Result = 1,
|
Result = 1,
|
||||||
StartDatetime = startDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
StartDatetime = startDateTime.ToString(Constants.DateTimeFormat),
|
||||||
EndDatetime = endDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
EndDatetime = endDateTime.ToString(Constants.DateTimeFormat),
|
||||||
Telop = "Hello 3209",
|
Telop = "Hello 3209",
|
||||||
VerupNo = 1
|
VerupNo = 1
|
||||||
};
|
};
|
||||||
|
@ -127,7 +127,7 @@ public class BaidQueryHandler(
|
|||||||
GotDanMax = maxDan,
|
GotDanMax = maxDan,
|
||||||
GotGaidenFlg = gotGaidenFlagArray,
|
GotGaidenFlg = gotGaidenFlagArray,
|
||||||
IsDispAchievementOn = userData.DisplayAchievement,
|
IsDispAchievementOn = userData.DisplayAchievement,
|
||||||
LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DATE_TIME_FORMAT),
|
LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DateTimeFormat),
|
||||||
LastPlayMode = userData.LastPlayMode,
|
LastPlayMode = userData.LastPlayMode,
|
||||||
SelectedToneId = userData.SelectedToneId,
|
SelectedToneId = userData.SelectedToneId,
|
||||||
Title = userData.Title,
|
Title = userData.Title,
|
||||||
|
@ -17,7 +17,7 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService,
|
|||||||
|
|
||||||
public Task<CommonInitialDataCheckResponse> Handle(GetInitialDataQuery request, CancellationToken cancellationToken)
|
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 musicList = gameDataService.GetMusicList();
|
||||||
var lockedSongsList = gameDataService.GetLockedSongsList();
|
var lockedSongsList = gameDataService.GetLockedSongsList();
|
||||||
@ -39,7 +39,7 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService,
|
|||||||
DefaultSongFlg = defaultSongFlg,
|
DefaultSongFlg = defaultSongFlg,
|
||||||
AchievementSongBit = enabledArray,
|
AchievementSongBit = enabledArray,
|
||||||
UraReleaseBit = uraReleaseBit,
|
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()
|
ServerCurrentDatetime = (ulong)DateTimeOffset.Now.ToUnixTimeSeconds()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,18 +65,18 @@ public class GetInitialDataQueryHandler(IGameDataService gameDataService,
|
|||||||
|
|
||||||
CommonInitialDataCheckResponse.VerupNoData2[] verupNo2List =
|
CommonInitialDataCheckResponse.VerupNoData2[] verupNo2List =
|
||||||
[
|
[
|
||||||
GetVerupNoData2(Constants.DAN_VERUP_MASTER_TYPE, commonDanDataDictionary),
|
GetVerupNoData2(Constants.DanVerupMasterType, commonDanDataDictionary),
|
||||||
GetVerupNoData2(Constants.GAIDEN_VERUP_MASTER_TYPE, commonGaidenDataDictionary),
|
GetVerupNoData2(Constants.GaidenVerupMasterType, commonGaidenDataDictionary),
|
||||||
GetVerupNoData2(Constants.FOLDER_VERUP_MASTER_TYPE, eventFolderDictionary),
|
GetVerupNoData2(Constants.FolderVerupMasterType, eventFolderDictionary),
|
||||||
GetVerupNoData2(Constants.INTRO_VERUP_MASTER_TYPE, songIntroDictionary)
|
GetVerupNoData2(Constants.IntroVerupMasterType, songIntroDictionary)
|
||||||
];
|
];
|
||||||
response.AryVerupNoData2s.AddRange(verupNo2List);
|
response.AryVerupNoData2s.AddRange(verupNo2List);
|
||||||
|
|
||||||
response.AryChassisFunctionIds =
|
response.AryChassisFunctionIds =
|
||||||
[
|
[
|
||||||
Constants.FUNCTION_ID_DANI_AVAILABLE,
|
Constants.FunctionIdDaniAvailable,
|
||||||
Constants.FUNCTION_ID_DANI_FOLDER_AVAILABLE,
|
Constants.FunctionIdDaniFolderAvailable,
|
||||||
Constants.FUNCTION_ID_AI_BATTLE_AVAILABLE
|
Constants.FunctionIdAiBattleAvailable
|
||||||
];
|
];
|
||||||
|
|
||||||
return Task.FromResult(response);
|
return Task.FromResult(response);
|
||||||
|
@ -22,12 +22,12 @@ public class UserDataQueryHandler(TaikoDbContext context, IGameDataService gameD
|
|||||||
lockedSongsList = lockedSongsList.Except(unlockedSongIdList).ToList();
|
lockedSongsList = lockedSongsList.Except(unlockedSongIdList).ToList();
|
||||||
var enabledMusicList = musicList.Except(lockedSongsList);
|
var enabledMusicList = musicList.Except(lockedSongsList);
|
||||||
var releaseSongArray =
|
var releaseSongArray =
|
||||||
FlagCalculator.GetBitArrayFromIds(enabledMusicList, Constants.MUSIC_ID_MAX, logger);
|
FlagCalculator.GetBitArrayFromIds(enabledMusicList, Constants.MusicIdMax, logger);
|
||||||
|
|
||||||
var defaultSongWithUraList = gameDataService.GetMusicWithUraList();
|
var defaultSongWithUraList = gameDataService.GetMusicWithUraList();
|
||||||
var enabledUraMusicList = defaultSongWithUraList.Except(lockedSongsList);
|
var enabledUraMusicList = defaultSongWithUraList.Except(lockedSongsList);
|
||||||
var uraSongArray =
|
var uraSongArray =
|
||||||
FlagCalculator.GetBitArrayFromIds(enabledUraMusicList, Constants.MUSIC_ID_MAX, logger);
|
FlagCalculator.GetBitArrayFromIds(enabledUraMusicList, Constants.MusicIdMax, logger);
|
||||||
|
|
||||||
if (userData.ToneFlgArray.Count == 0)
|
if (userData.ToneFlgArray.Count == 0)
|
||||||
{
|
{
|
||||||
|
@ -16,7 +16,7 @@ public class CommonBaidResponse
|
|||||||
public List<byte[]> CostumeFlagArrays { get; set; }
|
public List<byte[]> CostumeFlagArrays { get; set; }
|
||||||
= new() { Array.Empty<byte>(), Array.Empty<byte>(), Array.Empty<byte>(), Array.Empty<byte>(), Array.Empty<byte>() };
|
= 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 bool DisplayDan { get; set; }
|
||||||
public uint GotDanMax { get; set; }
|
public uint GotDanMax { get; set; }
|
||||||
public byte[] GotDanFlg { get; set; } = Array.Empty<byte>();
|
public byte[] GotDanFlg { get; set; } = Array.Empty<byte>();
|
||||||
|
@ -10,7 +10,7 @@ public class CommonInitialDataCheckResponse
|
|||||||
public byte[] UraReleaseBit { get; set; } = [];
|
public byte[] UraReleaseBit { get; set; } = [];
|
||||||
|
|
||||||
public string SongIntroductionEndDatetime { 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<MovieData> AryMovieInfoes { get; set; } = [];
|
||||||
public List<AiEventData> AryAiEventDatas { get; set; } = [];
|
public List<AiEventData> AryAiEventDatas { get; set; } = [];
|
||||||
|
@ -4,9 +4,27 @@ namespace TaikoLocalServer.Models;
|
|||||||
|
|
||||||
public class MusicInfoEntry
|
public class MusicInfoEntry
|
||||||
{
|
{
|
||||||
|
[JsonPropertyName("id")]
|
||||||
|
public string Id { get; set; } = string.Empty;
|
||||||
|
|
||||||
[JsonPropertyName("uniqueId")]
|
[JsonPropertyName("uniqueId")]
|
||||||
public uint MusicId { get; set; }
|
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")]
|
[JsonPropertyName("starUra")]
|
||||||
public uint StarUra { get; set; }
|
public int StarUra { get; set; }
|
||||||
}
|
}
|
@ -15,6 +15,8 @@ using Serilog;
|
|||||||
using SharedProject.Utils;
|
using SharedProject.Utils;
|
||||||
using TaikoLocalServer.Controllers.Api;
|
using TaikoLocalServer.Controllers.Api;
|
||||||
using TaikoLocalServer.Filters;
|
using TaikoLocalServer.Filters;
|
||||||
|
using Microsoft.AspNetCore.ResponseCompression;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
Log.Logger = new LoggerConfiguration()
|
Log.Logger = new LoggerConfiguration()
|
||||||
.WriteTo.Console()
|
.WriteTo.Console()
|
||||||
@ -29,14 +31,14 @@ Log.Information("Server starting up...");
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddHttpLogging(options =>
|
builder.Services.AddHttpLogging(options =>
|
||||||
{
|
{
|
||||||
options.LoggingFields = HttpLoggingFields.All;
|
options.LoggingFields = HttpLoggingFields.All;
|
||||||
options.RequestBodyLogLimit = 32768;
|
options.RequestBodyLogLimit = 32768;
|
||||||
options.ResponseBodyLogLimit = 32768;
|
options.ResponseBodyLogLimit = 32768;
|
||||||
});
|
});
|
||||||
|
|
||||||
const string configurationsDirectory = "Configurations";
|
const string configurationsDirectory = "Configurations";
|
||||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/Kestrel.json", optional: true, reloadOnChange: false);
|
builder.Configuration.AddJsonFile($"{configurationsDirectory}/Kestrel.json", optional: true, reloadOnChange: false);
|
||||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/Logging.json", optional: false, 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}/ServerSettings.json", optional: false, reloadOnChange: false);
|
||||||
builder.Configuration.AddJsonFile($"{configurationsDirectory}/DataSettings.json", optional: true, 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($"{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) =>
|
builder.Host.UseSerilog((context, configuration) =>
|
||||||
{
|
{
|
||||||
configuration
|
configuration
|
||||||
@ -65,6 +67,19 @@ try
|
|||||||
Log.Warning("Song limit expanded! Use at your own risk!");
|
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.
|
// Add services to the container.
|
||||||
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
|
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
|
||||||
builder.Services.AddOptions();
|
builder.Services.AddOptions();
|
||||||
@ -73,39 +88,38 @@ try
|
|||||||
builder.Services.Configure<DataSettings>(builder.Configuration.GetSection(nameof(DataSettings)));
|
builder.Services.Configure<DataSettings>(builder.Configuration.GetSection(nameof(DataSettings)));
|
||||||
builder.Services.Configure<AuthSettings>(builder.Configuration.GetSection(nameof(AuthSettings)));
|
builder.Services.Configure<AuthSettings>(builder.Configuration.GetSection(nameof(AuthSettings)));
|
||||||
|
|
||||||
// Read LoginRequired setting from appsettings.json
|
var loginRequired = builder.Configuration.GetSection("WebUiSettings").GetValue<bool>("LoginRequired");
|
||||||
var loginRequired = builder.Configuration.GetValue<bool>("LoginRequired");
|
|
||||||
builder.Services.Configure<AuthSettings>(options => { options.LoginRequired = loginRequired; });
|
builder.Services.Configure<AuthSettings>(options => { options.LoginRequired = loginRequired; });
|
||||||
|
|
||||||
// Add Authentication with JWT
|
// Add Authentication with JWT
|
||||||
builder.Services.AddAuthentication(options =>
|
builder.Services.AddAuthentication(options =>
|
||||||
|
{
|
||||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
||||||
|
})
|
||||||
|
.AddJwtBearer(options =>
|
||||||
|
{
|
||||||
|
options.TokenValidationParameters = new TokenValidationParameters
|
||||||
{
|
{
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
ValidateIssuer = true,
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
ValidateAudience = true,
|
||||||
})
|
ValidateLifetime = true,
|
||||||
.AddJwtBearer(options =>
|
ValidateIssuerSigningKey = true,
|
||||||
{
|
ValidIssuer = builder.Configuration.GetSection(nameof(AuthSettings))["JwtIssuer"],
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
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.AddScoped<AuthorizeIfRequiredAttribute>(); // Register the custom attribute
|
||||||
|
|
||||||
builder.Services.AddControllers().AddProtoBufNet();
|
builder.Services.AddControllers().AddProtoBufNet();
|
||||||
builder.Services.AddDbContext<TaikoDbContext>(option =>
|
builder.Services.AddDbContext<TaikoDbContext>(option =>
|
||||||
{
|
{
|
||||||
var dbName = builder.Configuration["DbFileName"];
|
var dbName = builder.Configuration["DbFileName"];
|
||||||
if (string.IsNullOrEmpty(dbName))
|
if (string.IsNullOrEmpty(dbName))
|
||||||
{
|
{
|
||||||
dbName = Constants.DEFAULT_DB_NAME;
|
dbName = Constants.DefaultDbName;
|
||||||
}
|
}
|
||||||
|
|
||||||
var path = Path.Combine(PathHelper.GetRootPath(), dbName);
|
var path = Path.Combine(PathHelper.GetRootPath(), dbName);
|
||||||
@ -148,6 +162,9 @@ try
|
|||||||
gameDataService.ThrowIfNull();
|
gameDataService.ThrowIfNull();
|
||||||
await gameDataService.InitializeAsync();
|
await gameDataService.InitializeAsync();
|
||||||
|
|
||||||
|
// Use response compression
|
||||||
|
app.UseResponseCompression();
|
||||||
|
|
||||||
// For reverse proxy
|
// For reverse proxy
|
||||||
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
app.UseForwardedHeaders(new ForwardedHeadersOptions
|
||||||
{
|
{
|
||||||
@ -159,22 +176,28 @@ try
|
|||||||
app.UseBlazorFrameworkFiles();
|
app.UseBlazorFrameworkFiles();
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseRouting();
|
app.UseRouting();
|
||||||
|
|
||||||
// Enable Authentication and Authorization middleware
|
// Enable Authentication and Authorization middleware
|
||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseHttpLogging();
|
app.UseHttpLogging();
|
||||||
app.Use(async (context, next) =>
|
app.Use(async (context, next) =>
|
||||||
{
|
{
|
||||||
await next();
|
await next();
|
||||||
|
|
||||||
if (context.Response.StatusCode >= 400)
|
if (context.Response.StatusCode == StatusCodes.Status404NotFound)
|
||||||
{
|
{
|
||||||
Log.Error("Unknown request from: {RemoteIpAddress} {Method} {Path} {StatusCode}",
|
Log.Error("Unknown request from: {RemoteIpAddress} {Method} {Path} {StatusCode}",
|
||||||
context.Connection.RemoteIpAddress, context.Request.Method, context.Request.Path, context.Response.StatusCode);
|
context.Connection.RemoteIpAddress, context.Request.Method, context.Request.Path, context.Response.StatusCode);
|
||||||
Log.Error("Request headers: {Headers}", context.Request.Headers);
|
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.MapControllers();
|
||||||
app.MapFallbackToFile("index.html");
|
app.MapFallbackToFile("index.html");
|
||||||
|
@ -6,11 +6,12 @@ using System.IO.Compression;
|
|||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using TaikoLocalServer.Settings;
|
using TaikoLocalServer.Settings;
|
||||||
|
using TaikoWebUI.Shared.Models;
|
||||||
using Throw;
|
using Throw;
|
||||||
|
|
||||||
namespace TaikoLocalServer.Services;
|
namespace TaikoLocalServer.Services;
|
||||||
|
|
||||||
public class GameDataService : IGameDataService
|
public class GameDataService(IOptions<DataSettings> dataSettings) : IGameDataService
|
||||||
{
|
{
|
||||||
private ImmutableDictionary<uint, DanData> commonDanDataDictionary =
|
private ImmutableDictionary<uint, DanData> commonDanDataDictionary =
|
||||||
ImmutableDictionary<uint, DanData>.Empty;
|
ImmutableDictionary<uint, DanData>.Empty;
|
||||||
@ -18,7 +19,7 @@ public class GameDataService : IGameDataService
|
|||||||
private ImmutableDictionary<uint, DanData> commonGaidenDataDictionary =
|
private ImmutableDictionary<uint, DanData> commonGaidenDataDictionary =
|
||||||
ImmutableDictionary<uint, DanData>.Empty;
|
ImmutableDictionary<uint, DanData>.Empty;
|
||||||
|
|
||||||
private ImmutableDictionary<uint, MusicInfoEntry> musicInfoes =
|
private ImmutableDictionary<uint, MusicInfoEntry> musicInfos =
|
||||||
ImmutableDictionary<uint, MusicInfoEntry>.Empty;
|
ImmutableDictionary<uint, MusicInfoEntry>.Empty;
|
||||||
|
|
||||||
private ImmutableDictionary<uint, MovieData> movieDataDictionary =
|
private ImmutableDictionary<uint, MovieData> movieDataDictionary =
|
||||||
@ -32,37 +33,44 @@ public class GameDataService : IGameDataService
|
|||||||
private ImmutableDictionary<uint, EventFolderData> eventFolderDictionary =
|
private ImmutableDictionary<uint, EventFolderData> eventFolderDictionary =
|
||||||
ImmutableDictionary<uint, EventFolderData>.Empty;
|
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 List<int> costumeFlagArraySizes = new();
|
private List<uint> lockedUraSongsList = [];
|
||||||
|
|
||||||
|
private readonly Dictionary<uint, MusicDetail> musicDetailDictionary = 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 titleFlagArraySize;
|
||||||
|
|
||||||
private int toneFlagArraySize;
|
private int toneFlagArraySize;
|
||||||
|
|
||||||
private Dictionary<string, int> tokenDataDictionary = new();
|
private Dictionary<string, int> tokenDataDictionary = new();
|
||||||
|
|
||||||
private readonly DataSettings settings;
|
private readonly DataSettings settings = dataSettings.Value;
|
||||||
|
|
||||||
public GameDataService(IOptions<DataSettings> settings)
|
|
||||||
{
|
|
||||||
this.settings = settings.Value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<uint> GetMusicList()
|
public List<uint> GetMusicList()
|
||||||
{
|
{
|
||||||
return musics;
|
return musicUniqueIdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<uint> GetMusicWithUraList()
|
public List<uint> GetMusicWithUraList()
|
||||||
{
|
{
|
||||||
return musicsWithUra;
|
return musicWithUraUniqueIdList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImmutableDictionary<uint, MovieData> GetMovieDataDictionary()
|
public ImmutableDictionary<uint, MovieData> GetMovieDataDictionary()
|
||||||
@ -104,10 +112,40 @@ public class GameDataService : IGameDataService
|
|||||||
{
|
{
|
||||||
return lockedSongsList;
|
return lockedSongsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<uint> GetLockedUraSongsList()
|
||||||
|
{
|
||||||
|
return lockedUraSongsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
public List<int> GetCostumeFlagArraySizes()
|
||||||
{
|
{
|
||||||
return costumeFlagArraySizes;
|
return costumeFlagArraySize;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetTitleFlagArraySize()
|
public int GetTitleFlagArraySize()
|
||||||
@ -130,23 +168,23 @@ public class GameDataService : IGameDataService
|
|||||||
var dataPath = PathHelper.GetDataPath();
|
var dataPath = PathHelper.GetDataPath();
|
||||||
var datatablePath = PathHelper.GetDatatablePath();
|
var datatablePath = PathHelper.GetDatatablePath();
|
||||||
|
|
||||||
var musicInfoPath = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.json");
|
var musicInfoPath = Path.Combine(datatablePath, $"{Constants.MusicInfoBaseName}.json");
|
||||||
var encryptedInfo = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.bin");
|
var encryptedInfo = Path.Combine(datatablePath, $"{Constants.MusicInfoBaseName}.bin");
|
||||||
|
|
||||||
var wordlistPath = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.json");
|
var wordlistPath = Path.Combine(datatablePath, $"{Constants.WordlistBaseName}.json");
|
||||||
var encryptedWordlist = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.bin");
|
var encryptedWordlist = Path.Combine(datatablePath, $"{Constants.WordlistBaseName}.bin");
|
||||||
|
|
||||||
var musicOrderPath = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.json");
|
var musicOrderPath = Path.Combine(datatablePath, $"{Constants.MusicOrderBaseName}.json");
|
||||||
var encryptedMusicOrder = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.bin");
|
var encryptedMusicOrder = Path.Combine(datatablePath, $"{Constants.MusicOrderBaseName}.bin");
|
||||||
|
|
||||||
var donCosRewardPath = Path.Combine(datatablePath, $"{Constants.DON_COS_REWARD_BASE_NAME}.json");
|
var donCosRewardPath = Path.Combine(datatablePath, $"{Constants.DonCosRewardBaseName}.json");
|
||||||
var encryptedDonCosReward = Path.Combine(datatablePath, $"{Constants.DON_COS_REWARD_BASE_NAME}.bin");
|
var encryptedDonCosReward = Path.Combine(datatablePath, $"{Constants.DonCosRewardBaseName}.bin");
|
||||||
|
|
||||||
var shougouPath = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.json");
|
var shougouPath = Path.Combine(datatablePath, $"{Constants.ShougouBaseName}.json");
|
||||||
var encryptedShougou = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.bin");
|
var encryptedShougou = Path.Combine(datatablePath, $"{Constants.ShougouBaseName}.bin");
|
||||||
|
|
||||||
var neiroPath = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.json");
|
var neiroPath = Path.Combine(datatablePath, $"{Constants.NeiroBaseName}.json");
|
||||||
var encryptedNeiro = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.bin");
|
var encryptedNeiro = Path.Combine(datatablePath, $"{Constants.NeiroBaseName}.bin");
|
||||||
|
|
||||||
var danDataPath = Path.Combine(dataPath, settings.DanDataFileName);
|
var danDataPath = Path.Combine(dataPath, settings.DanDataFileName);
|
||||||
var gaidenDataPath = Path.Combine(dataPath, settings.GaidenDataFileName);
|
var gaidenDataPath = Path.Combine(dataPath, settings.GaidenDataFileName);
|
||||||
@ -157,6 +195,8 @@ public class GameDataService : IGameDataService
|
|||||||
var tokenDataPath = Path.Combine(dataPath, settings.TokenDataFileName);
|
var tokenDataPath = Path.Combine(dataPath, settings.TokenDataFileName);
|
||||||
var lockedSongsDataPath = Path.Combine(dataPath, settings.LockedSongsDataFileName);
|
var lockedSongsDataPath = Path.Combine(dataPath, settings.LockedSongsDataFileName);
|
||||||
var qrCodeDataPath = Path.Combine(dataPath, settings.QrCodeDataFileName);
|
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>
|
var encryptedFiles = new List<string>
|
||||||
{
|
{
|
||||||
@ -186,12 +226,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);
|
await using var musicInfoFile = File.OpenRead(musicInfoPath);
|
||||||
@ -207,8 +244,12 @@ public class GameDataService : IGameDataService
|
|||||||
await using var shougouFile = File.OpenRead(shougouPath);
|
await using var shougouFile = File.OpenRead(shougouPath);
|
||||||
await using var neiroFile = File.OpenRead(neiroPath);
|
await using var neiroFile = File.OpenRead(neiroPath);
|
||||||
await using var qrCodeDataFile = File.OpenRead(qrCodeDataPath);
|
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 danData = await JsonSerializer.DeserializeAsync<List<DanData>>(danDataFile);
|
||||||
var gaidenData = await JsonSerializer.DeserializeAsync<List<DanData>>(gaidenDataFile);
|
var gaidenData = await JsonSerializer.DeserializeAsync<List<DanData>>(gaidenDataFile);
|
||||||
var introData = await JsonSerializer.DeserializeAsync<List<SongIntroductionData>>(songIntroDataFile);
|
var introData = await JsonSerializer.DeserializeAsync<List<SongIntroductionData>>(songIntroDataFile);
|
||||||
@ -221,8 +262,12 @@ public class GameDataService : IGameDataService
|
|||||||
var shougouData = await JsonSerializer.DeserializeAsync<Shougous>(shougouFile);
|
var shougouData = await JsonSerializer.DeserializeAsync<Shougous>(shougouFile);
|
||||||
var neiroData = await JsonSerializer.DeserializeAsync<Neiros>(neiroFile);
|
var neiroData = await JsonSerializer.DeserializeAsync<Neiros>(neiroFile);
|
||||||
var qrCodeData = await JsonSerializer.DeserializeAsync<List<QRCodeData>>(qrCodeDataFile);
|
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);
|
InitializeDanData(danData);
|
||||||
|
|
||||||
@ -239,10 +284,16 @@ public class GameDataService : IGameDataService
|
|||||||
InitializeTokenData(tokenData);
|
InitializeTokenData(tokenData);
|
||||||
|
|
||||||
InitializeLockedSongsData(lockedSongsData);
|
InitializeLockedSongsData(lockedSongsData);
|
||||||
|
|
||||||
|
InitializeMusicDetails(musicInfoData, musicOrderData, wordlistData);
|
||||||
|
|
||||||
InitializeCostumeFlagArraySizes(donCosRewardData);
|
InitializeCostumes(donCosRewardData, wordlistData);
|
||||||
|
|
||||||
InitializeTitleFlagArraySize(shougouData);
|
InitializeTitles(shougouData, wordlistData);
|
||||||
|
|
||||||
|
InitializeLockedCostumeData(lockedCostumeData);
|
||||||
|
|
||||||
|
InitializeLockedTitleData(lockedTitleData);
|
||||||
|
|
||||||
InitializeToneFlagArraySize(neiroData);
|
InitializeToneFlagArraySize(neiroData);
|
||||||
|
|
||||||
@ -304,16 +355,16 @@ public class GameDataService : IGameDataService
|
|||||||
{
|
{
|
||||||
infosData.ThrowIfNull("Shouldn't happen!");
|
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();
|
.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)
|
.Select(pair => pair.Key)
|
||||||
.ToList();
|
.ToList();
|
||||||
musicsWithUra.Sort();
|
musicWithUraUniqueIdList.Sort();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeShopFolderData(List<ShopFolderData>? shopFolderData)
|
private void InitializeShopFolderData(List<ShopFolderData>? shopFolderData)
|
||||||
@ -332,41 +383,129 @@ public class GameDataService : IGameDataService
|
|||||||
{
|
{
|
||||||
lockedSongsData.ThrowIfNull("Shouldn't happen!");
|
lockedSongsData.ThrowIfNull("Shouldn't happen!");
|
||||||
lockedSongsList = lockedSongsData["songNo"].ToList();
|
lockedSongsList = lockedSongsData["songNo"].ToList();
|
||||||
|
lockedUraSongsList = lockedSongsData["uraSongNo"].ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeMusicDetails(MusicInfos? musicInfoData, MusicOrder? musicOrderData, WordList? wordlistData)
|
||||||
|
{
|
||||||
|
musicInfoData.ThrowIfNull("Shouldn't happen!");
|
||||||
|
musicOrderData.ThrowIfNull("Shouldn't happen!");
|
||||||
|
wordlistData.ThrowIfNull("Shouldn't happen!");
|
||||||
|
|
||||||
|
foreach (var musicInfo in musicInfoData.MusicInfoEntries)
|
||||||
|
{
|
||||||
|
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 musicUniqueId = musicInfo.MusicId;
|
||||||
|
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 InitializeCostumeFlagArraySizes(DonCosRewards? donCosRewardData)
|
private void InitializeCostumes(DonCosRewards? donCosRewardData, WordList? wordlistData)
|
||||||
{
|
{
|
||||||
donCosRewardData.ThrowIfNull("Shouldn't happen!");
|
donCosRewardData.ThrowIfNull("Shouldn't happen!");
|
||||||
var kigurumiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
wordlistData.ThrowIfNull("Shouldn't happen!");
|
||||||
.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>
|
foreach (var donCosReward in donCosRewardData.DonCosRewardEntries)
|
||||||
{
|
{
|
||||||
(int)kigurumiUniqueIdList.Max() + 1,
|
var cosType = donCosReward.CosType;
|
||||||
(int)headUniqueIdList.Max() + 1,
|
var costumeId = donCosReward.UniqueId;
|
||||||
(int)bodyUniqueIdList.Max() + 1,
|
|
||||||
(int)faceUniqueIdList.Max() + 1,
|
var costumeNameKey = $"costume_{cosType}_{costumeId}";
|
||||||
(int)puchiUniqueIdList.Max() + 1
|
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 InitializeTitleFlagArraySize(Shougous? shougouData)
|
private void InitializeTitles(Shougous? shougouData, WordList? wordlistData)
|
||||||
{
|
{
|
||||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
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)
|
private void InitializeToneFlagArraySize(Neiros? neiroData)
|
||||||
|
@ -26,9 +26,21 @@ public interface IGameDataService
|
|||||||
public Dictionary<string, int> GetTokenDataDictionary();
|
public Dictionary<string, int> GetTokenDataDictionary();
|
||||||
|
|
||||||
public List<uint> GetLockedSongsList();
|
public List<uint> GetLockedSongsList();
|
||||||
|
|
||||||
|
public List<uint> GetLockedUraSongsList();
|
||||||
|
|
||||||
|
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 List<int> GetCostumeFlagArraySizes();
|
||||||
|
|
||||||
public int GetTitleFlagArraySize();
|
public int GetTitleFlagArraySize();
|
||||||
|
|
||||||
public int GetToneFlagArraySize();
|
public int GetToneFlagArraySize();
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<PackageReference Include="MediatR" Version="12.2.0" />
|
<PackageReference Include="MediatR" Version="12.2.0" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.4" />
|
<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.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" Version="8.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" 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": [
|
||||||
|
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -53,7 +53,7 @@
|
|||||||
isDarkMode = await LocalStorage.GetItemAsync<bool>("isDarkMode");
|
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
|
// If not logged in, attempt to use JwtToken from local storage to log in
|
||||||
await AuthService.LoginWithAuthToken();
|
await AuthService.LoginWithAuthToken();
|
||||||
|
@ -19,6 +19,12 @@ public partial class AccessCode
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
await InitializeUser();
|
await InitializeUser();
|
||||||
|
|
||||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||||
|
@ -11,6 +11,11 @@ public partial class ChangePassword
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnChangePassword()
|
private async Task OnChangePassword()
|
||||||
|
@ -143,13 +143,13 @@ else
|
|||||||
</MudTooltip>
|
</MudTooltip>
|
||||||
<MudStack Row="true" Spacing="1" Justify="Justify.Center" AlignItems="AlignItems.Center">
|
<MudStack Row="true" Spacing="1" Justify="Justify.Center" AlignItems="AlignItems.Center">
|
||||||
<MudIcon Icon="@Icons.Material.Filled.Star" Size="Size.Small" />
|
<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>
|
</MudStack>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
|
|
||||||
<MudItem xs="9" md="4" Style="display:flex;flex-direction:column;" Class="pl-4">
|
<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.body1" Style="font-weight: bold;">@GameDataService.GetMusicNameBySongId(musicDetailDictionary, danDataOdaiSong.SongNo, @CurrentLanguage)</MudText>
|
||||||
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(danDataOdaiSong.SongNo, @CurrentLanguage)</MudText>
|
<MudText Typo="Typo.caption">@GameDataService.GetMusicArtistBySongId(musicDetailDictionary, danDataOdaiSong.SongNo, @CurrentLanguage)</MudText>
|
||||||
</MudItem>
|
</MudItem>
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,12 +12,18 @@ public partial class DaniDojo
|
|||||||
private UserSetting? userSetting;
|
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();
|
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
response = await Client.GetFromJsonAsync<DanBestDataResponse>($"api/DanBestData/{Baid}");
|
response = await Client.GetFromJsonAsync<DanBestDataResponse>($"api/DanBestData/{Baid}");
|
||||||
response.ThrowIfNull();
|
response.ThrowIfNull();
|
||||||
@ -28,6 +34,8 @@ public partial class DaniDojo
|
|||||||
CurrentLanguage = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
CurrentLanguage = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||||
|
|
||||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||||
|
|
||||||
|
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||||
|
|
||||||
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
||||||
{
|
{
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
@using TaikoWebUI.Shared.Models
|
@using System.Collections.Immutable
|
||||||
@using System.Collections.Immutable
|
|
||||||
@inject IGameDataService GameDataService
|
@inject IGameDataService GameDataService
|
||||||
@inject IJSRuntime Js
|
@inject IJSRuntime Js
|
||||||
|
|
||||||
<MudDialog>
|
<MudDialog>
|
||||||
<DialogContent>
|
<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>
|
<ColGroup>
|
||||||
<col style="width: 50px;" />
|
<col style="width: 50px;" />
|
||||||
<col />
|
<col />
|
||||||
@ -66,9 +65,7 @@
|
|||||||
public bool AllowFreeProfileEditing { get; set; }
|
public bool AllowFreeProfileEditing { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public List<uint> TitleUniqueIdList { get; set; } = new();
|
public List<Title> Titles { get; set; } = new();
|
||||||
|
|
||||||
private IEnumerable<Title> titles = new List<Title>();
|
|
||||||
|
|
||||||
private Title? selectedTitle;
|
private Title? selectedTitle;
|
||||||
|
|
||||||
@ -77,28 +74,13 @@
|
|||||||
protected override void OnInitialized()
|
protected override void OnInitialized()
|
||||||
{
|
{
|
||||||
base.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
|
var currentTitle = new Title
|
||||||
{
|
{
|
||||||
TitleName = UserSetting.Title
|
TitleName = UserSetting.Title
|
||||||
};
|
};
|
||||||
if (titleSet.Contains(currentTitle))
|
if (Titles.Contains(currentTitle))
|
||||||
{
|
{
|
||||||
titleSet.TryGetValue(new Title
|
selectedTitle = currentTitle;
|
||||||
{
|
|
||||||
TitleName = UserSetting.Title
|
|
||||||
}, out selectedTitle);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,14 +22,7 @@
|
|||||||
{
|
{
|
||||||
@if (AuthService.LoginRequired && (!AuthService.IsLoggedIn || (AuthService.GetLoggedInBaid() != Baid && !AuthService.IsAdmin)))
|
@if (AuthService.LoginRequired && (!AuthService.IsLoggedIn || (AuthService.GetLoggedInBaid() != Baid && !AuthService.IsAdmin)))
|
||||||
{
|
{
|
||||||
if (!AuthService.IsLoggedIn)
|
NavigationManager.NavigateTo(AuthService.IsLoggedIn ? "/" : "/Login");
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo("/Login");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
NavigationManager.NavigateTo("/");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -50,7 +43,7 @@
|
|||||||
<MudText Typo="Typo.body2" Style="font-weight:bold">@Localizer["Song Name"]</MudText>
|
<MudText Typo="Typo.body2" Style="font-weight:bold">@Localizer["Song Name"]</MudText>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
<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>
|
<MudText>@Localizer["Level"]</MudText>
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
@ -106,7 +99,7 @@
|
|||||||
</MudTh>
|
</MudTh>
|
||||||
<MudTh>
|
<MudTh>
|
||||||
<MudTableSortLabel T="SongBestData" SortBy="x => x.PlayCount">
|
<MudTableSortLabel T="SongBestData" SortBy="x => x.PlayCount">
|
||||||
<MudText>@Localizer["Total Plays"]</MudText>
|
<MudText>@Localizer["Total Credits Played"]</MudText>
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
<MudTh>
|
<MudTh>
|
||||||
@ -148,7 +141,7 @@
|
|||||||
<MudTd>
|
<MudTd>
|
||||||
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
<MudStack Row="true" Spacing="1" AlignItems="AlignItems.Center">
|
||||||
<MudIcon Icon="@Icons.Material.Filled.Star" Size="Size.Small" />
|
<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>
|
</MudStack>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
<MudTd>
|
<MudTd>
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using static MudBlazor.Colors;
|
using Microsoft.JSInterop;
|
||||||
using System;
|
|
||||||
using Microsoft.JSInterop;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TaikoWebUI.Pages;
|
namespace TaikoWebUI.Pages;
|
||||||
|
|
||||||
@ -15,24 +12,32 @@ public partial class HighScores
|
|||||||
private Dictionary<Difficulty, List<SongBestData>> songBestDataMap = new();
|
private Dictionary<Difficulty, List<SongBestData>> songBestDataMap = new();
|
||||||
|
|
||||||
private readonly List<BreadcrumbItem> breadcrumbs = 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()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
||||||
response.ThrowIfNull();
|
response.ThrowIfNull();
|
||||||
|
|
||||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||||
|
|
||||||
var language = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
var language = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||||
|
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||||
|
|
||||||
response.SongBestData.ForEach(data =>
|
response.SongBestData.ForEach(data =>
|
||||||
{
|
{
|
||||||
var songId = data.SongId;
|
var songId = data.SongId;
|
||||||
data.Genre = GameDataService.GetMusicGenreBySongId(songId);
|
data.Genre = GameDataService.GetMusicGenreBySongId(musicDetailDictionary, songId);
|
||||||
data.MusicName = GameDataService.GetMusicNameBySongId(songId, string.IsNullOrEmpty(language) ? "ja" : language);
|
data.MusicName = GameDataService.GetMusicNameBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(songId, string.IsNullOrEmpty(language) ? "ja" : language);
|
data.MusicArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||||
});
|
});
|
||||||
|
|
||||||
songBestDataMap = response.SongBestData.GroupBy(data => data.Difficulty)
|
songBestDataMap = response.SongBestData.GroupBy(data => data.Difficulty)
|
||||||
@ -40,8 +45,8 @@ public partial class HighScores
|
|||||||
data => data.ToList());
|
data => data.ToList());
|
||||||
foreach (var songBestDataList in songBestDataMap.Values)
|
foreach (var songBestDataList in songBestDataMap.Values)
|
||||||
{
|
{
|
||||||
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(data1.SongId)
|
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data1.SongId)
|
||||||
.CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId)));
|
.CompareTo(GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data2.SongId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set last selected tab from local storage
|
// Set last selected tab from local storage
|
||||||
|
@ -9,6 +9,11 @@ public partial class Login
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnLogin()
|
private async Task OnLogin()
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
@inject IGameDataService GameDataService
|
@inject IGameDataService GameDataService
|
||||||
@inject HttpClient Client
|
@inject HttpClient Client
|
||||||
@inject AuthService AuthService
|
@inject AuthService AuthService
|
||||||
@inject IJSRuntime JSRuntime
|
@inject IJSRuntime JsRuntime
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@using TaikoWebUI.Utilities;
|
|
||||||
@using TaikoWebUI.Shared.Models;
|
|
||||||
@using SharedProject.Enums;
|
|
||||||
|
|
||||||
@page "/Users/{baid:int}/PlayHistory"
|
@page "/Users/{baid:int}/PlayHistory"
|
||||||
|
|
||||||
@ -113,7 +110,7 @@
|
|||||||
ToggledSize="Size.Small"
|
ToggledSize="Size.Small"
|
||||||
Title="Add to favorites" ToggledTitle="Remove from favorites" />
|
Title="Add to favorites" ToggledTitle="Remove from favorites" />
|
||||||
</div>
|
</div>
|
||||||
</MudStack>
|
</MudStack>
|
||||||
</MudTd>
|
</MudTd>
|
||||||
|
|
||||||
@* Genre display *@
|
@* Genre display *@
|
||||||
|
@ -1,9 +1,5 @@
|
|||||||
using static MudBlazor.Colors;
|
using System.Globalization;
|
||||||
using System;
|
|
||||||
using static MudBlazor.CategoryTypes;
|
|
||||||
using System.Globalization;
|
|
||||||
using Microsoft.JSInterop;
|
using Microsoft.JSInterop;
|
||||||
using TaikoWebUI.Shared.Models;
|
|
||||||
|
|
||||||
namespace TaikoWebUI.Pages;
|
namespace TaikoWebUI.Pages;
|
||||||
|
|
||||||
@ -24,22 +20,32 @@ public partial class PlayHistory
|
|||||||
|
|
||||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||||
|
|
||||||
|
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||||
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
||||||
response.ThrowIfNull();
|
response.ThrowIfNull();
|
||||||
|
|
||||||
currentLanguage = await JSRuntime.InvokeAsync<string>("blazorCulture.get");
|
currentLanguage = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||||
|
|
||||||
|
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||||
|
|
||||||
response.SongHistoryData.ForEach(data =>
|
response.SongHistoryData.ForEach(data =>
|
||||||
{
|
{
|
||||||
var songId = data.SongId;
|
var songId = data.SongId;
|
||||||
data.Genre = GameDataService.GetMusicGenreBySongId(songId);
|
data.Genre = GameDataService.GetMusicGenreBySongId(musicDetailDictionary, songId);
|
||||||
data.MusicName = GameDataService.GetMusicNameBySongId(songId, string.IsNullOrEmpty(currentLanguage) ? "ja" : currentLanguage);
|
data.MusicName = GameDataService.GetMusicNameBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(currentLanguage) ? "ja" : currentLanguage);
|
||||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(songId, string.IsNullOrEmpty(currentLanguage) ? "ja" : currentLanguage);
|
data.MusicArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, songId, string.IsNullOrEmpty(currentLanguage) ? "ja" : currentLanguage);
|
||||||
data.Stars = GameDataService.GetMusicStarLevel(songId, data.Difficulty);
|
data.Stars = GameDataService.GetMusicStarLevel(musicDetailDictionary, songId, data.Difficulty);
|
||||||
data.ShowDetails = false;
|
data.ShowDetails = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -126,35 +126,35 @@
|
|||||||
<MudSelect @bind-Value="@response.Head" Label=@Localizer["Head"]>
|
<MudSelect @bind-Value="@response.Head" Label=@Localizer["Head"]>
|
||||||
@foreach (var index in headUniqueIdList)
|
@foreach (var index in headUniqueIdList)
|
||||||
{
|
{
|
||||||
var costumeTitle = GameDataService.GetHeadTitle(index);
|
var costumeTitle = GameDataService.GetHeadTitle(costumeList, index);
|
||||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
<MudSelect @bind-Value="@response.Body" Label=@Localizer["Body"]>
|
<MudSelect @bind-Value="@response.Body" Label=@Localizer["Body"]>
|
||||||
@foreach (var index in bodyUniqueIdList)
|
@foreach (var index in bodyUniqueIdList)
|
||||||
{
|
{
|
||||||
var costumeTitle = GameDataService.GetBodyTitle(index);
|
var costumeTitle = GameDataService.GetBodyTitle(costumeList, index);
|
||||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
<MudSelect @bind-Value="@response.Face" Label=@Localizer["Face"]>
|
<MudSelect @bind-Value="@response.Face" Label=@Localizer["Face"]>
|
||||||
@foreach (var index in faceUniqueIdList)
|
@foreach (var index in faceUniqueIdList)
|
||||||
{
|
{
|
||||||
var costumeTitle = GameDataService.GetFaceTitle(index);
|
var costumeTitle = GameDataService.GetFaceTitle(costumeList, index);
|
||||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
<MudSelect @bind-Value="@response.Kigurumi" Label=@Localizer["Kigurumi"]>
|
<MudSelect @bind-Value="@response.Kigurumi" Label=@Localizer["Kigurumi"]>
|
||||||
@foreach (var index in kigurumiUniqueIdList)
|
@foreach (var index in kigurumiUniqueIdList)
|
||||||
{
|
{
|
||||||
var costumeTitle = GameDataService.GetKigurumiTitle(index);
|
var costumeTitle = GameDataService.GetKigurumiTitle(costumeList, index);
|
||||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
<MudSelect @bind-Value="@response.Puchi" Label=@Localizer["Puchi"]>
|
<MudSelect @bind-Value="@response.Puchi" Label=@Localizer["Puchi"]>
|
||||||
@foreach (var index in puchiUniqueIdList)
|
@foreach (var index in puchiUniqueIdList)
|
||||||
{
|
{
|
||||||
var costumeTitle = GameDataService.GetPuchiTitle(index);
|
var costumeTitle = GameDataService.GetPuchiTitle(costumeList, index);
|
||||||
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
<MudSelectItem Value="@index">@index - @costumeTitle</MudSelectItem>
|
||||||
}
|
}
|
||||||
</MudSelect>
|
</MudSelect>
|
||||||
|
@ -177,15 +177,31 @@ public partial class Profile
|
|||||||
private List<uint> puchiUniqueIdList = new();
|
private List<uint> puchiUniqueIdList = new();
|
||||||
private List<uint> titleUniqueIdList = new();
|
private List<uint> titleUniqueIdList = new();
|
||||||
private List<uint> titlePlateIdList = 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 int[] scoresArray = new int[10];
|
||||||
|
|
||||||
|
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
isSavingOptions = false;
|
isSavingOptions = false;
|
||||||
response = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
response = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||||
response.ThrowIfNull();
|
response.ThrowIfNull();
|
||||||
|
|
||||||
|
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||||
|
|
||||||
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
if (AuthService.IsLoggedIn && !AuthService.IsAdmin)
|
||||||
{
|
{
|
||||||
@ -194,10 +210,15 @@ public partial class Profile
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
breadcrumbs.Add(new BreadcrumbItem(Localizer["Users"], href: "/Users"));
|
||||||
};
|
}
|
||||||
breadcrumbs.Add(new BreadcrumbItem($"{response.MyDonName}", href: null, disabled: true));
|
breadcrumbs.Add(new BreadcrumbItem($"{response.MyDonName}", href: null, disabled: true));
|
||||||
breadcrumbs.Add(new BreadcrumbItem(Localizer["Profile"], href: $"/Users/{Baid}/Profile", disabled: false));
|
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();
|
InitializeAvailableCostumes();
|
||||||
InitializeAvailableTitles();
|
InitializeAvailableTitles();
|
||||||
|
|
||||||
@ -207,9 +228,9 @@ public partial class Profile
|
|||||||
songresponse.SongBestData.ForEach(data =>
|
songresponse.SongBestData.ForEach(data =>
|
||||||
{
|
{
|
||||||
var songId = data.SongId;
|
var songId = data.SongId;
|
||||||
data.Genre = GameDataService.GetMusicGenreBySongId(songId);
|
data.Genre = GameDataService.GetMusicGenreBySongId(musicDetailDictionary, songId);
|
||||||
data.MusicName = GameDataService.GetMusicNameBySongId(songId);
|
data.MusicName = GameDataService.GetMusicNameBySongId(musicDetailDictionary, songId);
|
||||||
data.MusicArtist = GameDataService.GetMusicArtistBySongId(songId);
|
data.MusicArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, songId);
|
||||||
});
|
});
|
||||||
|
|
||||||
songBestDataMap = songresponse.SongBestData.GroupBy(data => data.Difficulty)
|
songBestDataMap = songresponse.SongBestData.GroupBy(data => data.Difficulty)
|
||||||
@ -217,12 +238,12 @@ public partial class Profile
|
|||||||
data => data.ToList());
|
data => data.ToList());
|
||||||
foreach (var songBestDataList in songBestDataMap.Values)
|
foreach (var songBestDataList in songBestDataMap.Values)
|
||||||
{
|
{
|
||||||
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(data1.SongId)
|
songBestDataList.Sort((data1, data2) => GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data1.SongId)
|
||||||
.CompareTo(GameDataService.GetMusicIndexBySongId(data2.SongId)));
|
.CompareTo(GameDataService.GetMusicIndexBySongId(musicDetailDictionary, data2.SongId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < (int)Difficulty.UraOni; i++)
|
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;
|
highestDifficulty = (Difficulty)i;
|
||||||
}
|
}
|
||||||
@ -240,18 +261,30 @@ public partial class Profile
|
|||||||
|
|
||||||
if (AuthService.AllowFreeProfileEditing)
|
if (AuthService.AllowFreeProfileEditing)
|
||||||
{
|
{
|
||||||
kigurumiUniqueIdList = GameDataService.GetKigurumiUniqueIdList();
|
kigurumiUniqueIdList = costumeList.Where(costume => costume.CostumeType == "kigurumi").Select(costume => costume.CostumeId).ToList();
|
||||||
headUniqueIdList = GameDataService.GetHeadUniqueIdList();
|
headUniqueIdList = costumeList.Where(costume => costume.CostumeType == "head").Select(costume => costume.CostumeId).ToList();
|
||||||
bodyUniqueIdList = GameDataService.GetBodyUniqueIdList();
|
bodyUniqueIdList = costumeList.Where(costume => costume.CostumeType == "body").Select(costume => costume.CostumeId).ToList();
|
||||||
faceUniqueIdList = GameDataService.GetFaceUniqueIdList();
|
faceUniqueIdList = costumeList.Where(costume => costume.CostumeType == "face").Select(costume => costume.CostumeId).ToList();
|
||||||
puchiUniqueIdList = GameDataService.GetPuchiUniqueIdList();
|
puchiUniqueIdList = costumeList.Where(costume => costume.CostumeType == "puchi").Select(costume => costume.CostumeId).ToList();
|
||||||
|
|
||||||
// Lock costumes in LockedCostumesList but not in UnlockedCostumesList
|
// Lock costumes in LockedCostumesList but not in UnlockedCostumesList
|
||||||
var lockedKigurumiUniqueIdList = GameDataService.GetLockedKigurumiUniqueIdList().Except(unlockedKigurumi).ToList();
|
lockedCostumeDataDictionary.TryGetValue("kigurumi", out var lockedKigurumiUniqueIdList);
|
||||||
var lockedHeadUniqueIdList = GameDataService.GetLockedHeadUniqueIdList().Except(unlockedHead).ToList();
|
lockedCostumeDataDictionary.TryGetValue("head", out var lockedHeadUniqueIdList);
|
||||||
var lockedBodyUniqueIdList = GameDataService.GetLockedBodyUniqueIdList().Except(unlockedBody).ToList();
|
lockedCostumeDataDictionary.TryGetValue("body", out var lockedBodyUniqueIdList);
|
||||||
var lockedFaceUniqueIdList = GameDataService.GetLockedFaceUniqueIdList().Except(unlockedFace).ToList();
|
lockedCostumeDataDictionary.TryGetValue("face", out var lockedFaceUniqueIdList);
|
||||||
var lockedPuchiUniqueIdList = GameDataService.GetLockedPuchiUniqueIdList().Except(unlockedPuchi).ToList();
|
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));
|
lockedKigurumiUniqueIdList.ForEach(id => kigurumiUniqueIdList.Remove(id));
|
||||||
lockedHeadUniqueIdList.ForEach(id => headUniqueIdList.Remove(id));
|
lockedHeadUniqueIdList.ForEach(id => headUniqueIdList.Remove(id));
|
||||||
@ -262,19 +295,33 @@ public partial class Profile
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only unlock costumes that are in both UnlockedCostumesList and CostumeList
|
// Only unlock costumes that are in both UnlockedCostumesList and CostumeList
|
||||||
kigurumiUniqueIdList = GameDataService.GetKigurumiUniqueIdList().Intersect(unlockedKigurumi).ToList();
|
kigurumiUniqueIdList = costumeList.Where(costume => costume.CostumeType == "kigurumi").Select(costume => costume.CostumeId).Intersect(unlockedKigurumi).ToList();
|
||||||
headUniqueIdList = GameDataService.GetHeadUniqueIdList().Intersect(unlockedHead).ToList();
|
headUniqueIdList = costumeList.Where(costume => costume.CostumeType == "head").Select(costume => costume.CostumeId).Intersect(unlockedHead).ToList();
|
||||||
bodyUniqueIdList = GameDataService.GetBodyUniqueIdList().Intersect(unlockedBody).ToList();
|
bodyUniqueIdList = costumeList.Where(costume => costume.CostumeType == "body").Select(costume => costume.CostumeId).Intersect(unlockedBody).ToList();
|
||||||
faceUniqueIdList = GameDataService.GetFaceUniqueIdList().Intersect(unlockedFace).ToList();
|
faceUniqueIdList = costumeList.Where(costume => costume.CostumeType == "face").Select(costume => costume.CostumeId).Intersect(unlockedFace).ToList();
|
||||||
puchiUniqueIdList = GameDataService.GetPuchiUniqueIdList().Intersect(unlockedPuchi).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()
|
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
|
// 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()
|
private void InitializeAvailableTitles()
|
||||||
@ -285,23 +332,32 @@ public partial class Profile
|
|||||||
|
|
||||||
if (AuthService.AllowFreeProfileEditing)
|
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
|
// Lock titles in LockedTitlesList but not in UnlockedTitle
|
||||||
var lockedTitleUniqueIdList = GameDataService.GetLockedTitleUniqueIdList().ToList();
|
lockedTitleDataDictionary.TryGetValue("title", out var lockedTitleUniqueIdList);
|
||||||
var lockedTitlePlateIdList = GameDataService.GetLockedTitlePlateIdList().ToList();
|
lockedTitleDataDictionary.TryGetValue("titlePlate", out var lockedTitlePlateIdList);
|
||||||
|
|
||||||
|
lockedTitleUniqueIdList ??= new List<uint>();
|
||||||
|
lockedTitlePlateIdList ??= new List<uint>();
|
||||||
|
|
||||||
// Unlock titles in UnlockedTitlesList
|
// Unlock titles in UnlockedTitlesList
|
||||||
lockedTitleUniqueIdList = lockedTitleUniqueIdList.Except(unlockedTitle).ToList();
|
lockedTitleUniqueIdList = lockedTitleUniqueIdList.Except(unlockedTitle).ToList();
|
||||||
// Find uniqueIds of titles with rarity in lockedTitlePlateIdList
|
// 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();
|
titleUniqueIdList = titleUniqueIdList.Except(lockedTitleUniqueIdList).ToList();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Only unlock titles that are in both UnlockedTitlesList and TitleList
|
// 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()
|
private async Task SaveOptions()
|
||||||
@ -323,11 +379,22 @@ public partial class Profile
|
|||||||
response.AchievementDisplayDifficulty = difficulty;
|
response.AchievementDisplayDifficulty = difficulty;
|
||||||
scoresArray = new int[10];
|
scoresArray = new int[10];
|
||||||
|
|
||||||
if (difficulty is Difficulty.None) difficulty = highestDifficulty;
|
if (difficulty == Difficulty.None) difficulty = highestDifficulty;
|
||||||
|
|
||||||
if (!songBestDataMap.TryGetValue(difficulty, out var values)) return;
|
if (!songBestDataMap.TryGetValue(difficulty, out var values)) return;
|
||||||
|
|
||||||
foreach (var value in values)
|
var valuesList = new List<SongBestData>(values);
|
||||||
|
|
||||||
|
if (difficulty == Difficulty.UraOni)
|
||||||
|
{
|
||||||
|
// Also include Oni scores
|
||||||
|
if (songBestDataMap.TryGetValue(Difficulty.Oni, out var oniValues))
|
||||||
|
{
|
||||||
|
valuesList.AddRange(oniValues);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var value in valuesList)
|
||||||
{
|
{
|
||||||
switch (value.BestScoreRank)
|
switch (value.BestScoreRank)
|
||||||
{
|
{
|
||||||
@ -368,6 +435,7 @@ public partial class Profile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string CostumeOrDefault(string file, uint id, string defaultfile)
|
public static string CostumeOrDefault(string file, uint id, string defaultfile)
|
||||||
{
|
{
|
||||||
var path = "/images/Costumes/";
|
var path = "/images/Costumes/";
|
||||||
@ -391,7 +459,7 @@ public partial class Profile
|
|||||||
{
|
{
|
||||||
{x => x.UserSetting, response},
|
{x => x.UserSetting, response},
|
||||||
{x => x.AllowFreeProfileEditing, AuthService.AllowFreeProfileEditing},
|
{x => x.AllowFreeProfileEditing, AuthService.AllowFreeProfileEditing},
|
||||||
{x => x.TitleUniqueIdList, titleUniqueIdList}
|
{x => x.Titles, unlockedTitles},
|
||||||
};
|
};
|
||||||
var dialog = DialogService.Show<ChooseTitleDialog>("Player Titles", parameters, options);
|
var dialog = DialogService.Show<ChooseTitleDialog>("Player Titles", parameters, options);
|
||||||
var result = await dialog.Result;
|
var result = await dialog.Result;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
@inject HttpClient Client
|
@inject IDialogService DialogService
|
||||||
@inject IDialogService DialogService
|
|
||||||
@inject AuthService AuthService
|
@inject AuthService AuthService
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
|
|
||||||
|
@ -16,6 +16,11 @@ public partial class Register
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task OnRegister()
|
private async Task OnRegister()
|
||||||
|
@ -21,6 +21,11 @@ namespace TaikoWebUI.Pages
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
response = await Client.GetFromJsonAsync<SongHistoryResponse>($"api/PlayHistory/{(uint)Baid}");
|
||||||
response.ThrowIfNull();
|
response.ThrowIfNull();
|
||||||
@ -29,11 +34,13 @@ namespace TaikoWebUI.Pages
|
|||||||
|
|
||||||
// Get user settings
|
// Get user settings
|
||||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||||
|
|
||||||
|
var musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||||
|
|
||||||
// Get song title and artist
|
// Get song title and artist
|
||||||
var language = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
var language = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||||
songTitle = GameDataService.GetMusicNameBySongId((uint)SongId, string.IsNullOrEmpty(language) ? "ja" : language);
|
songTitle = GameDataService.GetMusicNameBySongId(musicDetailDictionary, (uint)SongId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||||
songArtist = GameDataService.GetMusicArtistBySongId((uint)SongId, string.IsNullOrEmpty(language) ? "ja" : language);
|
songArtist = GameDataService.GetMusicArtistBySongId(musicDetailDictionary, (uint)SongId, string.IsNullOrEmpty(language) ? "ja" : language);
|
||||||
|
|
||||||
// Breadcrumbs
|
// Breadcrumbs
|
||||||
var formattedSongTitle = songTitle;
|
var formattedSongTitle = songTitle;
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
@inject IJSRuntime JsRuntime
|
@inject IJSRuntime JsRuntime
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@using TaikoWebUI.Utilities;
|
@using TaikoWebUI.Utilities;
|
||||||
@using TaikoWebUI.Shared.Models;
|
|
||||||
|
|
||||||
@page "/Users/{baid:int}/Songs"
|
@page "/Users/{baid:int}/Songs"
|
||||||
|
|
||||||
@ -27,7 +26,7 @@
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
<MudItem xs="12">
|
<MudItem xs="12">
|
||||||
<MudTable Items="musicMap" Elevation="0" Outlined="true" Filter="@FilterSongs">
|
<MudTable Items="musicDetailDictionary.Values" Elevation="0" Outlined="true" Filter="@FilterSongs">
|
||||||
<ToolBarContent>
|
<ToolBarContent>
|
||||||
<MudGrid Spacing="2">
|
<MudGrid Spacing="2">
|
||||||
<MudItem xs="12" md="8">
|
<MudItem xs="12" md="8">
|
||||||
@ -56,7 +55,7 @@
|
|||||||
</ToolBarContent>
|
</ToolBarContent>
|
||||||
<HeaderContent>
|
<HeaderContent>
|
||||||
<MudTh>
|
<MudTh>
|
||||||
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicNameBySongId(context.SongId, CurrentLanguage)">
|
<MudTableSortLabel T="MusicDetail" SortBy="context => GameDataService.GetMusicNameBySongId(musicDetailDictionary, context.SongId, CurrentLanguage)">
|
||||||
@Localizer["Song Title / Artist"]
|
@Localizer["Song Title / Artist"]
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
@ -70,7 +69,7 @@
|
|||||||
@if (difficulty is not Difficulty.None)
|
@if (difficulty is not Difficulty.None)
|
||||||
{
|
{
|
||||||
<MudTh>
|
<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" />
|
<img src="@ScoreUtils.GetDifficultyIcon(difficulty)" alt="@ScoreUtils.GetDifficultyTitle(difficulty)" style="@Constants.ICON_STYLE" />
|
||||||
</MudTableSortLabel>
|
</MudTableSortLabel>
|
||||||
</MudTh>
|
</MudTh>
|
||||||
@ -83,10 +82,10 @@
|
|||||||
<div>
|
<div>
|
||||||
<a href="@($"/Users/{Baid}/Songs/{context.SongId}")">
|
<a href="@($"/Users/{Baid}/Songs/{context.SongId}")">
|
||||||
<MudText Typo="Typo.body2" Style="font-weight:bold">
|
<MudText Typo="Typo.body2" Style="font-weight:bold">
|
||||||
@GameDataService.GetMusicNameBySongId(context.SongId, CurrentLanguage)
|
@GameDataService.GetMusicNameBySongId(musicDetailDictionary, context.SongId, CurrentLanguage)
|
||||||
</MudText>
|
</MudText>
|
||||||
<MudText Typo="Typo.caption">
|
<MudText Typo="Typo.caption">
|
||||||
@GameDataService.GetMusicArtistBySongId(context.SongId, CurrentLanguage)
|
@GameDataService.GetMusicArtistBySongId(musicDetailDictionary, context.SongId, CurrentLanguage)
|
||||||
</MudText>
|
</MudText>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -110,7 +109,7 @@
|
|||||||
{
|
{
|
||||||
@if (difficulty is not Difficulty.None)
|
@if (difficulty is not Difficulty.None)
|
||||||
{
|
{
|
||||||
var starLevel = GameDataService.GetMusicStarLevel(context.SongId, difficulty);
|
var starLevel = GameDataService.GetMusicStarLevel(musicDetailDictionary, context.SongId, difficulty);
|
||||||
<MudTd>
|
<MudTd>
|
||||||
@if (starLevel > 0)
|
@if (starLevel > 0)
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,4 @@
|
|||||||
using System.Reflection.Emit;
|
using Microsoft.JSInterop;
|
||||||
using Microsoft.JSInterop;
|
|
||||||
using TaikoWebUI.Shared.Models;
|
|
||||||
|
|
||||||
|
|
||||||
namespace TaikoWebUI.Pages;
|
namespace TaikoWebUI.Pages;
|
||||||
|
|
||||||
@ -18,17 +15,23 @@ public partial class SongList
|
|||||||
private UserSetting? userSetting;
|
private UserSetting? userSetting;
|
||||||
|
|
||||||
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
private readonly List<BreadcrumbItem> breadcrumbs = new();
|
||||||
|
|
||||||
private List<MusicDetail> musicMap = new();
|
private Dictionary<uint, MusicDetail> musicDetailDictionary = new();
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
response = await Client.GetFromJsonAsync<SongBestResponse>($"api/PlayData/{Baid}");
|
||||||
response.ThrowIfNull();
|
response.ThrowIfNull();
|
||||||
|
|
||||||
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
userSetting = await Client.GetFromJsonAsync<UserSetting>($"api/UserSettings/{Baid}");
|
||||||
musicMap = GameDataService.GetMusicList();
|
musicDetailDictionary = await GameDataService.GetMusicDetailDictionary();
|
||||||
|
|
||||||
CurrentLanguage = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
CurrentLanguage = await JsRuntime.InvokeAsync<string>("blazorCulture.get");
|
||||||
|
|
||||||
|
@ -7,6 +7,11 @@ public partial class Users
|
|||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
await base.OnInitializedAsync();
|
await base.OnInitializedAsync();
|
||||||
|
if (AuthService.LoginRequired && !AuthService.IsLoggedIn)
|
||||||
|
{
|
||||||
|
await AuthService.LoginWithAuthToken();
|
||||||
|
}
|
||||||
|
|
||||||
if (AuthService.IsAdmin || !AuthService.LoginRequired)
|
if (AuthService.IsAdmin || !AuthService.LoginRequired)
|
||||||
{
|
{
|
||||||
users = await Client.GetFromJsonAsync<List<User>>("api/Users");
|
users = await Client.GetFromJsonAsync<List<User>>("api/Users");
|
||||||
|
@ -10,6 +10,16 @@ var builder = WebAssemblyHostBuilder.CreateDefault(args);
|
|||||||
builder.RootComponents.Add<App>("#app");
|
builder.RootComponents.Add<App>("#app");
|
||||||
builder.RootComponents.Add<HeadOutlet>("head::after");
|
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
|
builder.Services.AddSingleton(sp => new HttpClient
|
||||||
{
|
{
|
||||||
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
|
BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
|
||||||
@ -17,18 +27,16 @@ builder.Services.AddSingleton(sp => new HttpClient
|
|||||||
builder.Services.AddMudServices();
|
builder.Services.AddMudServices();
|
||||||
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
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.AddScoped<AuthService>();
|
||||||
builder.Services.AddLocalization();
|
builder.Services.AddLocalization();
|
||||||
builder.Services.AddSingleton<MudLocalizer, ResXMudLocalizer>();
|
builder.Services.AddSingleton<MudLocalizer, ResXMudLocalizer>();
|
||||||
builder.Services.AddSingleton<ScoreUtils>();
|
builder.Services.AddSingleton<ScoreUtils>();
|
||||||
builder.Services.AddSingleton<StringUtil>();
|
builder.Services.AddSingleton<StringUtil>();
|
||||||
|
|
||||||
|
|
||||||
builder.Services.AddBlazoredLocalStorage();
|
builder.Services.AddBlazoredLocalStorage();
|
||||||
|
|
||||||
|
|
||||||
var host = builder.Build();
|
var host = builder.Build();
|
||||||
|
|
||||||
var gameDataService = host.Services.GetRequiredService<IGameDataService>();
|
var gameDataService = host.Services.GetRequiredService<IGameDataService>();
|
||||||
@ -51,4 +59,4 @@ else
|
|||||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||||
CultureInfo.DefaultThreadCurrentUICulture = 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.Net.Http.Headers;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@ -23,8 +22,10 @@ public sealed class AuthService
|
|||||||
public bool IsAdmin { get; private set; }
|
public bool IsAdmin { get; private set; }
|
||||||
private readonly ILocalStorageService localStorage;
|
private readonly ILocalStorageService localStorage;
|
||||||
private readonly HttpClient client;
|
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;
|
this.localStorage = localStorage;
|
||||||
IsLoggedIn = false;
|
IsLoggedIn = false;
|
||||||
@ -37,6 +38,7 @@ public sealed class AuthService
|
|||||||
AllowUserDelete = webUiSettings.AllowUserDelete;
|
AllowUserDelete = webUiSettings.AllowUserDelete;
|
||||||
AllowFreeProfileEditing = webUiSettings.AllowFreeProfileEditing;
|
AllowFreeProfileEditing = webUiSettings.AllowFreeProfileEditing;
|
||||||
this.client = client;
|
this.client = client;
|
||||||
|
this.navigationManager = navigationManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnLoginStatusChanged()
|
private void OnLoginStatusChanged()
|
||||||
@ -105,11 +107,19 @@ public sealed class AuthService
|
|||||||
public async Task LoginWithAuthToken()
|
public async Task LoginWithAuthToken()
|
||||||
{
|
{
|
||||||
var hasAuthToken = await localStorage.ContainKeyAsync("authToken");
|
var hasAuthToken = await localStorage.ContainKeyAsync("authToken");
|
||||||
if (!hasAuthToken) return;
|
if (!hasAuthToken)
|
||||||
|
{
|
||||||
|
navigationManager.NavigateTo("/Login");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Attempt to get JWT token from local storage
|
// Attempt to get JWT token from local storage
|
||||||
var authToken = await localStorage.GetItemAsync<string>("authToken");
|
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);
|
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", authToken);
|
||||||
var responseMessage = await client.PostAsync("api/Auth/LoginWithToken", null);
|
var responseMessage = await client.PostAsync("api/Auth/LoginWithToken", null);
|
||||||
@ -117,6 +127,7 @@ public sealed class AuthService
|
|||||||
{
|
{
|
||||||
// Clear JWT token
|
// Clear JWT token
|
||||||
await localStorage.RemoveItemAsync("authToken");
|
await localStorage.RemoveItemAsync("authToken");
|
||||||
|
navigationManager.NavigateTo("/Login");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,38 +1,21 @@
|
|||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
using Swan.Mapping;
|
|
||||||
using TaikoWebUI.Shared.Models;
|
|
||||||
|
|
||||||
namespace TaikoWebUI.Services;
|
namespace TaikoWebUI.Services;
|
||||||
|
|
||||||
public class GameDataService : IGameDataService
|
public class GameDataService : IGameDataService
|
||||||
{
|
{
|
||||||
private readonly HttpClient client;
|
private readonly HttpClient client;
|
||||||
private readonly Dictionary<uint, MusicDetail> musicMap = new();
|
|
||||||
private ImmutableDictionary<uint, DanData> danMap = ImmutableDictionary<uint, DanData>.Empty;
|
private ImmutableDictionary<uint, DanData> danMap = ImmutableDictionary<uint, DanData>.Empty;
|
||||||
private ImmutableHashSet<Title> titles = ImmutableHashSet<Title>.Empty;
|
private Dictionary<uint, MusicDetail>? musicDetailDictionary = new();
|
||||||
|
private List<Costume>? costumeList;
|
||||||
private string[] bodyTitles = { };
|
private Dictionary<uint,Title>? titleDictionary = new();
|
||||||
private string[] faceTitles = { };
|
|
||||||
private string[] headTitles = { };
|
|
||||||
private string[] kigurumiTitles = { };
|
|
||||||
private string[] puchiTitles = { };
|
|
||||||
|
|
||||||
private List<uint> kigurumiUniqueIdList = new();
|
private bool musicDetailInitialized;
|
||||||
private List<uint> headUniqueIdList = new();
|
private bool costumesInitialized;
|
||||||
private List<uint> bodyUniqueIdList = new();
|
private bool titlesInitialized;
|
||||||
private List<uint> faceUniqueIdList = new();
|
|
||||||
private List<uint> puchiUniqueIdList = new();
|
|
||||||
|
|
||||||
private List<uint> titleUniqueIdList = new();
|
|
||||||
private List<uint> titlePlateIdList = new();
|
|
||||||
|
|
||||||
private List<uint> lockedKigurumiUniqueIdList = new();
|
private Dictionary<string, List<uint>>? lockedCostumeDataDictionary = new();
|
||||||
private List<uint> lockedHeadUniqueIdList = new();
|
private Dictionary<string, List<uint>>? lockedTitleDataDictionary = 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();
|
|
||||||
|
|
||||||
public GameDataService(HttpClient client)
|
public GameDataService(HttpClient client)
|
||||||
{
|
{
|
||||||
@ -42,58 +25,64 @@ public class GameDataService : IGameDataService
|
|||||||
public async Task InitializeAsync(string dataBaseUrl)
|
public async Task InitializeAsync(string dataBaseUrl)
|
||||||
{
|
{
|
||||||
dataBaseUrl = dataBaseUrl.TrimEnd('/');
|
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");
|
var danData = await client.GetFromJsonAsync<List<DanData>>($"{dataBaseUrl}/data/dan_data.json");
|
||||||
|
|
||||||
danData.ThrowIfNull();
|
danData.ThrowIfNull();
|
||||||
danMap = danData.ToImmutableDictionary(data => data.DanId);
|
danMap = danData.ToImmutableDictionary(data => data.DanId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Dictionary<uint, MusicDetail>> GetMusicDetailDictionary()
|
||||||
|
{
|
||||||
|
if (!musicDetailInitialized)
|
||||||
|
{
|
||||||
|
await InitializeMusicDetailAsync();
|
||||||
|
}
|
||||||
|
|
||||||
// To prevent duplicate entries in wordlist
|
return musicDetailDictionary ?? new Dictionary<uint, MusicDetail>();
|
||||||
var wordlistDict = wordList.WordListEntries.GroupBy(entry => entry.Key)
|
}
|
||||||
.ToImmutableDictionary(group => group.Key, group => group.First());
|
|
||||||
await Task.Run(() => InitializeMusicMap(musicInfo, wordlistDict, musicOrder));
|
public async Task<List<Costume>> GetCostumeList()
|
||||||
|
{
|
||||||
|
if (!costumesInitialized)
|
||||||
|
{
|
||||||
|
await InitializeCostumesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
await Task.Run(() => InitializeCostumeIdLists(donCosRewardData));
|
return costumeList ?? new List<Costume>();
|
||||||
await Task.Run(() => InitializeTitleIdList(shougouData));
|
}
|
||||||
|
|
||||||
await Task.Run(() => InitializeHeadTitles(wordlistDict));
|
public async Task<Dictionary<uint, Title>> GetTitleDictionary()
|
||||||
await Task.Run(() => InitializeFaceTitles(wordlistDict));
|
{
|
||||||
await Task.Run(() => InitializeBodyTitles(wordlistDict));
|
if (!titlesInitialized)
|
||||||
await Task.Run(() => InitializePuchiTitles(wordlistDict));
|
{
|
||||||
await Task.Run(() => InitializeKigurumiTitles(wordlistDict));
|
await InitializeTitlesAsync();
|
||||||
await Task.Run(() => InitializeTitles(wordlistDict, shougouData));
|
}
|
||||||
|
|
||||||
var lockedCostumeDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>($"{dataBaseUrl}/data/locked_costume_data.json") ?? throw new InvalidOperationException();
|
return titleDictionary ?? new Dictionary<uint, Title>();
|
||||||
lockedKigurumiUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Kigurumi") ?? new List<uint>();
|
}
|
||||||
lockedHeadUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Head") ?? new List<uint>();
|
|
||||||
lockedBodyUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Body") ?? new List<uint>();
|
public async Task<Dictionary<string, List<uint>>> GetLockedCostumeDataDictionary()
|
||||||
lockedFaceUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Face") ?? new List<uint>();
|
{
|
||||||
lockedPuchiUniqueIdList = lockedCostumeDataDictionary.GetValueOrDefault("Puchi") ?? new List<uint>();
|
if (!costumesInitialized)
|
||||||
|
{
|
||||||
|
await InitializeCostumesAsync();
|
||||||
|
}
|
||||||
|
|
||||||
var lockedTitleDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>($"{dataBaseUrl}/data/locked_title_data.json") ?? throw new InvalidOperationException();
|
return lockedCostumeDataDictionary ?? new Dictionary<string, List<uint>>();
|
||||||
lockedTitleUniqueIdList = lockedTitleDataDictionary.GetValueOrDefault("TitleNo") ?? new List<uint>();
|
}
|
||||||
lockedTitlePlateIdList = lockedTitleDataDictionary.GetValueOrDefault("TitlePlateNo") ?? new 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");
|
return musicDetails.TryGetValue(songId, out var musicDetail) ? language switch
|
||||||
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
|
|
||||||
{
|
{
|
||||||
"ja" => musicDetail.SongName,
|
"ja" => musicDetail.SongName,
|
||||||
"en-US" => musicDetail.SongNameEN,
|
"en-US" => musicDetail.SongNameEN,
|
||||||
@ -104,9 +93,9 @@ public class GameDataService : IGameDataService
|
|||||||
} : string.Empty;
|
} : 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,
|
"jp" => musicDetail.ArtistName,
|
||||||
"en-US" => musicDetail.ArtistNameEN,
|
"en-US" => musicDetail.ArtistNameEN,
|
||||||
@ -117,14 +106,14 @@ public class GameDataService : IGameDataService
|
|||||||
} : string.Empty;
|
} : 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)
|
public DanData GetDanDataById(uint danId)
|
||||||
@ -132,9 +121,9 @@ public class GameDataService : IGameDataService
|
|||||||
return danMap.GetValueOrDefault(danId, new DanData());
|
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
|
return difficulty switch
|
||||||
{
|
{
|
||||||
Difficulty.None => throw new ArgumentException("Difficulty cannot be none"),
|
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;
|
return costumes.FirstOrDefault(costume => costume.CostumeType == "puchi" && costume.CostumeId == index)?.CostumeName ?? string.Empty;
|
||||||
}
|
|
||||||
|
|
||||||
public ImmutableHashSet<Title> GetTitles()
|
|
||||||
{
|
|
||||||
return titles;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
titleDictionary = await client.GetFromJsonAsync<Dictionary<uint, Title>>("api/GameData/Titles");
|
||||||
}
|
lockedTitleDataDictionary = await client.GetFromJsonAsync<Dictionary<string, List<uint>>>("api/GameData/LockedTitles");
|
||||||
|
titlesInitialized = true;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,47 +1,34 @@
|
|||||||
using System.Collections.Immutable;
|
namespace TaikoWebUI.Services;
|
||||||
using TaikoWebUI.Shared.Models;
|
|
||||||
|
|
||||||
namespace TaikoWebUI.Services;
|
|
||||||
|
|
||||||
public interface IGameDataService
|
public interface IGameDataService
|
||||||
{
|
{
|
||||||
public Task InitializeAsync(string dataBaseUrl);
|
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 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 GetHeadTitle(IEnumerable<Costume> costumes, uint index);
|
||||||
public string GetKigurumiTitle(uint index);
|
public string GetKigurumiTitle(IEnumerable<Costume> costumes, uint index);
|
||||||
public string GetBodyTitle(uint index);
|
public string GetBodyTitle(IEnumerable<Costume> costumes, uint index);
|
||||||
public string GetFaceTitle(uint index);
|
public string GetFaceTitle(IEnumerable<Costume> costumes, uint index);
|
||||||
public string GetPuchiTitle(uint index);
|
public string GetPuchiTitle(IEnumerable<Costume> costumes, 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();
|
|
||||||
}
|
}
|
@ -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