1
0
mirror of synced 2024-12-18 09:25:56 +01:00

Move data folder

Use singleton service instead of self made singleton
This commit is contained in:
asesidaa 2022-09-14 21:11:06 +08:00
parent 23988544c4
commit 963bd1701b
14 changed files with 205 additions and 157 deletions

View File

@ -1,48 +0,0 @@
using System.Collections.Immutable;
using System.Text.Json;
using SharedProject.Models;
using Swan.Mapping;
namespace TaikoLocalServer.Common.Utils;
public class DanOdaiDataManager
{
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> OdaiDataList { get; }
static DanOdaiDataManager() {}
private DanOdaiDataManager()
{
var dataPath = PathHelper.GetDataPath();
var filePath = Path.Combine(dataPath, Constants.DAN_DATA_FILE_NAME);
var jsonString = File.ReadAllText(filePath);
var result = JsonSerializer.Deserialize<List<DanData>>(jsonString);
if (result is null)
{
throw new ApplicationException("Cannot parse dan data json!");
}
OdaiDataList = result.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData);
}
private GetDanOdaiResponse.OdaiData ToResponseOdaiData(DanData data)
{
var responseOdaiData = new GetDanOdaiResponse.OdaiData
{
DanId = data.DanId,
Title = data.Title,
VerupNo = data.VerupNo
};
var odaiSongs = data.OdaiSongList.Select(song => song.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiSong>());
responseOdaiData.AryOdaiSongs.AddRange(odaiSongs);
var odaiBorders = data.OdaiBorderList.Select(border => border.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiBorder>());
responseOdaiData.AryOdaiBorders.AddRange(odaiBorders);
return responseOdaiData;
}
public static DanOdaiDataManager Instance { get; } = new();
}

View File

@ -1,42 +0,0 @@
using System.Text.Json;
namespace TaikoLocalServer.Common.Utils;
public class MusicAttributeManager
{
public readonly Dictionary<uint,MusicAttributeEntry> MusicAttributes;
static MusicAttributeManager()
{
}
private MusicAttributeManager()
{
var dataPath = PathHelper.GetDataPath();
var filePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_FILE_NAME);
var jsonString = File.ReadAllText(filePath);
var result = JsonSerializer.Deserialize<MusicAttributes>(jsonString);
if (result is null)
{
throw new ApplicationException("Cannot parse music attribute json!");
}
MusicAttributes = result.MusicAttributeEntries.ToDictionary(attribute => attribute.MusicId);
Musics = MusicAttributes.Select(pair => pair.Key)
.ToList();
Musics.Sort();
MusicsWithUra = MusicAttributes.Where(attribute => attribute.Value.HasUra)
.Select(pair => pair.Key)
.ToList();
MusicsWithUra.Sort();
}
public static MusicAttributeManager Instance { get; } = new();
public readonly List<uint> Musics;
public readonly List<uint> MusicsWithUra;
}

View File

@ -1,42 +0,0 @@
using System.Collections.Immutable;
using System.Text.Json;
using SharedProject.Models;
namespace TaikoLocalServer.Common.Utils;
public class SongIntroductionDataManager
{
public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> IntroDataList { get; }
static SongIntroductionDataManager() { }
private SongIntroductionDataManager()
{
var dataPath = PathHelper.GetDataPath();
var filePath = Path.Combine(dataPath, Constants.INTRO_DATA_FILE_NAME);
var jsonString = File.ReadAllText(filePath);
var result = JsonSerializer.Deserialize<List<SongIntroductionData>>(jsonString);
if (result is null)
{
throw new ApplicationException("Cannot parse intro data json!");
}
IntroDataList = result.ToImmutableDictionary(data => data.SetId, ToResponseIntroData);
}
private GetSongIntroductionResponse.SongIntroductionData ToResponseIntroData(SongIntroductionData data)
{
var responseOdaiData = new GetSongIntroductionResponse.SongIntroductionData
{
SetId = data.SetId,
VerupNo = data.VerupNo,
MainSongNo = data.MainSongNo,
SubSongNoes = data.SubSongNo
};
return responseOdaiData;
}
public static SongIntroductionDataManager Instance { get; } = new();
}

View File

