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