diff --git a/TaikoLocalServer/.gitignore b/TaikoLocalServer/.gitignore index c6ea86d..388d155 100644 --- a/TaikoLocalServer/.gitignore +++ b/TaikoLocalServer/.gitignore @@ -1 +1 @@ -wwwroot/music_attribute.json \ No newline at end of file +wwwroot/data/music_attribute.json \ No newline at end of file diff --git a/TaikoLocalServer/Common/Constants.cs b/TaikoLocalServer/Common/Constants.cs index 13ef74c..427594e 100644 --- a/TaikoLocalServer/Common/Constants.cs +++ b/TaikoLocalServer/Common/Constants.cs @@ -35,4 +35,6 @@ public static class Constants public const int COSTUME_FLAG_3_ARRAY_SIZE = 156; public const int COSTUME_FLAG_4_ARRAY_SIZE = 58; public const int COSTUME_FLAG_5_ARRAY_SIZE = 129; + + public static readonly int[] CostumeFlagArraySizes = {154, 140, 156, 58, 129}; } \ No newline at end of file diff --git a/TaikoLocalServer/Common/Utils/FlagCalculator.cs b/TaikoLocalServer/Common/Utils/FlagCalculator.cs index b967908..9193d93 100644 --- a/TaikoLocalServer/Common/Utils/FlagCalculator.cs +++ b/TaikoLocalServer/Common/Utils/FlagCalculator.cs @@ -1,4 +1,5 @@ -using System.Collections.Specialized; +using System.Collections; +using System.Collections.Specialized; using System.Runtime.InteropServices; namespace TaikoLocalServer.Common.Utils; @@ -106,4 +107,22 @@ public static class FlagCalculator gotDanFlagList.Add(gotDanFlag.Data); return MemoryMarshal.AsBytes(new ReadOnlySpan(gotDanFlagList.ToArray())).ToArray(); } + + public static byte[] GetBitArrayFromIds(IEnumerable idArray, int bitArraySize, ILogger logger) + { + var result = new byte[bitArraySize / 8 + 1]; + var bitSet = new BitArray(bitArraySize + 1); + foreach (var id in idArray) + { + if (id >= bitArraySize) + { + logger.LogWarning("Id out of range!"); + continue; + } + bitSet.Set((int)id, true); + } + bitSet.CopyTo(result, 0); + + return result; + } } \ No newline at end of file diff --git a/TaikoLocalServer/Common/Utils/PathHelper.cs b/TaikoLocalServer/Common/Utils/PathHelper.cs index 4154003..152d29f 100644 --- a/TaikoLocalServer/Common/Utils/PathHelper.cs +++ b/TaikoLocalServer/Common/Utils/PathHelper.cs @@ -14,6 +14,6 @@ public static class PathHelper { throw new ApplicationException(); } - return Path.Combine(parentPath.ToString(), "wwwroot"); + return Path.Combine(parentPath.ToString(), "wwwroot", "data"); } } \ No newline at end of file diff --git a/TaikoLocalServer/Controllers/Game/BaidController.cs b/TaikoLocalServer/Controllers/Game/BaidController.cs index d7b05c3..3ffd832 100644 --- a/TaikoLocalServer/Controllers/Game/BaidController.cs +++ b/TaikoLocalServer/Controllers/Game/BaidController.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; -using System.Collections; -using System.Text.Json; +using System.Text.Json; using TaikoLocalServer.Services.Interfaces; using Throw; @@ -76,23 +74,9 @@ public class BaidController : BaseController datum.Difficulty == achievementDisplayDifficulty : datum.Difficulty is Difficulty.Oni or Difficulty.UraOni).ToList(); - var crownCount = new uint[3]; - foreach (var crownType in Enum.GetValues()) - { - if (crownType != CrownType.None) - { - crownCount[(int)crownType - 1] = (uint)songCountData.Count(datum => datum.BestCrown == crownType); - } - } + var crownCount = CalculateCrownCount(songCountData); - var scoreRankCount = new uint[7]; - foreach (var scoreRankType in Enum.GetValues()) - { - if (scoreRankType != ScoreRank.None) - { - scoreRankCount[(int)scoreRankType - 2] = (uint)songCountData.Count(datum => datum.BestScoreRank == scoreRankType); - } - } + var scoreRankCount = CalculateScoreRankCount(songCountData); var costumeData = new List{ 0, 0, 0, 0, 0 }; @@ -124,45 +108,9 @@ public class BaidController : BaseController // which means database content need to be fixed, so better throw costumeArrays.ThrowIfNull("Costume flg should never be null!"); - var costumeFlg1 = new byte[Constants.COSTUME_FLAG_1_ARRAY_SIZE]; - var bitSet = new BitArray(Constants.COSTUME_FLAG_1_ARRAY_SIZE); - foreach (var costume in costumeArrays[0]) - { - bitSet.Set((int)costume, true); - } - bitSet.CopyTo(costumeFlg1, 0); - - var costumeFlg2 = new byte[Constants.COSTUME_FLAG_2_ARRAY_SIZE]; - bitSet = new BitArray(Constants.COSTUME_FLAG_2_ARRAY_SIZE); - foreach (var costume in costumeArrays[1]) - { - bitSet.Set((int)costume, true); - } - bitSet.CopyTo(costumeFlg2, 0); - - var costumeFlg3 = new byte[Constants.COSTUME_FLAG_3_ARRAY_SIZE]; - bitSet = new BitArray(Constants.COSTUME_FLAG_3_ARRAY_SIZE); - foreach (var costume in costumeArrays[2]) - { - bitSet.Set((int)costume, true); - } - bitSet.CopyTo(costumeFlg3, 0); - - var costumeFlg4 = new byte[Constants.COSTUME_FLAG_4_ARRAY_SIZE]; - bitSet = new BitArray(Constants.COSTUME_FLAG_4_ARRAY_SIZE); - foreach (var costume in costumeArrays[3]) - { - bitSet.Set((int)costume, true); - } - bitSet.CopyTo(costumeFlg4, 0); - - var costumeFlg5 = new byte[Constants.COSTUME_FLAG_5_ARRAY_SIZE]; - bitSet = new BitArray(Constants.COSTUME_FLAG_5_ARRAY_SIZE); - foreach (var costume in costumeArrays[4]) - { - bitSet.Set((int)costume, true); - } - bitSet.CopyTo(costumeFlg5, 0); + var costumeFlagArrays = Constants.CostumeFlagArraySizes + .Select((size, index) => FlagCalculator.GetBitArrayFromIds(costumeArrays[index], size, Logger)) + .ToList(); var danData = await danScoreDatumService.GetDanScoreDatumByBaid(baid); @@ -199,11 +147,11 @@ public class BaidController : BaseController Costume4 = costumeData[3], Costume5 = costumeData[4] }, - CostumeFlg1 = costumeFlg1, - CostumeFlg2 = costumeFlg2, - CostumeFlg3 = costumeFlg3, - CostumeFlg4 = costumeFlg4, - CostumeFlg5 = costumeFlg5, + CostumeFlg1 = costumeFlagArrays[0], + CostumeFlg2 = costumeFlagArrays[1], + CostumeFlg3 = costumeFlagArrays[2], + CostumeFlg4 = costumeFlagArrays[3], + CostumeFlg5 = costumeFlagArrays[4], LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DATE_TIME_FORMAT), IsDispDanOn = userData.DisplayDan, GotDanMax = maxDan, @@ -227,4 +175,32 @@ public class BaidController : BaseController return Ok(response); } + private static uint[] CalculateScoreRankCount(IReadOnlyCollection songCountData) + { + var scoreRankCount = new uint[7]; + foreach (var scoreRankType in Enum.GetValues()) + { + if (scoreRankType != ScoreRank.None) + { + scoreRankCount[(int)scoreRankType - 2] = + (uint)songCountData.Count(datum => datum.BestScoreRank == scoreRankType); + } + } + + return scoreRankCount; + } + + private static uint[] CalculateCrownCount(IReadOnlyCollection songCountData) + { + var crownCount = new uint[3]; + foreach (var crownType in Enum.GetValues()) + { + if (crownType != CrownType.None) + { + crownCount[(int)crownType - 1] = (uint)songCountData.Count(datum => datum.BestCrown == crownType); + } + } + + return crownCount; + } } \ No newline at end of file diff --git a/TaikoLocalServer/Controllers/Game/PlayResultController.cs b/TaikoLocalServer/Controllers/Game/PlayResultController.cs index 173ea16..bc1cbed 100644 --- a/TaikoLocalServer/Controllers/Game/PlayResultController.cs +++ b/TaikoLocalServer/Controllers/Game/PlayResultController.cs @@ -1,7 +1,6 @@ using System.Buffers.Binary; using System.Globalization; using System.Text.Json; -using TaikoLocalServer.Entities; using TaikoLocalServer.Services.Interfaces; using Throw; @@ -66,7 +65,7 @@ public class PlayResultController : BaseController if (playMode == PlayMode.AiBattle) { - await UpdateAiBattleData(request, stageData); + // await UpdateAiBattleData(request, stageData); // Update AI win count here somewhere, or in UpdatePlayData? // I have no clue how to update input median or variance } @@ -75,7 +74,7 @@ public class PlayResultController : BaseController await UpdatePlayData(request, songNumber, stageData, lastPlayDatetime); } - + return Ok(response); } @@ -193,23 +192,80 @@ public class PlayResultController : BaseController userdata.LastPlayDatetime = lastPlayDatetime; userdata.LastPlayMode = playResultData.PlayMode; - var toneFlgData = JsonSerializer.Deserialize>(userdata.ToneFlgArray); - toneFlgData?.AddRange(playResultData.GetToneNoes ?? new uint[0]); - userdata.ToneFlgArray = JsonSerializer.Serialize(toneFlgData); - var titleFlgData = JsonSerializer.Deserialize>(userdata.TitleFlgArray); - titleFlgData?.AddRange(playResultData.GetTitleNoes ?? new uint[0]); - userdata.TitleFlgArray = JsonSerializer.Serialize(titleFlgData); - var costumeFlgData = JsonSerializer.Deserialize>>(userdata.CostumeFlgArray); - costumeFlgData?[0].AddRange(playResultData.GetCostumeNo1s ?? new uint[0]); - costumeFlgData?[1].AddRange(playResultData.GetCostumeNo2s ?? new uint[0]); - costumeFlgData?[2].AddRange(playResultData.GetCostumeNo3s ?? new uint[0]); - costumeFlgData?[3].AddRange(playResultData.GetCostumeNo4s ?? new uint[0]); - costumeFlgData?[4].AddRange(playResultData.GetCostumeNo5s ?? new uint[0]); - userdata.CostumeFlgArray = JsonSerializer.Serialize(costumeFlgData); + userdata.ToneFlgArray = + UpdateJsonUintFlagArray(userdata.ToneFlgArray, playResultData.GetToneNoes, nameof(userdata.ToneFlgArray)); + + userdata.TitleFlgArray = + UpdateJsonUintFlagArray(userdata.TitleFlgArray, playResultData.GetTitleNoes, + nameof(userdata.TitleFlgArray)); + + userdata.CostumeFlgArray = UpdateJsonCostumeFlagArray(userdata.CostumeFlgArray, + new[] + { + playResultData.GetCostumeNo1s, + playResultData.GetCostumeNo2s, + playResultData.GetCostumeNo3s, + playResultData.GetCostumeNo4s, + playResultData.GetCostumeNo5s + }); await userDatumService.UpdateUserDatum(userdata); } + private string UpdateJsonUintFlagArray(string originalValue, IReadOnlyCollection? newValue, string fieldName) + { + var flgData = new List(); + try + { + flgData = JsonSerializer.Deserialize>(originalValue); + } + catch (JsonException e) + { + Logger.LogError(e, "Parsing {FieldName} json data failed", fieldName); + } + + flgData?.AddRange(newValue ?? Array.Empty()); + var flgArray = flgData ?? new List(); + return JsonSerializer.Serialize(flgArray); + } + + private string UpdateJsonCostumeFlagArray(string originalValue, IReadOnlyList?>? newValue) + { + var flgData = new List>(); + try + { + flgData = JsonSerializer.Deserialize>>(originalValue); + } + catch (JsonException e) + { + Logger.LogError(e, "Parsing Costume flag json data failed"); + } + + if (flgData is null) + { + flgData = new List>(); + } + + for (var index = 0; index < flgData.Count; index++) + { + var subFlgData = flgData[index]; + subFlgData.AddRange(newValue?[index] ?? Array.Empty()); + } + + if (flgData.Count >= 5) + { + return JsonSerializer.Serialize(flgData); + } + + Logger.LogWarning("Costume flag array count less than 5!"); + flgData = new List> + { + new(), new(), new(), new(), new() + }; + + return JsonSerializer.Serialize(flgData); + } + private async Task UpdateBestData(PlayResultRequest request, StageData stageData, IEnumerable bestData) { @@ -231,7 +287,8 @@ public class PlayResultController : BaseController await songBestDatumService.UpdateOrInsertSongBestDatum(bestDatum); } - private async Task UpdateAiBattleData(PlayResultRequest request, StageData stageData) + // TODO: AI battle + /*private async Task UpdateAiBattleData(PlayResultRequest request, StageData stageData) { for (int i = 0; i < stageData.ArySectionDatas.Count; i++) { @@ -242,7 +299,7 @@ public class PlayResultController : BaseController // if any aspect of the section is higher than the previous best, update it // Similar to Dan best play updates } - } + }*/ private static CrownType PlayResultToCrown(StageData stageData) { diff --git a/TaikoLocalServer/Controllers/Game/UserDataController.cs b/TaikoLocalServer/Controllers/Game/UserDataController.cs index 8db6b30..554a51c 100644 --- a/TaikoLocalServer/Controllers/Game/UserDataController.cs +++ b/TaikoLocalServer/Controllers/Game/UserDataController.cs @@ -1,5 +1,4 @@ using System.Buffers.Binary; -using System.Collections; using System.Text.Json; using TaikoLocalServer.Services.Interfaces; using Throw; @@ -28,21 +27,11 @@ public class UserDataController : BaseController var musicAttributeManager = MusicAttributeManager.Instance; - var releaseSongArray = new byte[Constants.MUSIC_FLAG_ARRAY_SIZE]; - var bitSet = new BitArray(Constants.MUSIC_ID_MAX); - foreach (var music in musicAttributeManager.Musics) - { - bitSet.Set((int)music, true); - } - bitSet.CopyTo(releaseSongArray, 0); - - var uraSongArray = new byte[Constants.MUSIC_FLAG_ARRAY_SIZE]; - bitSet.SetAll(false); - foreach (var music in musicAttributeManager.MusicsWithUra) - { - bitSet.Set((int)music, true); - } - bitSet.CopyTo(uraSongArray, 0); + var releaseSongArray = + FlagCalculator.GetBitArrayFromIds(musicAttributeManager.Musics, Constants.MUSIC_ID_MAX, Logger); + + var uraSongArray = + FlagCalculator.GetBitArrayFromIds(musicAttributeManager.MusicsWithUra, Constants.MUSIC_ID_MAX, Logger); var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid); @@ -60,13 +49,7 @@ public class UserDataController : BaseController // which means database content need to be fixed, so better throw toneFlg.ThrowIfNull("Tone flg should never be null!"); - var toneArray = new byte[Constants.TONE_UID_MAX]; - bitSet = new BitArray(Constants.TONE_UID_MAX); - foreach (var tone in toneFlg) - { - bitSet.Set((int)tone, true); - } - bitSet.CopyTo(toneArray, 0); + var toneArray = FlagCalculator.GetBitArrayFromIds(toneFlg, Constants.TONE_UID_MAX, Logger); var titleFlg = Array.Empty(); try @@ -82,13 +65,7 @@ public class UserDataController : BaseController // which means database content need to be fixed, so better throw titleFlg.ThrowIfNull("Title flg should never be null!"); - var titleArray = new byte[Constants.TITLE_UID_MAX]; - bitSet = new BitArray(Constants.TITLE_UID_MAX); - foreach (var title in titleFlg) - { - bitSet.Set((int)title, true); - } - bitSet.CopyTo(titleArray, 0); + var titleArray = FlagCalculator.GetBitArrayFromIds(titleFlg, Constants.TITLE_UID_MAX, Logger); var recentSongs = (await songPlayDatumService.GetSongPlayDatumByBaid(request.Baid)) .AsEnumerable() diff --git a/TaikoLocalServer/TaikoLocalServer.csproj b/TaikoLocalServer/TaikoLocalServer.csproj index da79960..fd477fb 100644 --- a/TaikoLocalServer/TaikoLocalServer.csproj +++ b/TaikoLocalServer/TaikoLocalServer.csproj @@ -38,7 +38,7 @@ PreserveNewest - + PreserveNewest