@ -1,9 +1,18 @@
namespace TaikoLocalServer.Controllers.Game; using TaikoLocalServer.Services.Interfaces;
namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getdanodai.php")] [Route("/v12r03/chassis/getdanodai.php")]
[ApiController] [ApiController]
public class GetDanOdaiController : BaseController<GetDanOdaiController> public class GetDanOdaiController : BaseController<GetDanOdaiController>
{ {
private readonly IGameDataService gameDataService;
public GetDanOdaiController(IGameDataService gameDataService)
{
this.gameDataService = gameDataService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult GetDanOdai([FromBody] GetDanOdaiRequest request) public IActionResult GetDanOdai([FromBody] GetDanOdaiRequest request)
@ -20,10 +29,9 @@ public class GetDanOdaiController : BaseController<GetDanOdaiController>
return Ok(response); return Ok(response);
} }
var manager = DanOdaiDataManager.Instance;
foreach (var danId in request.DanIds) foreach (var danId in request.DanIds)
{ {
manager.OdaiDataList.TryGetValue(danId, out var odaiData); gameDataService.GetDanDataDictionary().TryGetValue(danId, out var odaiData);
if (odaiData is null) if (odaiData is null)
{ {
Logger.LogWarning("Requested dan id {Id} does not exist!", danId); Logger.LogWarning("Requested dan id {Id} does not exist!", danId);

View File

@ -1,9 +1,18 @@
namespace TaikoLocalServer.Controllers.Game; using TaikoLocalServer.Services.Interfaces;
namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/getsongintroduction.php")] [Route("/v12r03/chassis/getsongintroduction.php")]
[ApiController] [ApiController]
public class GetSongIntroductionController : BaseController<GetSongIntroductionController> public class GetSongIntroductionController : BaseController<GetSongIntroductionController>
{ {
private readonly IGameDataService gameDataService;
public GetSongIntroductionController(IGameDataService gameDataService)
{
this.gameDataService = gameDataService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult GetSongIntroduction([FromBody] GetSongIntroductionRequest request) public IActionResult GetSongIntroduction([FromBody] GetSongIntroductionRequest request)
@ -15,10 +24,9 @@ public class GetSongIntroductionController : BaseController<GetSongIntroductionC
Result = 1 Result = 1
}; };
var manager = SongIntroductionDataManager.Instance;
foreach (var setId in request.SetIds) foreach (var setId in request.SetIds)
{ {
manager.IntroDataList.TryGetValue(setId, out var introData); gameDataService.GetSongIntroDictionary().TryGetValue(setId, out var introData);
if (introData is null) if (introData is null)
{ {
Logger.LogWarning("Requested set id {Id} does not exist!", setId); Logger.LogWarning("Requested set id {Id} does not exist!", setId);

View File

@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using TaikoLocalServer.Services.Interfaces;
namespace TaikoLocalServer.Controllers.Game; namespace TaikoLocalServer.Controllers.Game;
@ -6,17 +7,22 @@ namespace TaikoLocalServer.Controllers.Game;
[Route("/v12r03/chassis/initialdatacheck.php")] [Route("/v12r03/chassis/initialdatacheck.php")]
public class InitialDataCheckController : BaseController<InitialDataCheckController> public class InitialDataCheckController : BaseController<InitialDataCheckController>
{ {
private readonly IGameDataService gameDataService;
public InitialDataCheckController(IGameDataService gameDataService)
{
this.gameDataService = gameDataService;
}
[HttpPost] [HttpPost]
[Produces("application/protobuf")] [Produces("application/protobuf")]
public IActionResult InitialDataCheck([FromBody] InitialdatacheckRequest request) public IActionResult InitialDataCheck([FromBody] InitialdatacheckRequest request)
{ {
Logger.LogInformation("Initial data check request: {Request}", request.Stringify()); Logger.LogInformation("Initial data check request: {Request}", request.Stringify());
var musicAttributeManager = MusicAttributeManager.Instance;
var enabledArray = new byte[Constants.MUSIC_FLAG_ARRAY_SIZE]; var enabledArray = new byte[Constants.MUSIC_FLAG_ARRAY_SIZE];
var bitSet = new BitArray(Constants.MUSIC_ID_MAX); var bitSet = new BitArray(Constants.MUSIC_ID_MAX);
foreach (var music in musicAttributeManager.Musics) foreach (var music in gameDataService.GetMusicList())
{ {
bitSet.Set((int)music, true); bitSet.Set((int)music, true);
} }
@ -32,9 +38,8 @@ public class InitialDataCheckController : BaseController<InitialDataCheckControl
}); });
} }
var manager = SongIntroductionDataManager.Instance;
var introData = new List<InitialdatacheckResponse.InformationData>(); var introData = new List<InitialdatacheckResponse.InformationData>();
for (var setId = 1; setId <= manager.IntroDataList.Count; setId++) for (var setId = 1; setId <= gameDataService.GetSongIntroDictionary().Count; setId++)
{ {
introData.Add(new InitialdatacheckResponse.InformationData introData.Add(new InitialdatacheckResponse.InformationData
{ {

View File

@ -9,9 +9,12 @@ public class SelfBestController : BaseController<SelfBestController>
{ {
private readonly ISongBestDatumService songBestDatumService; private readonly ISongBestDatumService songBestDatumService;
public SelfBestController(ISongBestDatumService songBestDatumService) private readonly IGameDataService gameDataService;
public SelfBestController(ISongBestDatumService songBestDatumService, IGameDataService gameDataService)
{ {
this.songBestDatumService = songBestDatumService; this.songBestDatumService = songBestDatumService;
this.gameDataService = gameDataService;
} }
[HttpPost] [HttpPost]
@ -26,8 +29,6 @@ public class SelfBestController : BaseController<SelfBestController>
Level = request.Level Level = request.Level
}; };
var manager = MusicAttributeManager.Instance;
var requestDifficulty = (Difficulty)request.Level; var requestDifficulty = (Difficulty)request.Level;
requestDifficulty.Throw().IfOutOfRange(); requestDifficulty.Throw().IfOutOfRange();
@ -38,7 +39,7 @@ public class SelfBestController : BaseController<SelfBestController>
.ToList(); .ToList();
foreach (var songNo in request.ArySongNoes) foreach (var songNo in request.ArySongNoes)
{ {
if (!manager.MusicAttributes.ContainsKey(songNo)) if (!gameDataService.GetMusicAttributes().ContainsKey(songNo))
{ {
Logger.LogWarning("Music no {No} is missing!", songNo); Logger.LogWarning("Music no {No} is missing!", songNo);
continue; continue;

View File

@ -13,10 +13,13 @@ public class UserDataController : BaseController<UserDataController>
private readonly ISongPlayDatumService songPlayDatumService; private readonly ISongPlayDatumService songPlayDatumService;
public UserDataController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService) private readonly IGameDataService gameDataService;
public UserDataController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService, IGameDataService gameDataService)
{ {
this.userDatumService = userDatumService; this.userDatumService = userDatumService;
this.songPlayDatumService = songPlayDatumService; this.songPlayDatumService = songPlayDatumService;
this.gameDataService = gameDataService;
} }
[HttpPost] [HttpPost]
@ -25,13 +28,11 @@ public class UserDataController : BaseController<UserDataController>
{ {
Logger.LogInformation("UserData request : {Request}", request.Stringify()); Logger.LogInformation("UserData request : {Request}", request.Stringify());
var musicAttributeManager = MusicAttributeManager.Instance;
var releaseSongArray = var releaseSongArray =
FlagCalculator.GetBitArrayFromIds(musicAttributeManager.Musics, Constants.MUSIC_ID_MAX, Logger); FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicList(), Constants.MUSIC_ID_MAX, Logger);
var uraSongArray = var uraSongArray =
FlagCalculator.GetBitArrayFromIds(musicAttributeManager.MusicsWithUra, Constants.MUSIC_ID_MAX, Logger); FlagCalculator.GetBitArrayFromIds(gameDataService.GetMusicWithUraList(), Constants.MUSIC_ID_MAX, Logger);
var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid); var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid);

View File

@ -6,6 +6,7 @@ using TaikoLocalServer.Services;
using TaikoLocalServer.Services.Extentions; using TaikoLocalServer.Services.Extentions;
using TaikoLocalServer.Services.Interfaces; using TaikoLocalServer.Services.Interfaces;
using TaikoLocalServer.Settings; using TaikoLocalServer.Settings;
using Throw;
var builder = WebApplication.CreateBuilder(args); var builder = WebApplication.CreateBuilder(args);
// Manually enable tls 1.0 // Manually enable tls 1.0
@ -19,6 +20,7 @@ builder.WebHost.UseKestrel(kestrelOptions =>
// Add services to the container. // Add services to the container.
builder.Services.AddOptions(); builder.Services.AddOptions();
builder.Services.AddSingleton<IGameDataService, GameDataService>();
builder.Services.Configure<UrlSettings>(builder.Configuration.GetSection(nameof(UrlSettings))); builder.Services.Configure<UrlSettings>(builder.Configuration.GetSection(nameof(UrlSettings)));
builder.Services.AddControllers().AddProtoBufNet(); builder.Services.AddControllers().AddProtoBufNet();
builder.Services.AddDbContext<TaikoDbContext>(option => builder.Services.AddDbContext<TaikoDbContext>(option =>
@ -58,6 +60,10 @@ using (var scope = app.Services.CreateScope())
db.Database.Migrate(); db.Database.Migrate();
} }
var gameDataService = app.Services.GetService<IGameDataService>();
gameDataService.ThrowIfNull();
await gameDataService.InitializeAsync();
// For reverse proxy // For reverse proxy
app.UseForwardedHeaders(new ForwardedHeadersOptions app.UseForwardedHeaders(new ForwardedHeadersOptions
{ {

View File

@ -0,0 +1,130 @@
using System.Collections.Immutable;
using System.Text.Json;
using SharedProject.Models;
using Swan.Mapping;
using TaikoLocalServer.Services.Interfaces;
using Throw;
namespace TaikoLocalServer.Services;
public class GameDataService : IGameDataService
{
private ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> danDataDictionary =
ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData>.Empty;
private ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> introDataDictionary =
ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData>.Empty;
private ImmutableDictionary<uint, MusicAttributeEntry> musicAttributes =
ImmutableDictionary<uint, MusicAttributeEntry>.Empty;
private List<uint> musics = new();
private List<uint> musicsWithUra = new();
public List<uint> GetMusicList()
{
return musics;
}
public List<uint> GetMusicWithUraList()
{
return musicsWithUra;
}
public ImmutableDictionary<uint, MusicAttributeEntry> GetMusicAttributes()
{
return musicAttributes;
}
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary()
{
return danDataDictionary;
}
public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary()
{
return introDataDictionary;
}
public async Task InitializeAsync()
{
var dataPath = PathHelper.GetDataPath();
var musicAttributePath = Path.Combine(dataPath, Constants.MUSIC_ATTRIBUTE_FILE_NAME);
var danDataPath = Path.Combine(dataPath, Constants.DAN_DATA_FILE_NAME);
var songIntroDataPath = Path.Combine(dataPath, Constants.INTRO_DATA_FILE_NAME);
await using var musicAttributeFile = File.OpenRead(musicAttributePath);
await using var danDataFile = File.OpenRead(danDataPath);
await using var songIntroDataFile = File.OpenRead(songIntroDataPath);
var attributesData = await JsonSerializer.DeserializeAsync<MusicAttributes>(musicAttributeFile);
var danData = await JsonSerializer.DeserializeAsync<List<DanData>>(danDataFile);
var introData = await JsonSerializer.DeserializeAsync<List<SongIntroductionData>>(songIntroDataFile);
InitializeMusicAttributes(attributesData);
InitializeDanData(danData);
InitializeIntroData(introData);
}
private void InitializeIntroData(List<SongIntroductionData>? introData)
{
introData.ThrowIfNull("Shouldn't happen!");
introDataDictionary = introData.ToImmutableDictionary(data => data.SetId, ToResponseIntroData);
}
private void InitializeDanData(List<DanData>? danData)
{
danData.ThrowIfNull("Shouldn't happen!");
danDataDictionary = danData.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData);
}
private void InitializeMusicAttributes(MusicAttributes? attributesData)
{
attributesData.ThrowIfNull("Shouldn't happen!");
musicAttributes = attributesData.MusicAttributeEntries.ToImmutableDictionary(attribute => attribute.MusicId);
musics = musicAttributes.Select(pair => pair.Key)
.ToList();
musics.Sort();
musicsWithUra = musicAttributes.Where(attribute => attribute.Value.HasUra)
.Select(pair => pair.Key)
.ToList();
musicsWithUra.Sort();
}
private static GetDanOdaiResponse.OdaiData ToResponseOdaiData(DanData data)
{
var responseOdaiData = new GetDanOdaiResponse.OdaiData
{
DanId = data.DanId,
Title = data.Title,
VerupNo = data.VerupNo
};
var odaiSongs = data.OdaiSongList.Select(song => song.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiSong>());
responseOdaiData.AryOdaiSongs.AddRange(odaiSongs);
var odaiBorders = data.OdaiBorderList.Select(border => border.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiBorder>());
responseOdaiData.AryOdaiBorders.AddRange(odaiBorders);
return responseOdaiData;
}
private static GetSongIntroductionResponse.SongIntroductionData ToResponseIntroData(SongIntroductionData data)
{
var responseOdaiData = new GetSongIntroductionResponse.SongIntroductionData
{
SetId = data.SetId,
VerupNo = data.VerupNo,
MainSongNo = data.MainSongNo,
SubSongNoes = data.SubSongNo
};
return responseOdaiData;
}
}

View File

@ -0,0 +1,18 @@
using System.Collections.Immutable;
namespace TaikoLocalServer.Services.Interfaces;
public interface IGameDataService
{
public Task InitializeAsync();
public List<uint> GetMusicList();
public List<uint> GetMusicWithUraList();
public ImmutableDictionary<uint, MusicAttributeEntry> GetMusicAttributes();
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary();
public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary();
}

View File

@ -35,10 +35,13 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Update="wwwroot\dan_data.json"> <Content Update="wwwroot\data\music_attribute.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
<Content Update="wwwroot\data\music_attribute.json"> <Content Update="wwwroot\data\dan_data.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Update="wwwroot\data\intro_data.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content> </Content>
</ItemGroup> </ItemGroup>