Stage initial refactors
This commit is contained in:
parent
0cfa5f2033
commit
a88965bdd1
@ -4,35 +4,38 @@ namespace GameDatabase.Entities
|
||||
{
|
||||
public partial class UserDatum
|
||||
{
|
||||
public uint Baid { get; set; }
|
||||
public string MyDonName { get; set; } = string.Empty;
|
||||
public uint MyDonNameLanguage { get; set; }
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public uint TitlePlateId { get; set; }
|
||||
public string FavoriteSongsArray { get; set; } = "[]";
|
||||
public string ToneFlgArray { get; set; } = "[]";
|
||||
public string TitleFlgArray { get; set; } = "[]";
|
||||
public string CostumeFlgArray { get; set; } = "[[],[],[],[],[]]";
|
||||
public string GenericInfoFlgArray { get; set; } = "[]";
|
||||
public short OptionSetting { get; set; }
|
||||
public int NotesPosition { get; set; }
|
||||
public bool IsVoiceOn { get; set; }
|
||||
public bool IsSkipOn { get; set; }
|
||||
public string DifficultyPlayedArray { get; set; } = "[]";
|
||||
public string DifficultySettingArray { get; set; } = "[]";
|
||||
public uint SelectedToneId { get; set; }
|
||||
public DateTime LastPlayDatetime { get; set; }
|
||||
public uint LastPlayMode { get; set; }
|
||||
public uint ColorBody { get; set; }
|
||||
public uint ColorFace { get; set; }
|
||||
public uint ColorLimb { get; set; }
|
||||
public string CostumeData { get; set; } = "[]";
|
||||
public bool DisplayDan { get; set; }
|
||||
public bool DisplayAchievement { get; set; }
|
||||
public Difficulty AchievementDisplayDifficulty { get; set; }
|
||||
public int AiWinCount { get; set; }
|
||||
public List<Token> Tokens { get; set; } = new();
|
||||
public string UnlockedSongIdList { get; set; } = "[]";
|
||||
public bool IsAdmin { get; set; }
|
||||
public uint Baid { get; set; }
|
||||
public string MyDonName { get; set; } = string.Empty;
|
||||
public uint MyDonNameLanguage { get; set; }
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public uint TitlePlateId { get; set; }
|
||||
public uint[] FavoriteSongsArray { get; set; } = Array.Empty<uint>();
|
||||
public uint[] ToneFlgArray { get; set; } = Array.Empty<uint>();
|
||||
public uint[] TitleFlgArray { get; set; } = Array.Empty<uint>();
|
||||
public string CostumeFlgArray { get; set; } = "[[],[],[],[],[]]";
|
||||
public uint[] GenericInfoFlgArray { get; set; } = Array.Empty<uint>();
|
||||
public short OptionSetting { get; set; }
|
||||
public int NotesPosition { get; set; }
|
||||
public bool IsVoiceOn { get; set; }
|
||||
public bool IsSkipOn { get; set; }
|
||||
// TODO: Split into separate fields
|
||||
public string DifficultyPlayedArray { get; set; } = "[]";
|
||||
// TODO: Split into separate fields
|
||||
public string DifficultySettingArray { get; set; } = "[]";
|
||||
public uint SelectedToneId { get; set; }
|
||||
public DateTime LastPlayDatetime { get; set; }
|
||||
public uint LastPlayMode { get; set; }
|
||||
public uint ColorBody { get; set; }
|
||||
public uint ColorFace { get; set; }
|
||||
public uint ColorLimb { get; set; }
|
||||
// TODO: Split into separate fields
|
||||
public string CostumeData { get; set; } = "[]";
|
||||
public bool DisplayDan { get; set; }
|
||||
public bool DisplayAchievement { get; set; }
|
||||
public Difficulty AchievementDisplayDifficulty { get; set; }
|
||||
public int AiWinCount { get; set; }
|
||||
public List<Token> Tokens { get; set; } = new();
|
||||
public uint[] UnlockedSongIdList { get; set; } = Array.Empty<uint>();
|
||||
public bool IsAdmin { get; set; }
|
||||
}
|
||||
}
|
@ -33,7 +33,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasKey("Baid", "SongId", "Difficulty");
|
||||
|
||||
b.ToTable("AiScoreData");
|
||||
b.ToTable("AiScoreData", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiSectionScoreDatum", b =>
|
||||
@ -73,7 +73,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasKey("Baid", "SongId", "Difficulty", "SectionIndex");
|
||||
|
||||
b.ToTable("AiSectionScoreData");
|
||||
b.ToTable("AiSectionScoreData", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Card", b =>
|
||||
@ -138,7 +138,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasKey("Baid", "DanId", "DanType");
|
||||
|
||||
b.ToTable("DanScoreData");
|
||||
b.ToTable("DanScoreData", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.DanStageScoreDatum", b =>
|
||||
@ -183,7 +183,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasKey("Baid", "DanId", "DanType", "SongNumber");
|
||||
|
||||
b.ToTable("DanStageScoreData");
|
||||
b.ToTable("DanStageScoreData", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongBestDatum", b =>
|
||||
@ -211,7 +211,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasKey("Baid", "SongId", "Difficulty");
|
||||
|
||||
b.ToTable("SongBestData");
|
||||
b.ToTable("SongBestData", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.SongPlayDatum", b =>
|
||||
@ -272,7 +272,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasIndex("Baid");
|
||||
|
||||
b.ToTable("SongPlayData");
|
||||
b.ToTable("SongPlayData", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.Token", b =>
|
||||
@ -288,7 +288,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasKey("Baid", "Id");
|
||||
|
||||
b.ToTable("Tokens");
|
||||
b.ToTable("Tokens", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.UserDatum", b =>
|
||||
@ -394,7 +394,7 @@ namespace TaikoLocalServer.Migrations
|
||||
|
||||
b.HasKey("Baid");
|
||||
|
||||
b.ToTable("UserData");
|
||||
b.ToTable("UserData", (string)null);
|
||||
});
|
||||
|
||||
modelBuilder.Entity("GameDatabase.Entities.AiScoreDatum", b =>
|
||||
|
10
SharedProject/Enums/NameLanguage.cs
Normal file
10
SharedProject/Enums/NameLanguage.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace SharedProject.Enums;
|
||||
|
||||
public enum NameLanguage : uint
|
||||
{
|
||||
Japanese = 0,
|
||||
English = 1,
|
||||
Korean = 2,
|
||||
ChineseTraditional = 3,
|
||||
ChineseSimplified = 4,
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class DanData
|
||||
public class DanData : IVerupNo
|
||||
{
|
||||
[JsonPropertyName("danId")]
|
||||
public uint DanId { get; set; }
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class EventFolderData
|
||||
public class EventFolderData : IVerupNo
|
||||
{
|
||||
[JsonPropertyName("folderId")]
|
||||
public uint FolderId { get; set; }
|
||||
@ -14,7 +14,7 @@ public class EventFolderData
|
||||
public uint Priority { get; set; }
|
||||
|
||||
[JsonPropertyName("songNo")]
|
||||
public uint[]? SongNo { get; set; }
|
||||
public uint[]? SongNoes { get; set; }
|
||||
|
||||
[JsonPropertyName("parentFolderId")]
|
||||
public uint ParentFolderId { get; set; }
|
||||
|
8
SharedProject/Models/IVerupNo.cs
Normal file
8
SharedProject/Models/IVerupNo.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public interface IVerupNo
|
||||
{
|
||||
public uint VerupNo { get; set; }
|
||||
}
|
@ -6,5 +6,6 @@ public class ShopFolderData
|
||||
{
|
||||
[JsonPropertyName("songNo")] public uint SongNo { get; set; }
|
||||
|
||||
public uint Type { get; set; }
|
||||
[JsonPropertyName("price")] public uint Price { get; set; }
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace SharedProject.Models;
|
||||
|
||||
public class SongIntroductionData
|
||||
public class SongIntroductionData : IVerupNo
|
||||
{
|
||||
[JsonPropertyName("setId")]
|
||||
public uint SetId { get; set; }
|
||||
@ -14,5 +14,5 @@ public class SongIntroductionData
|
||||
public uint MainSongNo { get; set; }
|
||||
|
||||
[JsonPropertyName("subSongNo")]
|
||||
public uint[]? SubSongNo { get; set; }
|
||||
public uint[]? SubSongNoes { get; set; }
|
||||
}
|
@ -16,4 +16,13 @@ public static class Constants
|
||||
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 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 FUNCTION_ID_DANI_FOLDER_AVAILABLE = 1;
|
||||
public const uint FUNCTION_ID_DANI_AVAILABLE = 2;
|
||||
public const uint FUNCTION_ID_AI_BATTLE_AVAILABLE = 3;
|
||||
}
|
@ -33,7 +33,7 @@ public class UserSettingsController : BaseController<UserSettingsController>
|
||||
|
||||
var costumeUnlockData = JsonHelper.GetCostumeUnlockDataFromUserData(user, Logger);
|
||||
|
||||
var unlockedTitle = JsonHelper.GetUIntArrayFromJson(user.TitleFlgArray, 0, Logger, nameof(user.TitleFlgArray))
|
||||
var unlockedTitle = user.TitleFlgArray//JsonHelper.GetUIntArrayFromJson(user.TitleFlgArray, 0, Logger, nameof(user.TitleFlgArray))
|
||||
.ToList();
|
||||
|
||||
for (var i = 0; i < 5; i++)
|
||||
@ -125,8 +125,8 @@ public class UserSettingsController : BaseController<UserSettingsController>
|
||||
user.CostumeData = JsonSerializer.Serialize(costumes);
|
||||
|
||||
// If a locked tone is selected, unlock it
|
||||
uint[] toneFlg = { 0u };
|
||||
try
|
||||
uint[] toneFlg = user.ToneFlgArray;
|
||||
/*try
|
||||
{
|
||||
toneFlg = JsonSerializer.Deserialize<uint[]>(user.ToneFlgArray)!;
|
||||
}
|
||||
@ -134,10 +134,10 @@ public class UserSettingsController : BaseController<UserSettingsController>
|
||||
{
|
||||
Logger.LogError(e, "Parsing tone flg json data failed");
|
||||
}
|
||||
toneFlg.ThrowIfNull("Tone flg should never be null!");
|
||||
toneFlg.ThrowIfNull("Tone flg should never be null!");*/
|
||||
toneFlg = toneFlg.Append(0u).Append(userSetting.ToneId).Distinct().ToArray();
|
||||
|
||||
user.ToneFlgArray = JsonSerializer.Serialize(toneFlg);
|
||||
user.ToneFlgArray = toneFlg;
|
||||
|
||||
await userDatumService.UpdateUserDatum(user);
|
||||
|
||||
|
@ -1,8 +1,14 @@
|
||||
namespace TaikoLocalServer.Controllers;
|
||||
using MediatR;
|
||||
|
||||
namespace TaikoLocalServer.Controllers;
|
||||
|
||||
public abstract class BaseController<T> : ControllerBase where T : BaseController<T>
|
||||
{
|
||||
private ILogger<T>? logger;
|
||||
|
||||
private ISender? mediator;
|
||||
|
||||
protected ISender Mediator => (mediator ??= HttpContext.RequestServices.GetService<ISender>()) ?? throw new InvalidOperationException();
|
||||
|
||||
protected ILogger<T> Logger => (logger ??= HttpContext.RequestServices.GetService<ILogger<T>>()) ?? throw new InvalidOperationException();
|
||||
}
|
@ -1,49 +1,37 @@
|
||||
using System.Text.Json;
|
||||
using GameDatabase.Entities;
|
||||
using Throw;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using AddTokenCountRequestMapper = TaikoLocalServer.Mappers.AddTokenCountRequestMapper;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/addtokencount_7547j3o4.php")]
|
||||
[ApiController]
|
||||
public class AddTokenCountController : BaseController<AddTokenCountController>
|
||||
{
|
||||
private readonly IUserDatumService userDatumService;
|
||||
|
||||
public AddTokenCountController(IUserDatumService userDatumService)
|
||||
{
|
||||
this.userDatumService = userDatumService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/addtokencount_7547j3o4.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> AddTokenCount([FromBody] AddTokenCountRequest request)
|
||||
{
|
||||
Logger.LogInformation("AddTokenCount request : {Request}", request.Stringify());
|
||||
Logger.LogInformation("[3906] AddTokenCount request : {Request}", request.Stringify());
|
||||
|
||||
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
|
||||
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
|
||||
var command = new AddTokenCountCommand(AddTokenCountRequestMapper.Map(request));
|
||||
await Mediator.Send(command);
|
||||
|
||||
foreach (var addTokenCountData in request.AryAddTokenCountDatas)
|
||||
var response = new AddTokenCountResponse
|
||||
{
|
||||
var tokenId = addTokenCountData.TokenId;
|
||||
var addTokenCount = addTokenCountData.AddTokenCount;
|
||||
var token = user.Tokens.FirstOrDefault(t => t.Id == tokenId);
|
||||
if (token != null)
|
||||
{
|
||||
token.Count += addTokenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
user.Tokens.Add(new Token
|
||||
{
|
||||
Id = (int)tokenId,
|
||||
Count = addTokenCount
|
||||
});
|
||||
}
|
||||
}
|
||||
Result = 1
|
||||
};
|
||||
|
||||
await userDatumService.UpdateUserDatum(user);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/addtokencount.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> AddTokenCount3209([FromBody] Models.v3209.AddTokenCountRequest request)
|
||||
{
|
||||
Logger.LogInformation("[3209] AddTokenCount request : {Request}", request.Stringify());
|
||||
|
||||
var command = new AddTokenCountCommand(AddTokenCountRequestMapper.Map(request));
|
||||
await Mediator.Send(command);
|
||||
|
||||
var response = new AddTokenCountResponse
|
||||
{
|
||||
|
@ -1,200 +1,68 @@
|
||||
using GameDatabase.Entities;
|
||||
using System.Text.Json;
|
||||
using Throw;
|
||||
using TaikoLocalServer.Handlers;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[ApiController]
|
||||
[Route("/v12r08_ww/chassis/baidcheck_dcfxit1u.php")]
|
||||
public class BaidController : BaseController<BaidController>
|
||||
{
|
||||
private readonly IUserDatumService userDatumService;
|
||||
|
||||
private readonly ICardService cardService;
|
||||
|
||||
private readonly ISongBestDatumService songBestDatumService;
|
||||
|
||||
private readonly IDanScoreDatumService danScoreDatumService;
|
||||
|
||||
private readonly IAiDatumService aiDatumService;
|
||||
|
||||
private readonly IGameDataService gameDataService;
|
||||
|
||||
public BaidController(IUserDatumService userDatumService, ICardService cardService,
|
||||
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService,
|
||||
IGameDataService gameDataService)
|
||||
{
|
||||
this.userDatumService = userDatumService;
|
||||
this.cardService = cardService;
|
||||
this.songBestDatumService = songBestDatumService;
|
||||
this.danScoreDatumService = danScoreDatumService;
|
||||
this.aiDatumService = aiDatumService;
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/baidcheck_dcfxit1u.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetBaid([FromBody] BAIDRequest request)
|
||||
{
|
||||
Logger.LogInformation("Baid request: {Request}", request.Stringify());
|
||||
var commonResponse = await Mediator.Send(new BaidQuery(request.AccessCode));
|
||||
BAIDResponse response;
|
||||
var card = await cardService.GetCardByAccessCode(request.AccessCode);
|
||||
if (card is null)
|
||||
if (commonResponse.IsNewUser)
|
||||
{
|
||||
Logger.LogInformation("New user with access code {AccessCode}", request.AccessCode);
|
||||
var newId = cardService.GetNextBaid();
|
||||
|
||||
response = new BAIDResponse
|
||||
{
|
||||
Result = 1,
|
||||
PlayerType = 1,
|
||||
Baid = newId,
|
||||
Baid = commonResponse.Baid,
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
var baid = card.Baid;
|
||||
|
||||
var userData = await userDatumService.GetFirstUserDatumOrDefault(baid);
|
||||
|
||||
var songBestData = await songBestDatumService.GetAllSongBestData(baid);
|
||||
|
||||
var achievementDisplayDifficulty = userData.AchievementDisplayDifficulty;
|
||||
if (userData.AchievementDisplayDifficulty == Difficulty.None)
|
||||
{
|
||||
achievementDisplayDifficulty = songBestData.Any(datum => datum.BestCrown >= CrownType.Clear) ?
|
||||
songBestData.Where(datum => datum.BestCrown >= CrownType.Clear).Max(datum => datum.Difficulty) :
|
||||
Difficulty.Easy;
|
||||
}
|
||||
|
||||
var songCountData = songBestData.Where(datum => achievementDisplayDifficulty != Difficulty.UraOni ?
|
||||
datum.Difficulty == achievementDisplayDifficulty :
|
||||
datum.Difficulty is Difficulty.Oni or Difficulty.UraOni).ToList();
|
||||
|
||||
var crownCount = CalculateCrownCount(songCountData);
|
||||
|
||||
var scoreRankCount = CalculateScoreRankCount(songCountData);
|
||||
|
||||
|
||||
var costumeData = JsonHelper.GetCostumeDataFromUserData(userData, Logger);
|
||||
|
||||
var costumeArrays = JsonHelper.GetCostumeUnlockDataFromUserData(userData, Logger);
|
||||
|
||||
var costumeFlagArrays = gameDataService.GetCostumeFlagArraySizes()
|
||||
.Select((size, index) => FlagCalculator.GetBitArrayFromIds(costumeArrays[index], size, Logger))
|
||||
.ToList();
|
||||
|
||||
var danData = await danScoreDatumService.GetDanScoreDataList(baid, DanType.Normal);
|
||||
|
||||
var maxDan = danData.Where(datum => datum.ClearState != DanClearState.NotClear)
|
||||
.Select(datum => datum.DanId)
|
||||
.DefaultIfEmpty()
|
||||
.Max();
|
||||
|
||||
var danDataDictionary = gameDataService.GetDanDataDictionary();
|
||||
var danIdList = danDataDictionary.Keys.ToList();
|
||||
var gotDanFlagArray = FlagCalculator.ComputeGotDanFlags(danData, danIdList);
|
||||
|
||||
var gaidenData = await danScoreDatumService.GetDanScoreDataList(baid, DanType.Gaiden);
|
||||
|
||||
var gaidenDataDictionary = gameDataService.GetGaidenDataDictionary();
|
||||
var gaidenIdList = gaidenDataDictionary.Keys.ToList();
|
||||
var gotGaidenFlagArray = FlagCalculator.ComputeGotDanFlags(gaidenData, gaidenIdList);
|
||||
|
||||
var genericInfoFlg = Array.Empty<uint>();
|
||||
try
|
||||
{
|
||||
genericInfoFlg = JsonSerializer.Deserialize<uint[]>(userData.GenericInfoFlgArray);
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
Logger.LogError(e, "Parsing genericinfo flg json data failed");
|
||||
}
|
||||
|
||||
// The only way to get a null is provide string "null" as input,
|
||||
// which means database content need to be fixed, so better throw
|
||||
genericInfoFlg.ThrowIfNull("Genericinfo flg should never be null!");
|
||||
|
||||
var genericInfoFlgLength = genericInfoFlg.Any() ? genericInfoFlg.Max() + 1 : 0;
|
||||
var genericInfoFlgArray = FlagCalculator.GetBitArrayFromIds(genericInfoFlg, (int)genericInfoFlgLength, Logger);
|
||||
|
||||
var aiRank = (uint)(userData.AiWinCount / 10);
|
||||
if (aiRank > 11)
|
||||
{
|
||||
aiRank = 11;
|
||||
}
|
||||
response = new BAIDResponse
|
||||
{
|
||||
Result = 1,
|
||||
PlayerType = 0,
|
||||
Baid = baid,
|
||||
MydonName = userData.MyDonName,
|
||||
MydonNameLanguage = userData.MyDonNameLanguage,
|
||||
Title = userData.Title,
|
||||
TitleplateId = userData.TitlePlateId,
|
||||
ColorFace = userData.ColorFace,
|
||||
ColorBody = userData.ColorBody,
|
||||
ColorLimb = userData.ColorLimb,
|
||||
AryCostumedata = new BAIDResponse.CostumeData
|
||||
{
|
||||
Costume1 = costumeData[0],
|
||||
Costume2 = costumeData[1],
|
||||
Costume3 = costumeData[2],
|
||||
Costume4 = costumeData[3],
|
||||
Costume5 = costumeData[4]
|
||||
},
|
||||
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,
|
||||
GotDanFlg = gotDanFlagArray,
|
||||
GotDanextraFlg = gotGaidenFlagArray,
|
||||
DefaultToneSetting = userData.SelectedToneId,
|
||||
GenericInfoFlg = genericInfoFlgArray,
|
||||
AryCrownCounts = crownCount,
|
||||
AryScoreRankCounts = scoreRankCount,
|
||||
IsDispAchievementOn = userData.DisplayAchievement,
|
||||
DispAchievementType = (uint)achievementDisplayDifficulty,
|
||||
IsDispAchievementTypeSet = true,
|
||||
LastPlayMode = userData.LastPlayMode,
|
||||
IsDispSouuchiOn = true
|
||||
};
|
||||
|
||||
response = Mappers.BaidResponseMapper.Map3906WithPostProcess(commonResponse);
|
||||
response.Result = 1;
|
||||
response.PlayerType = 0;
|
||||
response.IsDispAchievementTypeSet = true;
|
||||
response.IsDispSouuchiOn = true;
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
private static uint[] CalculateScoreRankCount(IReadOnlyCollection<SongBestDatum> songCountData)
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/baidcheck.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetBaid3209([FromBody] Models.v3209.BAIDRequest request)
|
||||
{
|
||||
var scoreRankCount = new uint[7];
|
||||
foreach (var scoreRankType in Enum.GetValues<ScoreRank>())
|
||||
Logger.LogInformation("Baid request: {Request}", request.Stringify());
|
||||
|
||||
var commonResponse = await Mediator.Send(new BaidQuery(request.WechatQrStr));
|
||||
Models.v3209.BAIDResponse response;
|
||||
if (commonResponse.IsNewUser)
|
||||
{
|
||||
if (scoreRankType != ScoreRank.None)
|
||||
Logger.LogInformation("New user with access code {AccessCode}", request.WechatQrStr);
|
||||
|
||||
response = new Models.v3209.BAIDResponse
|
||||
{
|
||||
scoreRankCount[(int)scoreRankType - 2] =
|
||||
(uint)songCountData.Count(datum => datum.BestScoreRank == scoreRankType);
|
||||
}
|
||||
Result = 1,
|
||||
PlayerType = 1,
|
||||
Baid = commonResponse.Baid,
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
return scoreRankCount;
|
||||
}
|
||||
|
||||
private static uint[] CalculateCrownCount(IReadOnlyCollection<SongBestDatum> songCountData)
|
||||
{
|
||||
var crownCount = new uint[3];
|
||||
foreach (var crownType in Enum.GetValues<CrownType>())
|
||||
{
|
||||
if (crownType != CrownType.None)
|
||||
{
|
||||
crownCount[(int)crownType - 1] = (uint)songCountData.Count(datum => datum.BestCrown == crownType);
|
||||
}
|
||||
}
|
||||
|
||||
return crownCount;
|
||||
response = Mappers.BaidResponseMapper.Map3209WithPostProcess(commonResponse);
|
||||
response.Result = 1;
|
||||
response.PlayerType = 0;
|
||||
response.IsDispAchievementTypeSet = true;
|
||||
response.IsDispSouuchiOn = true;
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,14 +1,13 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[ApiController]
|
||||
[Route("/v12r08_ww/chassis/bookkeeping_s4esi5un.php")]
|
||||
public class BookkeepingController : BaseController<BookkeepingController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/bookkeeping_s4esi5un.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult StartupAuth([FromBody] BookKeepingRequest request)
|
||||
{
|
||||
Logger.LogInformation("Bookkeeping request: {Request}", request.Stringify());
|
||||
Logger.LogInformation("[3906] Bookkeeping request: {Request}", request.Stringify());
|
||||
var response = new BookKeepingResponse
|
||||
{
|
||||
Result = 1
|
||||
@ -18,4 +17,15 @@ public class BookkeepingController : BaseController<BookkeepingController>
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/bookkeeping.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult StartupAuth3209([FromBody] Models.v3209.BookKeepingRequest request)
|
||||
{
|
||||
Logger.LogInformation("[3209] Bookkeeping request: {Request}", request.Stringify());
|
||||
var response = new BookKeepingResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/challengecompe.php")]
|
||||
[ApiController]
|
||||
public class ChallengeCompetitionController : BaseController<ChallengeCompetitionController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/challengecompe.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult HandleChallenge([FromBody] ChallengeCompeRequest request)
|
||||
{
|
||||
@ -16,6 +15,19 @@ public class ChallengeCompetitionController : BaseController<ChallengeCompetitio
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/challengecompe.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult HandleChallenge3209([FromBody] Models.v3209.ChallengeCompeRequest request)
|
||||
{
|
||||
Logger.LogInformation("ChallengeCompe request : {Request}", request.Stringify());
|
||||
|
||||
var response = new Models.v3209.ChallengeCompeResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@ using TaikoLocalServer.Settings;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/crownsdata_oqgqy90s.php")]
|
||||
[ApiController]
|
||||
public class CrownsDataController : BaseController<CrownsDataController>
|
||||
{
|
||||
@ -17,16 +16,50 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
||||
this.settings = settings.Value;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/crownsdata_oqgqy90s.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> CrownsData([FromBody] CrownsDataRequest request)
|
||||
{
|
||||
Logger.LogInformation("CrownsData request : {Request}", request.Stringify());
|
||||
|
||||
var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid);
|
||||
var crownData = await Handle(request.Baid);
|
||||
|
||||
var response = new CrownsDataResponse
|
||||
{
|
||||
Result = 1,
|
||||
CrownFlg = crownData.CrownFlg,
|
||||
DondafulCrownFlg = crownData.DondafulCrownFlg
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/crownsdata.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> CrownsData3209([FromBody] Models.v3209.CrownsDataRequest request)
|
||||
{
|
||||
Logger.LogInformation("CrownsData request : {Request}", request.Stringify());
|
||||
|
||||
var crownData = await Handle((uint)request.Baid);
|
||||
|
||||
var response = new Models.v3209.CrownsDataResponse
|
||||
{
|
||||
Result = 1,
|
||||
CrownFlg = crownData.CrownFlg,
|
||||
DondafulCrownFlg = crownData.DondafulCrownFlg
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
public record CrownData(byte[] CrownFlg, byte[] DondafulCrownFlg);
|
||||
|
||||
public async Task<CrownData> Handle(uint baid)
|
||||
{
|
||||
var songBestData = await songBestDatumService.GetAllSongBestData(baid);
|
||||
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||
var crown = new ushort[songIdMax + 1];
|
||||
var crown = new ushort[songIdMax + 1];
|
||||
var dondafulCrown = new byte[songIdMax + 1];
|
||||
|
||||
for (var songId = 0; songId < songIdMax; songId++)
|
||||
@ -34,7 +67,7 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
||||
var id = songId;
|
||||
dondafulCrown[songId] = songBestData
|
||||
// Select song of this song id with dondaful crown
|
||||
.Where(datum => datum.SongId == id &&
|
||||
.Where(datum => datum.SongId == id &&
|
||||
datum.BestCrown == CrownType.Dondaful)
|
||||
// Calculate flag according to difficulty
|
||||
.Aggregate((byte)0, (flag, datum) => FlagCalculator.ComputeDondafulCrownFlag(flag, datum.Difficulty));
|
||||
@ -46,14 +79,7 @@ public class CrownsDataController : BaseController<CrownsDataController>
|
||||
// Calculate flag according to difficulty
|
||||
.Aggregate((ushort)0, (flag, datum) => FlagCalculator.ComputeCrownFlag(flag, datum.BestCrown, datum.Difficulty));
|
||||
}
|
||||
|
||||
var response = new CrownsDataResponse
|
||||
{
|
||||
Result = 1,
|
||||
CrownFlg = GZipBytesUtil.GetGZipBytes(crown),
|
||||
DondafulCrownFlg = GZipBytesUtil.GetGZipBytes(dondafulCrown)
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
|
||||
return new CrownData(GZipBytesUtil.GetGZipBytes(crown), GZipBytesUtil.GetGZipBytes(dondafulCrown));
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/executeqrcode_rgowsr5m.php")]
|
||||
[ApiController]
|
||||
public class ExecuteQrCodeController : BaseController<ExecuteQrCodeController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/executeqrcode_rgowsr5m.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult ExecuteQrCode([FromBody] ExecuteQrcodeRequest request)
|
||||
{
|
||||
@ -18,4 +17,19 @@ public class ExecuteQrCodeController : BaseController<ExecuteQrCodeController>
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/executeqrcode.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult ExecuteQrCode3209([FromBody] Models.v3209.ExecuteQrcodeRequest request)
|
||||
{
|
||||
Logger.LogInformation("ExecuteQrcode request : {Request}", request.Stringify());
|
||||
|
||||
var response = new Models.v3209.ExecuteQrcodeResponse
|
||||
{
|
||||
QrcodeId = 1,
|
||||
Result = 1
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
using Throw;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getaidata_6x30b9nr.php")]
|
||||
[ApiController]
|
||||
public class GetAiDataController : BaseController<GetAiDataController>
|
||||
{
|
||||
@ -13,22 +13,27 @@ public class GetAiDataController : BaseController<GetAiDataController>
|
||||
this.userDatumService = userDatumService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getaidata_6x30b9nr.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetAiData([FromBody] GetAiDataRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetAiData request : {Request}", request.Stringify());
|
||||
|
||||
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
|
||||
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
|
||||
var response = new GetAiDataResponse
|
||||
{
|
||||
Result = 1,
|
||||
TotalWinnings = (uint)user.AiWinCount,
|
||||
InputMedian = "1000",
|
||||
InputVariance = "2000"
|
||||
};
|
||||
var commonResponse = await Mediator.Send(new GetAiDataQuery(request.Baid));
|
||||
var response = Mappers.AiDataResponseMapper.MapTo3906(commonResponse);
|
||||
response.Result = 1;
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getaidata.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetAiData3209([FromBody] Models.v3209.GetAiDataRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetAiData request : {Request}", request.Stringify());
|
||||
|
||||
var commonResponse = await Mediator.Send(new GetAiDataQuery((uint)request.Baid));
|
||||
var response = Mappers.AiDataResponseMapper.MapTo3209(commonResponse);
|
||||
response.Result = 1;
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,8 +1,9 @@
|
||||
using Throw;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getaiscore_lp38po4w.php")]
|
||||
[ApiController]
|
||||
public class GetAiScoreController : BaseController<GetAiScoreController>
|
||||
{
|
||||
@ -13,93 +14,29 @@ public class GetAiScoreController : BaseController<GetAiScoreController>
|
||||
this.aiDatumService = aiDatumService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getaiscore_lp38po4w.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetAiScore([FromBody] GetAiScoreRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetAiScore request : {Request}", request.Stringify());
|
||||
|
||||
var response = new GetAiScoreResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
var commonResponse = await Mediator.Send(new GetAiScoreQuery(request.Baid, request.SongNo, request.Level));
|
||||
var response = AiScoreMappers.MapTo3906(commonResponse);
|
||||
response.Result = 1;
|
||||
|
||||
var difficulty = (Difficulty)request.Level;
|
||||
difficulty.Throw().IfOutOfRange();
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
var aiData = await aiDatumService.GetSongAiScore(request.Baid, request.SongNo, difficulty);
|
||||
if (aiData is null)
|
||||
{
|
||||
return Ok(response);
|
||||
}
|
||||
[HttpPost("v12r00_cn/chassis/getaiscore.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetAiScore3209([FromBody] Models.v3209.GetAiScoreRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetAiScore request : {Request}", request.Stringify());
|
||||
|
||||
for (var index = 0; index < aiData.AiSectionScoreData.Count; index++)
|
||||
{
|
||||
var sectionScoreDatum = aiData.AiSectionScoreData[index];
|
||||
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData
|
||||
{
|
||||
Crown = (uint)sectionScoreDatum.Crown,
|
||||
GoodCnt = sectionScoreDatum.GoodCount,
|
||||
OkCnt = sectionScoreDatum.OkCount,
|
||||
NgCnt = sectionScoreDatum.MissCount,
|
||||
PoundCnt = sectionScoreDatum.DrumrollCount,
|
||||
Score = sectionScoreDatum.Score,
|
||||
SectionNo = (uint)index
|
||||
});
|
||||
}
|
||||
|
||||
// There's either 3 or 5 total sections
|
||||
// SectionNo doesn't seem to actually affect which section is being assigned to, only the List order matters
|
||||
/*response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
||||
{
|
||||
SectionNo = 1,
|
||||
Crown = (uint)CrownType.Clear,
|
||||
Score = 100000,
|
||||
GoodCnt = 100,
|
||||
OkCnt = 50,
|
||||
NgCnt = 25,
|
||||
PoundCnt = 12
|
||||
});
|
||||
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
||||
{
|
||||
SectionNo = 2,
|
||||
Crown = (uint)CrownType.Gold,
|
||||
Score = 100001,
|
||||
GoodCnt = 101,
|
||||
OkCnt = 50,
|
||||
NgCnt = 25,
|
||||
PoundCnt = 12
|
||||
});
|
||||
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
||||
{
|
||||
SectionNo = 3,
|
||||
Crown = (uint)CrownType.Dondaful,
|
||||
Score = 100002,
|
||||
GoodCnt = 102,
|
||||
OkCnt = 50,
|
||||
NgCnt = 25,
|
||||
PoundCnt = 12
|
||||
});
|
||||
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
||||
{
|
||||
SectionNo = 4,
|
||||
Crown = (uint)CrownType.Gold,
|
||||
Score = 100003,
|
||||
GoodCnt = 103,
|
||||
OkCnt = 50,
|
||||
NgCnt = 25,
|
||||
PoundCnt = 12
|
||||
});
|
||||
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
||||
{
|
||||
SectionNo = 5,
|
||||
Crown = (uint)CrownType.Clear,
|
||||
Score = 100004,
|
||||
GoodCnt = 104,
|
||||
OkCnt = 50,
|
||||
NgCnt = 25,
|
||||
PoundCnt = 12
|
||||
});*/
|
||||
var commonResponse =
|
||||
await Mediator.Send(new GetAiScoreQuery((uint)request.Baid, request.SongNo, request.Level));
|
||||
var response = AiScoreMappers.MapTo3209(commonResponse);
|
||||
response.Result = 1;
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getapplicationurl.php")]
|
||||
[ApiController]
|
||||
public class GetApplicationUrlController : BaseController<GetApplicationUrlController>
|
||||
{
|
||||
private const string APPLICATION_URL = "vsapi.taiko-p.jp";
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getapplicationurl.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetApplicationUrl([FromBody] GetApplicationUrlRequest request)
|
||||
{
|
||||
@ -15,9 +13,25 @@ public class GetApplicationUrlController : BaseController<GetApplicationUrlContr
|
||||
var response = new GetApplicationUrlResponse
|
||||
{
|
||||
Result = 1,
|
||||
ApplicationUrl = APPLICATION_URL
|
||||
ApplicationUrl = $"{HttpContext.Request.Host.Value}/app"
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getapplicationurl.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetApplicationUrl3209([FromBody] Models.v3209.GetApplicationUrlRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetApplicationUrl request : {Request}", request.Stringify());
|
||||
|
||||
var response = new Models.v3209.GetApplicationUrlResponse
|
||||
{
|
||||
Result = 1,
|
||||
ApplicationUrl = $"{HttpContext.Request.Host.Value}/app"
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
}
|
@ -1,19 +1,14 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getdanodai_ela9zu1a.php")]
|
||||
[ApiController]
|
||||
public class GetDanOdaiController : BaseController<GetDanOdaiController>
|
||||
{
|
||||
private readonly IGameDataService gameDataService;
|
||||
|
||||
public GetDanOdaiController(IGameDataService gameDataService)
|
||||
{
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getdanodai_ela9zu1a.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetDanOdai([FromBody] GetDanOdaiRequest request)
|
||||
public async Task<IActionResult> GetDanOdai([FromBody] GetDanOdaiRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetDanOdai request : {Request}", request.Stringify());
|
||||
|
||||
@ -22,34 +17,25 @@ public class GetDanOdaiController : BaseController<GetDanOdaiController>
|
||||
Result = 1
|
||||
};
|
||||
|
||||
if (request.Type == 1)
|
||||
{
|
||||
foreach (var danId in request.DanIds)
|
||||
{
|
||||
gameDataService.GetDanDataDictionary().TryGetValue(danId, out var odaiData);
|
||||
if (odaiData is null)
|
||||
{
|
||||
Logger.LogWarning("Requested dan id {Id} does not exist!", danId);
|
||||
continue;
|
||||
}
|
||||
var odaiDataList = await Mediator.Send(new GetDanOdaiQuery(request.DanIds, request.Type));
|
||||
response.AryOdaiDatas.AddRange(odaiDataList.Select(DanDataMappers.To3906OdaiData));
|
||||
|
||||
response.AryOdaiDatas.Add(odaiData);
|
||||
}
|
||||
}
|
||||
else if (request.Type == 2)
|
||||
{
|
||||
foreach (var danId in request.DanIds)
|
||||
{
|
||||
gameDataService.GetGaidenDataDictionary().TryGetValue(danId, out var odaiData);
|
||||
if (odaiData is null)
|
||||
{
|
||||
Logger.LogWarning("Requested dan id {Id} does not exist!", danId);
|
||||
continue;
|
||||
}
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getdanodai.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetDanOdai3209([FromBody] Models.v3209.GetDanOdaiRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetDanOdai request : {Request}", request.Stringify());
|
||||
|
||||
response.AryOdaiDatas.Add(odaiData);
|
||||
}
|
||||
}
|
||||
var response = new Models.v3209.GetDanOdaiResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
|
||||
var odaiDataList = await Mediator.Send(new GetDanOdaiQuery(request.DanIds, request.Type));
|
||||
response.AryOdaiDatas.AddRange(odaiDataList.Select(DanDataMappers.To3209OdaiData));
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
@ -1,52 +1,33 @@
|
||||
using GameDatabase.Entities;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getdanscore_frqhg7q6.php")]
|
||||
[ApiController]
|
||||
public class GetDanScoreController : BaseController<GetDanScoreController>
|
||||
{
|
||||
private readonly IDanScoreDatumService danScoreDatumService;
|
||||
|
||||
public GetDanScoreController(IDanScoreDatumService danScoreDatumService)
|
||||
{
|
||||
this.danScoreDatumService = danScoreDatumService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getdanscore_frqhg7q6.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetDanScore([FromBody] GetDanScoreRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetDanScore request : {Request}", request.Stringify());
|
||||
|
||||
var response = new GetDanScoreResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
var commonResponse = await Mediator.Send(new GetDanScoreQuery(request.Baid, request.Type, request.DanIds));
|
||||
var response = DanScoreMappers.MapTo3906(commonResponse);
|
||||
|
||||
var danType = (DanType)request.Type;
|
||||
danType.Throw().IfOutOfRange();
|
||||
var danScoreData = await danScoreDatumService.GetDanScoreDataList(request.Baid, danType);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getdanscore.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetDanScore3209([FromBody] Models.v3209.GetDanScoreRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetDanScore3209 request : {Request}", request.Stringify());
|
||||
|
||||
foreach (var danId in request.DanIds)
|
||||
{
|
||||
var datum = danScoreData.FirstOrDefault(scoreDatum => scoreDatum.DanId == danId, new DanScoreDatum());
|
||||
|
||||
var responseData = new GetDanScoreResponse.DanScoreData
|
||||
{
|
||||
DanId = danId,
|
||||
ArrivalSongCnt = datum.ArrivalSongCount,
|
||||
ComboCntTotal = datum.ComboCountTotal,
|
||||
SoulGaugeTotal = datum.SoulGaugeTotal
|
||||
};
|
||||
foreach (var stageScoreDatum in datum.DanStageScoreData)
|
||||
{
|
||||
responseData.AryDanScoreDataStages.Add(ObjectMappers.DanStageDbToResponseMap.Apply(stageScoreDatum));
|
||||
}
|
||||
|
||||
response.AryDanScoreDatas.Add(responseData);
|
||||
}
|
||||
var commonResponse = await Mediator.Send(new GetDanScoreQuery((uint)request.Baid, request.Type, request.DanIds));
|
||||
var response = DanScoreMappers.MapTo3209(commonResponse);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
@ -1,38 +1,28 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getfolder_rffj346i.php")]
|
||||
[ApiController]
|
||||
public class GetFolderController : BaseController<GetFolderController>
|
||||
{
|
||||
private readonly IGameDataService gameDataService;
|
||||
public GetFolderController(IGameDataService gameDataService)
|
||||
{
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getfolder_rffj346i.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetFolder([FromBody] GetfolderRequest request)
|
||||
public async Task<IActionResult> GetFolder([FromBody] GetfolderRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetFolder request : {Request}", request.Stringify());
|
||||
|
||||
var response = new GetfolderResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
|
||||
foreach (var folderId in request.FolderIds)
|
||||
{
|
||||
gameDataService.GetFolderDictionary().TryGetValue(folderId, out var folderData);
|
||||
if (folderData is null)
|
||||
{
|
||||
Logger.LogWarning("Requested folder id {Id} does not exist!", folderId);
|
||||
continue;
|
||||
}
|
||||
|
||||
response.AryEventfolderDatas.Add(folderData);
|
||||
}
|
||||
|
||||
var commonResponse = await Mediator.Send(new GetFolderQuery(request.FolderIds));
|
||||
var response = FolderDataMappers.MapTo3906(commonResponse);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getfolder.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetFolder([FromBody] Models.v3209.GetfolderRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetFolder3209 request : {Request}", request.Stringify());
|
||||
var commonResponse = await Mediator.Send(new GetFolderQuery(request.FolderIds));
|
||||
var response = FolderDataMappers.MapTo3209(commonResponse);
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[ApiController]
|
||||
[Route("/v12r08_ww/chassis/getgenericmaster_ts8om3qd.php")]
|
||||
public class GetGenericMasterController : BaseController<GetGenericMasterController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getgenericmaster_ts8om3qd.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetGenericMaster([FromBody] GetGenericMasterRequest request)
|
||||
{
|
||||
@ -17,6 +16,21 @@ public class GetGenericMasterController : BaseController<GetGenericMasterControl
|
||||
EnableIdBit = FlagCalculator.GetBitArrayTrue(5000)
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getgenericmaster.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetGenericMaster([FromBody] Models.v3209.GetGenericMasterRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetGenericMaster3209Request: {Request}", request.Stringify());
|
||||
|
||||
var response = new Models.v3209.GetGenericMasterResponse
|
||||
{
|
||||
Result = 1,
|
||||
VerupNo = 2,
|
||||
EnableIdBit = FlagCalculator.GetBitArrayTrue(5000)
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
@ -3,36 +3,63 @@ using TaikoLocalServer.Settings;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getscorerank_1c8l7y61.php")]
|
||||
[ApiController]
|
||||
public class GetScoreRankController : BaseController<GetScoreRankController>
|
||||
public class GetScoreRankController(ISongBestDatumService songBestDatumService, IOptions<ServerSettings> settings)
|
||||
: BaseController<GetScoreRankController>
|
||||
{
|
||||
private readonly ISongBestDatumService songBestDatumService;
|
||||
private readonly ServerSettings settings = settings.Value;
|
||||
|
||||
private readonly ServerSettings settings;
|
||||
|
||||
public GetScoreRankController(ISongBestDatumService songBestDatumService, IOptions<ServerSettings> settings)
|
||||
{
|
||||
this.songBestDatumService = songBestDatumService;
|
||||
this.settings = settings.Value;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getscorerank_1c8l7y61.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetScoreRank([FromBody] GetScoreRankRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetScoreRank request : {Request}", request.Stringify());
|
||||
|
||||
var scoreRankData = await Handle(request.Baid);
|
||||
var response = new GetScoreRankResponse
|
||||
{
|
||||
Result = 1,
|
||||
IkiScoreRankFlg = scoreRankData.IkiScoreRankFlg,
|
||||
KiwamiScoreRankFlg = scoreRankData.KiwamiScoreRankFlg,
|
||||
MiyabiScoreRankFlg = scoreRankData.MiyabiScoreRankFlg
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getscorerank.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetScoreRank3209([FromBody] Models.v3209.GetScoreRankRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetScoreRank request : {Request}", request.Stringify());
|
||||
|
||||
var scoreRankData = await Handle((uint)request.Baid);
|
||||
var response = new Models.v3209.GetScoreRankResponse
|
||||
{
|
||||
Result = 1,
|
||||
IkiScoreRankFlg = scoreRankData.IkiScoreRankFlg,
|
||||
KiwamiScoreRankFlg = scoreRankData.KiwamiScoreRankFlg,
|
||||
MiyabiScoreRankFlg = scoreRankData.MiyabiScoreRankFlg
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
public record ScoreRankData(byte[] IkiScoreRankFlg, byte[] KiwamiScoreRankFlg, byte[] MiyabiScoreRankFlg);
|
||||
|
||||
private async Task<ScoreRankData> Handle(uint baid)
|
||||
{
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||
var kiwamiScores = new byte[songIdMax + 1];
|
||||
var kiwamiScores = new byte[songIdMax + 1];
|
||||
var miyabiScores = new ushort[songIdMax + 1];
|
||||
var ikiScores = new ushort[songIdMax + 1];
|
||||
var songBestData = await songBestDatumService.GetAllSongBestData(request.Baid);
|
||||
var ikiScores = new ushort[songIdMax + 1];
|
||||
var songBestData = await songBestDatumService.GetAllSongBestData(baid);
|
||||
|
||||
for (var songId = 0; songId < songIdMax; songId++)
|
||||
{
|
||||
var id = songId;
|
||||
kiwamiScores[songId] = songBestData
|
||||
.Where(datum => datum.SongId == id &&
|
||||
.Where(datum => datum.SongId == id &&
|
||||
datum.BestScoreRank == ScoreRank.Dondaful)
|
||||
.Aggregate((byte)0, (flag, datum) => FlagCalculator.ComputeKiwamiScoreRankFlag(flag, datum.Difficulty));
|
||||
|
||||
@ -46,14 +73,11 @@ public class GetScoreRankController : BaseController<GetScoreRankController>
|
||||
datum.BestScoreRank is ScoreRank.Gold or ScoreRank.Purple or ScoreRank.Sakura)
|
||||
.Aggregate((ushort)0, (flag, datum) => FlagCalculator.ComputeMiyabiOrIkiScoreRank(flag, datum.BestScoreRank, datum.Difficulty));
|
||||
}
|
||||
var response = new GetScoreRankResponse
|
||||
{
|
||||
Result = 1,
|
||||
IkiScoreRankFlg = GZipBytesUtil.GetGZipBytes(ikiScores),
|
||||
KiwamiScoreRankFlg = GZipBytesUtil.GetGZipBytes(kiwamiScores),
|
||||
MiyabiScoreRankFlg = GZipBytesUtil.GetGZipBytes(miyabiScores)
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
return new ScoreRankData(
|
||||
GZipBytesUtil.GetGZipBytes(ikiScores),
|
||||
GZipBytesUtil.GetGZipBytes(kiwamiScores),
|
||||
GZipBytesUtil.GetGZipBytes(miyabiScores)
|
||||
);
|
||||
}
|
||||
}
|
@ -1,34 +1,31 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getshopfolder_w4xik0uw.php")]
|
||||
[ApiController]
|
||||
public class GetShopFolderController : BaseController<GetShopFolderController>
|
||||
{
|
||||
private readonly IGameDataService gameDataService;
|
||||
|
||||
public GetShopFolderController(IGameDataService gameDataService)
|
||||
{
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getshopfolder_w4xik0uw.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetShopFolder([FromBody] GetShopFolderRequest request)
|
||||
public async Task<IActionResult> GetShopFolder([FromBody] GetShopFolderRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetShopFolder request : {Request}", request.Stringify());
|
||||
|
||||
gameDataService.GetTokenDataDictionary().TryGetValue("shopTokenId", out var shopTokenId);
|
||||
var commonResponse = await Mediator.Send(new GetShopFolderQuery());
|
||||
var response = ShopFolderDataMappers.MapTo3906(commonResponse);
|
||||
|
||||
var shopFolderList = gameDataService.GetShopFolderList();
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getshopfolder.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetShopFolder3209([FromBody] Models.v3209.GetShopFolderRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetShopFolder request : {Request}", request.Stringify());
|
||||
|
||||
var response = new GetShopFolderResponse
|
||||
{
|
||||
Result = 1,
|
||||
TokenId = shopTokenId > 0 ? (uint)shopTokenId : 1,
|
||||
VerupNo = 2
|
||||
};
|
||||
|
||||
response.AryShopFolderDatas.AddRange(shopFolderList);
|
||||
var commonResponse = await Mediator.Send(new GetShopFolderQuery());
|
||||
var response = ShopFolderDataMappers.MapTo3209(commonResponse);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/getsongintroduction_66blw6is.php")]
|
||||
[ApiController]
|
||||
public class GetSongIntroductionController : BaseController<GetSongIntroductionController>
|
||||
{
|
||||
@ -11,29 +13,27 @@ public class GetSongIntroductionController : BaseController<GetSongIntroductionC
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/getsongintroduction_66blw6is.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetSongIntroduction([FromBody] GetSongIntroductionRequest request)
|
||||
public async Task<IActionResult> GetSongIntroduction([FromBody] GetSongIntroductionRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetSongIntroduction request : {Request}", request.Stringify());
|
||||
|
||||
var response = new GetSongIntroductionResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
|
||||
foreach (var setId in request.SetIds)
|
||||
{
|
||||
gameDataService.GetSongIntroDictionary().TryGetValue(setId, out var introData);
|
||||
if (introData is null)
|
||||
{
|
||||
Logger.LogWarning("Requested set id {Id} does not exist!", setId);
|
||||
continue;
|
||||
}
|
||||
|
||||
response.ArySongIntroductionDatas.Add(introData);
|
||||
}
|
||||
var commonResponse = await Mediator.Send(new GetSongIntroductionQuery(request.SetIds));
|
||||
var response = SongIntroductionDataMappers.MapTo3906(commonResponse);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/getsongintroduction.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetSongIntroduction3209([FromBody] Models.v3209.GetSongIntroductionRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetSongIntroduction request : {Request}", request.Stringify());
|
||||
|
||||
var commonResponse = await Mediator.Send(new GetSongIntroductionQuery(request.SetIds));
|
||||
var response = SongIntroductionDataMappers.MapTo3209(commonResponse);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/gettelop_o0cb2z3e.php")]
|
||||
[ApiController]
|
||||
public class GetTelopController : BaseController<GetTelopController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/gettelop_o0cb2z3e.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetTelop([FromBody] GettelopRequest request)
|
||||
{
|
||||
@ -18,7 +17,28 @@ public class GetTelopController : BaseController<GetTelopController>
|
||||
Result = 1,
|
||||
StartDatetime = startDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
EndDatetime = endDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
Telop = "Hello world",
|
||||
Telop = "Hello 3906",
|
||||
VerupNo = 1
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/gettelop.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetTelop3209([FromBody] Models.v3209.GettelopRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetTelop request : {Request}", request.Stringify());
|
||||
|
||||
var startDateTime = DateTime.Now - TimeSpan.FromDays(999.0);
|
||||
var endDateTime = DateTime.Now + TimeSpan.FromDays(999.0);
|
||||
|
||||
var response = new Models.v3209.GettelopResponse
|
||||
{
|
||||
Result = 1,
|
||||
StartDatetime = startDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
EndDatetime = endDateTime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
Telop = "Hello 3209",
|
||||
VerupNo = 1
|
||||
};
|
||||
|
||||
|
@ -1,92 +1,34 @@
|
||||
using System.Text.Json;
|
||||
using GameDatabase.Entities;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/gettokencount_iut9g23g.php")]
|
||||
[ApiController]
|
||||
public class GetTokenCountController : BaseController<GetTokenCountController>
|
||||
{
|
||||
private readonly IGameDataService gameDataService;
|
||||
private readonly IUserDatumService userDatumService;
|
||||
|
||||
public GetTokenCountController(IUserDatumService userDatumService, IGameDataService gameDataService)
|
||||
{
|
||||
this.userDatumService = userDatumService;
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/gettokencount_iut9g23g.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetTokenCount([FromBody] GetTokenCountRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetTokenCount request : {Request}", request.Stringify());
|
||||
|
||||
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
|
||||
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
|
||||
var commonResponse = await Mediator.Send(new GetTokenCountQuery(request.Baid));
|
||||
var response = TokenCountDataMappers.MapTo3906(commonResponse);
|
||||
|
||||
var tokenDataDictionary = gameDataService.GetTokenDataDictionary();
|
||||
tokenDataDictionary.TryGetValue("shopTokenId", out var shopTokenId);
|
||||
tokenDataDictionary.TryGetValue("kaTokenId", out var kaTokenId);
|
||||
tokenDataDictionary.TryGetValue("onePieceTokenId", out var onePieceTokenId);
|
||||
tokenDataDictionary.TryGetValue("soshinaTokenId", out var soshinaTokenId);
|
||||
tokenDataDictionary.TryGetValue("Yatsushika1TokenId", out var yatsushika1TokenId);
|
||||
tokenDataDictionary.TryGetValue("Yatsushika2TokenId", out var yatsushika2TokenId);
|
||||
tokenDataDictionary.TryGetValue("Yatsushika3TokenId", out var yatsushika3TokenId);
|
||||
tokenDataDictionary.TryGetValue("Yatsushika4TokenId", out var yatsushika4TokenId);
|
||||
tokenDataDictionary.TryGetValue("MaskedKid1TokenId", out var maskedKid1TokenId);
|
||||
tokenDataDictionary.TryGetValue("MaskedKid2TokenId", out var maskedKid2TokenId);
|
||||
tokenDataDictionary.TryGetValue("MaskedKid3TokenId", out var maskedKid3TokenId);
|
||||
tokenDataDictionary.TryGetValue("MaskedKid4TokenId", out var maskedKid4TokenId);
|
||||
tokenDataDictionary.TryGetValue("Kiyoshi1TokenId", out var kiyoshi1TokenId);
|
||||
tokenDataDictionary.TryGetValue("Kiyoshi2TokenId", out var kiyoshi2TokenId);
|
||||
tokenDataDictionary.TryGetValue("Kiyoshi3TokenId", out var kiyoshi3TokenId);
|
||||
tokenDataDictionary.TryGetValue("Kiyoshi4TokenId", out var kiyoshi4TokenId);
|
||||
tokenDataDictionary.TryGetValue("Amitie1TokenId", out var amitie1TokenId);
|
||||
tokenDataDictionary.TryGetValue("Amitie2TokenId", out var amitie2TokenId);
|
||||
tokenDataDictionary.TryGetValue("Amitie3TokenId", out var amitie3TokenId);
|
||||
tokenDataDictionary.TryGetValue("Amitie4TokenId", out var amitie4TokenId);
|
||||
tokenDataDictionary.TryGetValue("Machina1TokenId", out var machina1TokenId);
|
||||
tokenDataDictionary.TryGetValue("Machina2TokenId", out var machina2TokenId);
|
||||
tokenDataDictionary.TryGetValue("Machina3TokenId", out var machina3TokenId);
|
||||
tokenDataDictionary.TryGetValue("Machina4TokenId", out var machina4TokenId);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("v12r00_cn/chassis/gettokencount.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetTokenCount3209([FromBody] Models.v3209.GetTokenCountRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetTokenCount request : {Request}", request.Stringify());
|
||||
|
||||
int[] tokenDataIdArray =
|
||||
{
|
||||
shopTokenId, kaTokenId, onePieceTokenId, soshinaTokenId, yatsushika1TokenId, yatsushika2TokenId,
|
||||
yatsushika3TokenId, yatsushika4TokenId, maskedKid1TokenId, maskedKid2TokenId, maskedKid3TokenId,
|
||||
maskedKid4TokenId, kiyoshi1TokenId, kiyoshi2TokenId, kiyoshi3TokenId, kiyoshi4TokenId, amitie1TokenId,
|
||||
amitie2TokenId, amitie3TokenId, amitie4TokenId, machina1TokenId, machina2TokenId, machina3TokenId,
|
||||
machina4TokenId
|
||||
};
|
||||
|
||||
var response = new GetTokenCountResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
|
||||
foreach (var tokenDataId in tokenDataIdArray)
|
||||
{
|
||||
if (tokenDataId <= 0) continue;
|
||||
var castedTokenDataId = (uint)tokenDataId;
|
||||
if (user.Tokens.All(token => token.Id != castedTokenDataId))
|
||||
{
|
||||
user.Tokens.Add(new Token
|
||||
{
|
||||
Id = (int)castedTokenDataId,
|
||||
Count = 0
|
||||
});
|
||||
}
|
||||
var tokenCount = user.Tokens.First(token => token.Id == castedTokenDataId).Count;
|
||||
response.AryTokenCountDatas.Add(new GetTokenCountResponse.TokenCountData
|
||||
{
|
||||
TokenCount = tokenCount,
|
||||
TokenId = castedTokenDataId
|
||||
});
|
||||
}
|
||||
|
||||
await userDatumService.UpdateUserDatum(user);
|
||||
var commonResponse = await Mediator.Send(new GetTokenCountQuery((uint)request.Baid));
|
||||
var response = TokenCountDataMappers.MapTo3209(commonResponse);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[ApiController]
|
||||
[Route("/v12r08_ww/chassis/heartbeat_hcv5akgr.php")]
|
||||
public class HeartbeatController : BaseController<HeartbeatController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/heartbeat_hcv5akgr.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult HeartBeat([FromBody] HeartBeatRequest request)
|
||||
{
|
||||
@ -18,4 +17,18 @@ public class HeartbeatController : BaseController<HeartbeatController>
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/heartbeat.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult HeartBeat3209([FromBody] Models.v3209.HeartBeatRequest request)
|
||||
{
|
||||
Logger.LogInformation("Heartbeat request: {Request}", request.Stringify());
|
||||
var response = new Models.v3209.HeartBeatResponse
|
||||
{
|
||||
Result = 1,
|
||||
GameSvrStat = 1
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,139 +1,33 @@
|
||||
using Microsoft.Extensions.Options;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
using TaikoLocalServer.Settings;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[ApiController]
|
||||
[Route("/v12r08_ww/chassis/initialdatacheck_vaosv643.php")]
|
||||
public class InitialDataCheckController : BaseController<InitialDataCheckController>
|
||||
{
|
||||
private readonly IGameDataService gameDataService;
|
||||
|
||||
private readonly ServerSettings settings;
|
||||
|
||||
public InitialDataCheckController(IGameDataService gameDataService, IOptions<ServerSettings> settings)
|
||||
{
|
||||
this.gameDataService = gameDataService;
|
||||
this.settings = settings.Value;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/initialdatacheck_vaosv643.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult InitialDataCheck([FromBody] InitialdatacheckRequest request)
|
||||
public async Task<IActionResult> InitialDataCheck([FromBody] InitialdatacheckRequest request)
|
||||
{
|
||||
Logger.LogInformation("Initial data check request: {Request}", request.Stringify());
|
||||
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||
var commonResponse = await Mediator.Send(new GetInitialDataQuery());
|
||||
var response = InitialDataMappers.MapTo3906(commonResponse);
|
||||
|
||||
var musicList = gameDataService.GetMusicList();
|
||||
var lockedSongsList = gameDataService.GetLockedSongsList();
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/initialdatacheck.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> InitialDataCheckCN([FromBody] Models.v3209.InitialdatacheckRequest request)
|
||||
{
|
||||
Logger.LogInformation("Initial data check request: {Request}", request.Stringify());
|
||||
|
||||
var enabledArray =
|
||||
FlagCalculator.GetBitArrayFromIds(musicList, songIdMax, Logger);
|
||||
|
||||
var defaultSongList = musicList.Except(lockedSongsList);
|
||||
var defaultSongFlg =
|
||||
FlagCalculator.GetBitArrayFromIds(defaultSongList, songIdMax, Logger);
|
||||
|
||||
var defaultSongWithUraList = gameDataService.GetMusicWithUraList();
|
||||
var uraReleaseBit =
|
||||
FlagCalculator.GetBitArrayFromIds(defaultSongWithUraList, songIdMax, Logger);
|
||||
|
||||
var response = new InitialdatacheckResponse
|
||||
{
|
||||
Result = 1,
|
||||
DefaultSongFlg = defaultSongFlg,
|
||||
AchievementSongBit = enabledArray,
|
||||
UraReleaseBit = uraReleaseBit,
|
||||
SongIntroductionEndDatetime = DateTime.Now.AddYears(10).ToString(Constants.DATE_TIME_FORMAT),
|
||||
};
|
||||
|
||||
var movieDataDictionary = gameDataService.GetMovieDataDictionary();
|
||||
foreach (var movieData in movieDataDictionary) response.AryMovieInfoes.Add(movieData.Value);
|
||||
|
||||
var verupNo1 = new uint[] { 2, 3, 4, 5, 6, 7, 8, 13, 15, 24, 25, 26, 27, 28, 29, 30, 31, 104 };
|
||||
var aryVerUp = verupNo1.Select(i => new InitialdatacheckResponse.VerupNoData1
|
||||
{
|
||||
MasterType = i,
|
||||
VerupNo = 1
|
||||
})
|
||||
.ToList();
|
||||
response.AryVerupNoData1s.AddRange(aryVerUp);
|
||||
|
||||
var danData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
|
||||
var danDataDictionary = gameDataService.GetDanDataDictionary();
|
||||
foreach (var danId in danDataDictionary.Keys)
|
||||
{
|
||||
gameDataService.GetDanDataDictionary().TryGetValue(danId, out var odaiData);
|
||||
danData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
|
||||
{
|
||||
InfoId = danId,
|
||||
VerupNo = odaiData?.VerupNo ?? 1
|
||||
});
|
||||
}
|
||||
var verUp2Type101 = new InitialdatacheckResponse.VerupNoData2
|
||||
{
|
||||
MasterType = 101,
|
||||
};
|
||||
verUp2Type101.AryInformationDatas.AddRange(danData);
|
||||
response.AryVerupNoData2s.Add(verUp2Type101);
|
||||
|
||||
var gaidenData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
|
||||
var gaidenDataDictionary = gameDataService.GetGaidenDataDictionary();
|
||||
foreach (var gaidenId in gaidenDataDictionary.Keys)
|
||||
{
|
||||
gaidenDataDictionary.TryGetValue(gaidenId, out var odaiData);
|
||||
gaidenData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
|
||||
{
|
||||
InfoId = gaidenId,
|
||||
VerupNo = odaiData?.VerupNo ?? 1
|
||||
});
|
||||
}
|
||||
|
||||
var verUp2Type102 = new InitialdatacheckResponse.VerupNoData2
|
||||
{
|
||||
MasterType = 102,
|
||||
};
|
||||
verUp2Type102.AryInformationDatas.AddRange(gaidenData);
|
||||
response.AryVerupNoData2s.Add(verUp2Type102);
|
||||
|
||||
var eventFolderData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
|
||||
var eventFolderDictionary = gameDataService.GetFolderDictionary();
|
||||
foreach (var folderId in eventFolderDictionary.Keys)
|
||||
{
|
||||
eventFolderDictionary.TryGetValue(folderId, out var folderData);
|
||||
eventFolderData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
|
||||
{
|
||||
InfoId = folderId,
|
||||
VerupNo = folderData?.VerupNo ?? 1
|
||||
});
|
||||
}
|
||||
var verUp2Type103 = new InitialdatacheckResponse.VerupNoData2
|
||||
{
|
||||
MasterType = 103,
|
||||
};
|
||||
verUp2Type103.AryInformationDatas.AddRange(eventFolderData);
|
||||
response.AryVerupNoData2s.Add(verUp2Type103);
|
||||
|
||||
var songIntroData = new List<InitialdatacheckResponse.VerupNoData2.InformationData>();
|
||||
var songIntroDictionary = gameDataService.GetSongIntroDictionary();
|
||||
foreach (var setId in songIntroDictionary.Select(item => item.Value.SetId))
|
||||
{
|
||||
songIntroDictionary.TryGetValue(setId, out var introData);
|
||||
songIntroData.Add(new InitialdatacheckResponse.VerupNoData2.InformationData
|
||||
{
|
||||
InfoId = setId,
|
||||
VerupNo = introData?.VerupNo ?? 1
|
||||
});
|
||||
}
|
||||
var verUp2Type105 = new InitialdatacheckResponse.VerupNoData2
|
||||
{
|
||||
MasterType = 105,
|
||||
};
|
||||
verUp2Type105.AryInformationDatas.AddRange(songIntroData);
|
||||
response.AryVerupNoData2s.Add(verUp2Type105);
|
||||
|
||||
response.AryChassisFunctionIds = new uint[] { 1, 2, 3 };
|
||||
var commonResponse = await Mediator.Send(new GetInitialDataQuery());
|
||||
var response = InitialDataMappers.MapTo3209(commonResponse);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
@ -1,73 +1,31 @@
|
||||
using GameDatabase.Entities;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/mydonentry_3nrd7kwk.php")]
|
||||
[ApiController]
|
||||
public class MyDonEntryController : BaseController<MyDonEntryController>
|
||||
{
|
||||
private readonly IUserDatumService userDatumService;
|
||||
|
||||
private readonly ICardService cardService;
|
||||
|
||||
private readonly ICredentialService credentialService;
|
||||
|
||||
public MyDonEntryController(IUserDatumService userDatumService, ICardService cardService, ICredentialService credentialService)
|
||||
{
|
||||
this.userDatumService = userDatumService;
|
||||
this.cardService = cardService;
|
||||
this.credentialService = credentialService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/mydonentry_3nrd7kwk.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetMyDonEntry([FromBody] MydonEntryRequest request)
|
||||
{
|
||||
Logger.LogInformation("MyDonEntry request : {Request}", request.Stringify());
|
||||
|
||||
var newId = cardService.GetNextBaid();
|
||||
|
||||
var newUser = new UserDatum
|
||||
{
|
||||
Baid = newId,
|
||||
MyDonName = request.MydonName,
|
||||
MyDonNameLanguage = 0,
|
||||
DisplayDan = true,
|
||||
DisplayAchievement = true,
|
||||
AchievementDisplayDifficulty = Difficulty.None,
|
||||
ColorFace = 0,
|
||||
ColorBody = 1,
|
||||
ColorLimb = 3,
|
||||
FavoriteSongsArray = "[]",
|
||||
ToneFlgArray = "[0]",
|
||||
TitleFlgArray = "[]",
|
||||
CostumeFlgArray = "[[0],[0],[0],[0],[0]]",
|
||||
GenericInfoFlgArray = "[]",
|
||||
UnlockedSongIdList = "[]"
|
||||
};
|
||||
await userDatumService.InsertUserDatum(newUser);
|
||||
|
||||
await cardService.AddCard(new Card
|
||||
{
|
||||
AccessCode = request.AccessCode,
|
||||
Baid = newId
|
||||
});
|
||||
|
||||
await credentialService.AddCredential(new Credential
|
||||
{
|
||||
Baid = newId,
|
||||
Password = "",
|
||||
Salt = ""
|
||||
});
|
||||
|
||||
var response = new MydonEntryResponse
|
||||
{
|
||||
Result = 1,
|
||||
Baid = newId,
|
||||
MydonName = request.MydonName,
|
||||
MydonNameLanguage = 0
|
||||
};
|
||||
var commonResponse = await Mediator.Send(new AddMyDonEntryCommand(request.AccessCode, request.MydonName, request.MydonNameLanguage));
|
||||
var response = MyDonEntryMappers.MapTo3906(commonResponse);
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/mydonentry.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> GetMyDonEntry3209([FromBody] Models.v3209.MydonEntryRequest request)
|
||||
{
|
||||
Logger.LogInformation("MyDonEntry request : {Request}", request.Stringify());
|
||||
|
||||
var commonResponse = await Mediator.Send(new AddMyDonEntryCommand(request.WechatQrStr, request.MydonName, request.MydonNameLanguage));
|
||||
var response = MyDonEntryMappers.MapTo3209(commonResponse);
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -222,11 +222,16 @@ public class PlayResultController : BaseController<PlayResultController>
|
||||
userdata.LastPlayDatetime = lastPlayDatetime;
|
||||
userdata.LastPlayMode = playResultData.PlayMode;
|
||||
|
||||
userdata.ToneFlgArray =
|
||||
UpdateJsonUintFlagArray(userdata.ToneFlgArray, playResultData.GetToneNoes, nameof(userdata.ToneFlgArray));
|
||||
var tones = userdata.ToneFlgArray.ToList();
|
||||
tones.AddRange(playResultData.GetToneNoes);
|
||||
userdata.ToneFlgArray = tones.ToArray();
|
||||
//UpdateJsonUintFlagArray(userdata.ToneFlgArray, playResultData.GetToneNoes, nameof(userdata.ToneFlgArray));
|
||||
|
||||
userdata.TitleFlgArray =
|
||||
UpdateJsonUintFlagArray(userdata.TitleFlgArray, playResultData.GetTitleNoes, nameof(userdata.TitleFlgArray));
|
||||
/*userdata.TitleFlgArray =
|
||||
UpdateJsonUintFlagArray(userdata.TitleFlgArray, playResultData.GetTitleNoes, nameof(userdata.TitleFlgArray));*/
|
||||
var titles = userdata.TitleFlgArray.ToList();
|
||||
titles.AddRange(playResultData.GetTitleNoes);
|
||||
userdata.TitleFlgArray = titles.ToArray();
|
||||
|
||||
userdata.CostumeFlgArray = UpdateJsonCostumeFlagArray(userdata.CostumeFlgArray,
|
||||
new[]
|
||||
@ -238,8 +243,11 @@ public class PlayResultController : BaseController<PlayResultController>
|
||||
playResultData.GetCostumeNo5s
|
||||
});
|
||||
|
||||
userdata.GenericInfoFlgArray =
|
||||
UpdateJsonUintFlagArray(userdata.GenericInfoFlgArray, playResultData.GetGenericInfoNoes, nameof(userdata.GenericInfoFlgArray));
|
||||
/*userdata.GenericInfoFlgArray =
|
||||
UpdateJsonUintFlagArray(userdata.GenericInfoFlgArray, playResultData.GetGenericInfoNoes, nameof(userdata.GenericInfoFlgArray));*/
|
||||
var genericInfo = userdata.GenericInfoFlgArray.ToList();
|
||||
genericInfo.AddRange(playResultData.GetGenericInfoNoes);
|
||||
userdata.GenericInfoFlgArray = genericInfo.ToArray();
|
||||
|
||||
var difficultyPlayedArray = new List<uint>
|
||||
{
|
||||
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/rewarditem.php")]
|
||||
[ApiController]
|
||||
public class RewardItemController : BaseController<RewardItemController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/rewarditem.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult RewardItem([FromBody] RewardItemRequest request)
|
||||
{
|
||||
@ -17,4 +16,18 @@ public class RewardItemController : BaseController<RewardItemController>
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/rewarditem.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult RewardItem3209([FromBody] Models.v3209.RewardItemRequest request)
|
||||
{
|
||||
Logger.LogInformation("RewardItem request : {Request}", request.Stringify());
|
||||
|
||||
var response = new Models.v3209.RewardItemResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,81 +1,36 @@
|
||||
using GameDatabase.Entities;
|
||||
using TaikoLocalServer.Handlers;
|
||||
using TaikoLocalServer.Mappers;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/selfbest_5nz47auu.php")]
|
||||
[ApiController]
|
||||
public class SelfBestController : BaseController<SelfBestController>
|
||||
{
|
||||
private readonly ISongBestDatumService songBestDatumService;
|
||||
|
||||
private readonly IGameDataService gameDataService;
|
||||
|
||||
public SelfBestController(ISongBestDatumService songBestDatumService, IGameDataService gameDataService)
|
||||
{
|
||||
this.songBestDatumService = songBestDatumService;
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/selfbest_5nz47auu.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> SelfBest([FromBody] SelfBestRequest request)
|
||||
{
|
||||
Logger.LogInformation("SelfBest request : {Request}", request.Stringify());
|
||||
|
||||
var response = new SelfBestResponse
|
||||
{
|
||||
Result = 1,
|
||||
Level = request.Level
|
||||
};
|
||||
|
||||
var requestDifficulty = (Difficulty)request.Level;
|
||||
requestDifficulty.Throw().IfOutOfRange();
|
||||
|
||||
var playerBestData = await songBestDatumService.GetAllSongBestData(request.Baid);
|
||||
playerBestData = playerBestData
|
||||
.Where(datum => datum.Difficulty == requestDifficulty ||
|
||||
(datum.Difficulty == Difficulty.UraOni && requestDifficulty == Difficulty.Oni))
|
||||
.ToList();
|
||||
foreach (var songNo in request.ArySongNoes)
|
||||
{
|
||||
if (!gameDataService.GetMusicList().Contains(songNo))
|
||||
{
|
||||
Logger.LogWarning("Music no {No} is missing!", songNo);
|
||||
continue;
|
||||
}
|
||||
|
||||
var selfBestData = GetSongSelfBestData(playerBestData, songNo);
|
||||
|
||||
response.ArySelfbestScores.Add(selfBestData);
|
||||
}
|
||||
response.ArySelfbestScores.Sort((data, otherData) => data.SongNo.CompareTo(otherData.SongNo));
|
||||
var commonResponse =
|
||||
await Mediator.Send(new GetSelfBestQuery(request.Baid, request.Level, request.ArySongNoes));
|
||||
var response = SelfBestMappers.MapTo3906(commonResponse);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
private static SelfBestResponse.SelfBestData GetSongSelfBestData(IEnumerable<SongBestDatum> playerBestData, uint songNo)
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/selfbest.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public async Task<IActionResult> SelfBest3209([FromBody] Models.v3209.SelfBestRequest request)
|
||||
{
|
||||
var songBestDatum = playerBestData.Where(datum => datum.SongId == songNo);
|
||||
Logger.LogInformation("SelfBest3209 request : {Request}", request.Stringify());
|
||||
|
||||
var selfBestData = new SelfBestResponse.SelfBestData
|
||||
{
|
||||
SongNo = songNo,
|
||||
};
|
||||
var commonResponse =
|
||||
await Mediator.Send(new GetSelfBestQuery((uint)request.Baid, request.Level, request.ArySongNoes));
|
||||
var response = SelfBestMappers.MapTo3209(commonResponse);
|
||||
|
||||
foreach (var datum in songBestDatum)
|
||||
{
|
||||
if (datum.Difficulty == Difficulty.UraOni)
|
||||
{
|
||||
selfBestData.UraBestScore = datum.BestScore;
|
||||
selfBestData.UraBestScoreRate = datum.BestRate;
|
||||
continue;
|
||||
}
|
||||
|
||||
selfBestData.SelfBestScore = datum.BestScore;
|
||||
selfBestData.SelfBestScoreRate = datum.BestRate;
|
||||
}
|
||||
|
||||
return selfBestData;
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/setanystring_mssxf3bo.php")]
|
||||
[ApiController]
|
||||
public class SetAnyStringController : BaseController<SetAnyStringController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/setanystring_mssxf3bo.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult SetAnyString([FromBody] SetAnyStringRequest request)
|
||||
{
|
||||
@ -17,4 +16,18 @@ public class SetAnyStringController : BaseController<SetAnyStringController>
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/setanystring.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult SetAnyString3209([FromBody] Models.v3209.SetAnyStringRequest request)
|
||||
{
|
||||
Logger.LogInformation("SetAnyString request : {Request}", request.Stringify());
|
||||
|
||||
var response = new Models.v3209.SetAnyStringResponse
|
||||
{
|
||||
Result = 1,
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -23,37 +23,9 @@ public class SongPurchaseController : BaseController<SongPurchaseController>
|
||||
var user = await userDatumService.GetFirstUserDatumOrNull(request.Baid);
|
||||
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
|
||||
|
||||
/*var tokenCountDict = new Dictionary<uint, int>();
|
||||
try
|
||||
{
|
||||
tokenCountDict = !string.IsNullOrEmpty(user.TokenCountDict)
|
||||
? JsonSerializer.Deserialize<Dictionary<uint, int>>(user.TokenCountDict)
|
||||
: new Dictionary<uint, int>();
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
Logger.LogError(e, "Parsing TokenCountDict data for user with baid {Request} failed!", request.Baid);
|
||||
}
|
||||
|
||||
tokenCountDict.ThrowIfNull("TokenCountDict should never be null");*/
|
||||
|
||||
Logger.LogInformation("Original UnlockedSongIdList: {UnlockedSongIdList}", user.UnlockedSongIdList);
|
||||
|
||||
var unlockedSongIdList = new List<uint>();
|
||||
try
|
||||
{
|
||||
unlockedSongIdList = !string.IsNullOrEmpty(user.UnlockedSongIdList)
|
||||
? JsonSerializer.Deserialize<List<uint>>(user.UnlockedSongIdList)
|
||||
: new List<uint>();
|
||||
}
|
||||
catch (JsonException e)
|
||||
{
|
||||
Logger.LogError(e, "Parsing UnlockedSongIdList data for user with baid {Request} failed!", request.Baid);
|
||||
}
|
||||
|
||||
unlockedSongIdList.ThrowIfNull("UnlockedSongIdList should never be null");
|
||||
|
||||
//if (tokenCountDict.ContainsKey(request.TokenId)) tokenCountDict[request.TokenId] -= (int)request.Price;
|
||||
var unlockedSongIdList = user.UnlockedSongIdList.ToList();
|
||||
|
||||
var token = user.Tokens.FirstOrDefault(t => t.Id == request.TokenId);
|
||||
if (token is not null && token.Count >= request.Price)
|
||||
@ -68,7 +40,7 @@ public class SongPurchaseController : BaseController<SongPurchaseController>
|
||||
|
||||
if (!unlockedSongIdList.Contains(request.SongNo)) unlockedSongIdList.Add(request.SongNo);
|
||||
|
||||
user.UnlockedSongIdList = JsonSerializer.Serialize(unlockedSongIdList);
|
||||
user.UnlockedSongIdList = unlockedSongIdList.ToArray();
|
||||
|
||||
Logger.LogInformation("Updated UnlockedSongIdList: {UnlockedSongIdList}", user.UnlockedSongIdList);
|
||||
|
||||
|
@ -1,10 +1,9 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/tournamentcheck.php")]
|
||||
[ApiController]
|
||||
public class TournamentCheckController : BaseController<TournamentCheckController>
|
||||
{
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/tournamentcheck.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult TournamentCheck([FromBody] TournamentcheckRequest request)
|
||||
{
|
||||
@ -17,4 +16,18 @@ public class TournamentCheckController : BaseController<TournamentCheckControlle
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
[HttpPost("/v12r00_cn/chassis/tournamentcheck.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult TournamentCheck3209([FromBody] Models.v3209.TournamentcheckRequest request)
|
||||
{
|
||||
Logger.LogInformation("TournamentCheck request : {Request}", request.Stringify());
|
||||
|
||||
var response = new Models.v3209.TournamentcheckResponse
|
||||
{
|
||||
Result = 1,
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
}
|
@ -37,7 +37,7 @@ public class UserDataController : BaseController<UserDataController>
|
||||
|
||||
var userData = await userDatumService.GetFirstUserDatumOrDefault(request.Baid);
|
||||
|
||||
var unlockedSongIdList = new List<uint>();
|
||||
var unlockedSongIdList = userData.UnlockedSongIdList;/*new List<uint>();
|
||||
try
|
||||
{
|
||||
unlockedSongIdList = !string.IsNullOrEmpty(userData.UnlockedSongIdList)
|
||||
@ -49,7 +49,7 @@ public class UserDataController : BaseController<UserDataController>
|
||||
Logger.LogError(e, "Parsing UnlockedSongIdList data for user with baid {Request} failed!", request.Baid);
|
||||
}
|
||||
|
||||
unlockedSongIdList.ThrowIfNull("UnlockedSongIdList should never be null");
|
||||
unlockedSongIdList.ThrowIfNull("UnlockedSongIdList should never be null");*/
|
||||
|
||||
var musicList = gameDataService.GetMusicList();
|
||||
var lockedSongsList = gameDataService.GetLockedSongsList();
|
||||
@ -63,7 +63,7 @@ public class UserDataController : BaseController<UserDataController>
|
||||
var uraSongArray =
|
||||
FlagCalculator.GetBitArrayFromIds(enabledUraMusicList, songIdMax, Logger);
|
||||
|
||||
var toneFlg = Array.Empty<uint>();
|
||||
var toneFlg = userData.ToneFlgArray;/*Array.Empty<uint>();
|
||||
try
|
||||
{
|
||||
toneFlg = JsonSerializer.Deserialize<uint[]>(userData.ToneFlgArray);
|
||||
@ -75,19 +75,19 @@ public class UserDataController : BaseController<UserDataController>
|
||||
|
||||
// The only way to get a null is provide string "null" as input,
|
||||
// which means database content need to be fixed, so better throw
|
||||
toneFlg.ThrowIfNull("Tone flg should never be null!");
|
||||
toneFlg.ThrowIfNull("Tone flg should never be null!");*/
|
||||
|
||||
// If toneFlg is empty, add 0 to it
|
||||
if (toneFlg.Length == 0)
|
||||
{
|
||||
toneFlg = new uint[] { 0 };
|
||||
userData.ToneFlgArray = JsonSerializer.Serialize(toneFlg);
|
||||
userData.ToneFlgArray = toneFlg;//JsonSerializer.Serialize(toneFlg);
|
||||
await userDatumService.UpdateUserDatum(userData);
|
||||
}
|
||||
|
||||
var toneArray = FlagCalculator.GetBitArrayFromIds(toneFlg, gameDataService.GetToneFlagArraySize(), Logger);
|
||||
|
||||
var titleFlg = Array.Empty<uint>();
|
||||
var titleFlg = userData.TitleFlgArray;/*Array.Empty<uint>();
|
||||
try
|
||||
{
|
||||
titleFlg = JsonSerializer.Deserialize<uint[]>(userData.TitleFlgArray);
|
||||
@ -99,7 +99,7 @@ public class UserDataController : BaseController<UserDataController>
|
||||
|
||||
// The only way to get a null is provide string "null" as input,
|
||||
// which means database content need to be fixed, so better throw
|
||||
titleFlg.ThrowIfNull("Title flg should never be null!");
|
||||
titleFlg.ThrowIfNull("Title flg should never be null!");*/
|
||||
|
||||
var titleArray = FlagCalculator.GetBitArrayFromIds(titleFlg, gameDataService.GetTitleFlagArraySize(), Logger);
|
||||
|
||||
@ -123,7 +123,7 @@ public class UserDataController : BaseController<UserDataController>
|
||||
|
||||
recentSongs = recentSet.ToArray();
|
||||
|
||||
var favoriteSongs = Array.Empty<uint>();
|
||||
var favoriteSongs = userData.FavoriteSongsArray;/*Array.Empty<uint>();
|
||||
try
|
||||
{
|
||||
favoriteSongs = JsonSerializer.Deserialize<uint[]>(userData.FavoriteSongsArray);
|
||||
@ -135,7 +135,7 @@ public class UserDataController : BaseController<UserDataController>
|
||||
|
||||
// The only way to get a null is provide string "null" as input,
|
||||
// which means database content need to be fixed, so better throw
|
||||
favoriteSongs.ThrowIfNull("Favorite song should never be null!");
|
||||
favoriteSongs.ThrowIfNull("Favorite song should never be null!");*/
|
||||
|
||||
var defaultOptions = new byte[2];
|
||||
BinaryPrimitives.WriteInt16LittleEndian(defaultOptions, userData.OptionSetting);
|
||||
|
@ -1,6 +1,5 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r08_ww/chassis/verifyqrcode_ku5ra5q7.php")]
|
||||
[ApiController]
|
||||
public class VerifyQrCodeController : BaseController<VerifyQrCodeController>
|
||||
{
|
||||
@ -11,27 +10,39 @@ public class VerifyQrCodeController : BaseController<VerifyQrCodeController>
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[HttpPost("/v12r08_ww/chassis/verifyqrcode_ku5ra5q7.php")]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult VerifyQrCode([FromBody] VerifyQrcodeRequest request)
|
||||
{
|
||||
Logger.LogInformation("VerifyQrCode request : {Request}", request.Stringify());
|
||||
|
||||
var qrCodeDataDictionary = gameDataService.GetQRCodeDataDictionary();
|
||||
|
||||
qrCodeDataDictionary.TryGetValue(request.QrcodeSerial, out var qrCodeId);
|
||||
|
||||
if (qrCodeId == 0)
|
||||
{
|
||||
Logger.LogWarning("Requested QR code serial {Serial} does not exist!", request.QrcodeSerial);
|
||||
}
|
||||
|
||||
var qrCodeId = VerifyQr(request.QrcodeSerial);
|
||||
var response = new VerifyQrcodeResponse
|
||||
{
|
||||
Result = 1,
|
||||
QrcodeId = qrCodeId
|
||||
QrcodeId = (uint)qrCodeId
|
||||
};
|
||||
|
||||
if (qrCodeId == -1)
|
||||
{
|
||||
response.Result = 51;
|
||||
}
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
private int VerifyQr(string serial)
|
||||
{
|
||||
var qrCodeDataDictionary = gameDataService.GetQRCodeDataDictionary();
|
||||
|
||||
qrCodeDataDictionary.TryGetValue(serial, out var qrCodeId);
|
||||
|
||||
if (qrCodeId == 0)
|
||||
{
|
||||
Logger.LogWarning("Requested QR code serial {Serial} does not exist!", serial);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (int)qrCodeId;
|
||||
}
|
||||
}
|
@ -2,9 +2,10 @@
|
||||
global using Microsoft.AspNetCore.Mvc;
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
global using ProtoBuf;
|
||||
global using MediatR;
|
||||
global using Swan.Formatters;
|
||||
global using SharedProject.Enums;
|
||||
global using taiko.game;
|
||||
global using TaikoLocalServer.Models.v3906;
|
||||
global using TaikoLocalServer.Common;
|
||||
global using TaikoLocalServer.Common.Utils;
|
||||
global using TaikoLocalServer.Models;
|
||||
|
64
TaikoLocalServer/Handlers/AddMyDonEntryCommand.cs
Normal file
64
TaikoLocalServer/Handlers/AddMyDonEntryCommand.cs
Normal file
@ -0,0 +1,64 @@
|
||||
using GameDatabase.Context;
|
||||
using GameDatabase.Entities;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
public record AddMyDonEntryCommand(string AccessCode, string Name, uint Language) : IRequest<CommonMyDonEntryResponse>;
|
||||
|
||||
public class AddMyDonEntryCommandHandler(TaikoDbContext context, ILogger<AddMyDonEntryCommandHandler> logger)
|
||||
: IRequestHandler<AddMyDonEntryCommand, CommonMyDonEntryResponse>
|
||||
{
|
||||
public async Task<CommonMyDonEntryResponse> Handle(AddMyDonEntryCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var nextBaid = await context.Cards.Select(card => card.Baid)
|
||||
.DefaultIfEmpty(0u)
|
||||
.MaxAsync(cancellationToken) + 1;
|
||||
var newUser = new UserDatum
|
||||
{
|
||||
Baid = nextBaid,
|
||||
MyDonName = request.Name,
|
||||
MyDonNameLanguage = request.Language,
|
||||
DisplayDan = true,
|
||||
DisplayAchievement = true,
|
||||
AchievementDisplayDifficulty = Difficulty.None,
|
||||
ColorFace = 0,
|
||||
ColorBody = 1,
|
||||
ColorLimb = 3,
|
||||
FavoriteSongsArray = [],
|
||||
ToneFlgArray = [0],
|
||||
TitleFlgArray = [],
|
||||
CostumeFlgArray = "[[0],[0],[0],[0],[0]]",
|
||||
GenericInfoFlgArray = [],
|
||||
UnlockedSongIdList = []
|
||||
};
|
||||
|
||||
context.UserData.Add(newUser);
|
||||
|
||||
var newCard = new Card
|
||||
{
|
||||
AccessCode = request.AccessCode,
|
||||
Baid = nextBaid
|
||||
};
|
||||
context.Cards.Add(newCard);
|
||||
|
||||
var newCredential = new Credential
|
||||
{
|
||||
Baid = nextBaid,
|
||||
Password = "",
|
||||
Salt = ""
|
||||
};
|
||||
context.Credentials.Add(newCredential);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
var response = new CommonMyDonEntryResponse
|
||||
{
|
||||
Result = 1,
|
||||
Baid = nextBaid,
|
||||
MydonName = request.Name,
|
||||
MydonNameLanguage = request.Language,
|
||||
ComSvrResult = 1,
|
||||
AccessCode = request.AccessCode
|
||||
};
|
||||
return response;
|
||||
}
|
||||
}
|
53
TaikoLocalServer/Handlers/AddTokenCountCommand.cs
Normal file
53
TaikoLocalServer/Handlers/AddTokenCountCommand.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using GameDatabase.Context;
|
||||
using GameDatabase.Entities;
|
||||
using MediatR;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record AddTokenCountCommand(CommonAddTokenCountRequest Request) : IRequest;
|
||||
|
||||
public class AddTokenCountCommandHandler : IRequestHandler<AddTokenCountCommand>
|
||||
{
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
private readonly ILogger<AddTokenCountCommandHandler> logger;
|
||||
|
||||
public AddTokenCountCommandHandler(TaikoDbContext context, ILogger<AddTokenCountCommandHandler> logger)
|
||||
{
|
||||
this.context = context;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task Handle(AddTokenCountCommand command, CancellationToken cancellationToken)
|
||||
{
|
||||
var request = command.Request;
|
||||
var user = await context.UserData
|
||||
.Include(userDatum => userDatum.Tokens)
|
||||
.FirstOrDefaultAsync(datum => datum.Baid == request.Baid, cancellationToken);
|
||||
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
|
||||
|
||||
foreach (var addTokenCountData in request.AryAddTokenCountDatas)
|
||||
{
|
||||
var tokenId = addTokenCountData.TokenId;
|
||||
var addTokenCount = addTokenCountData.AddTokenCount;
|
||||
var token = user.Tokens.FirstOrDefault(t => t.Id == tokenId);
|
||||
if (token is not null)
|
||||
{
|
||||
token.Count += addTokenCount;
|
||||
}
|
||||
else
|
||||
{
|
||||
user.Tokens.Add(new Token
|
||||
{
|
||||
Id = (int)tokenId,
|
||||
Count = addTokenCount
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
context.Update(user);
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
}
|
||||
}
|
146
TaikoLocalServer/Handlers/BaidQuery.cs
Normal file
146
TaikoLocalServer/Handlers/BaidQuery.cs
Normal file
@ -0,0 +1,146 @@
|
||||
using System.Text.Json;
|
||||
using GameDatabase.Context;
|
||||
using MediatR;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record BaidQuery(string AccessCode) : IRequest<CommonBaidResponse>;
|
||||
|
||||
public class BaidQueryHandler : IRequestHandler<BaidQuery, CommonBaidResponse>
|
||||
{
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
private readonly ILogger<BaidQueryHandler> logger;
|
||||
|
||||
private readonly IGameDataService gameDataService;
|
||||
|
||||
public BaidQueryHandler(TaikoDbContext context, ILogger<BaidQueryHandler> logger, IGameDataService gameDataService)
|
||||
{
|
||||
this.context = context;
|
||||
this.logger = logger;
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
public async Task<CommonBaidResponse> Handle(BaidQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var card = await context.Cards.FindAsync(request.AccessCode);
|
||||
if (card is null)
|
||||
{
|
||||
logger.LogInformation("New user with access code {AccessCode}", request.AccessCode);
|
||||
return new CommonBaidResponse
|
||||
{
|
||||
IsNewUser = true,
|
||||
Baid = context.Cards.Any() ? context.Cards.ToList().Max(c => c.Baid) + 1 : 1
|
||||
};
|
||||
}
|
||||
|
||||
var baid = card.Baid;
|
||||
var userData = await context.UserData.FindAsync(baid);
|
||||
userData.ThrowIfNull($"User not found for card with Baid {baid}!");
|
||||
|
||||
var songBestData = context.SongBestData.Where(datum => datum.Baid == baid);
|
||||
var achievementDisplayDifficulty = userData.AchievementDisplayDifficulty;
|
||||
if (achievementDisplayDifficulty == Difficulty.None)
|
||||
{
|
||||
achievementDisplayDifficulty = songBestData
|
||||
.Where(datum => datum.BestCrown >= CrownType.Clear)
|
||||
.Select(datum => datum.Difficulty)
|
||||
.DefaultIfEmpty(Difficulty.Easy)
|
||||
.Max();
|
||||
}
|
||||
// For each crown type, calculate how many songs have that crown type
|
||||
var crownCountData = await songBestData
|
||||
.Where(datum => datum.BestCrown >= CrownType.Clear)
|
||||
.GroupBy(datum => datum.BestCrown)
|
||||
.ToDictionaryAsync(datums => datums.Key, datums => (uint)datums.Count(), cancellationToken);
|
||||
var crownCount = new uint[3];
|
||||
foreach (var crownType in Enum.GetValues<CrownType>())
|
||||
{
|
||||
if (crownType != CrownType.None)
|
||||
{
|
||||
crownCount[(int)crownType - 1] = crownCountData.GetValueOrDefault(crownType, (uint)0);
|
||||
}
|
||||
}
|
||||
|
||||
var scoreRankData = await songBestData
|
||||
.Where(datum => datum.BestCrown >= CrownType.Clear)
|
||||
.GroupBy(datum => datum.BestScoreRank)
|
||||
.ToDictionaryAsync(datums => datums.Key, datums => (uint)datums.Count(), cancellationToken);
|
||||
var scoreRankCount = new uint[7];
|
||||
foreach (var scoreRank in Enum.GetValues<ScoreRank>())
|
||||
{
|
||||
if (scoreRank != ScoreRank.None)
|
||||
{
|
||||
scoreRankCount[(int)scoreRank - 2] = scoreRankData.GetValueOrDefault(scoreRank, (uint)0);
|
||||
}
|
||||
}
|
||||
|
||||
var costumeData = JsonHelper.GetCostumeDataFromUserData(userData, logger);
|
||||
|
||||
var costumeArrays = JsonHelper.GetCostumeUnlockDataFromUserData(userData, logger);
|
||||
|
||||
var costumeFlagArrays = gameDataService.GetCostumeFlagArraySizes()
|
||||
.Select((size, index) => FlagCalculator.GetBitArrayFromIds(costumeArrays[index], size, logger))
|
||||
.ToList();
|
||||
|
||||
var danData = await context.DanScoreData
|
||||
.Where(datum => datum.Baid == baid && datum.DanType == DanType.Normal)
|
||||
.Include(datum => datum.DanStageScoreData).ToListAsync(cancellationToken);
|
||||
var gaidenData = await context.DanScoreData
|
||||
.Where(datum => datum.Baid == baid && datum.DanType == DanType.Gaiden)
|
||||
.Include(datum => datum.DanStageScoreData).ToListAsync(cancellationToken);
|
||||
|
||||
var maxDan = danData.Where(datum => datum.ClearState != DanClearState.NotClear)
|
||||
.Select(datum => datum.DanId)
|
||||
.DefaultIfEmpty()
|
||||
.Max();
|
||||
|
||||
var danDataDictionary = gameDataService.GetCommonDanDataDictionary();
|
||||
var danIdList = danDataDictionary.Keys.ToList();
|
||||
var gotDanFlagArray = FlagCalculator.ComputeGotDanFlags(danData, danIdList);
|
||||
|
||||
var gaidenDataDictionary = gameDataService.GetCommonGaidenDataDictionary();
|
||||
var gaidenIdList = gaidenDataDictionary.Keys.ToList();
|
||||
var gotGaidenFlagArray = FlagCalculator.ComputeGotDanFlags(gaidenData, gaidenIdList);
|
||||
|
||||
var genericInfoFlg = userData.GenericInfoFlgArray;
|
||||
|
||||
var genericInfoFlgLength = genericInfoFlg.Any() ? genericInfoFlg.Max() + 1 : 0;
|
||||
var genericInfoFlgArray = FlagCalculator.GetBitArrayFromIds(genericInfoFlg, (int)genericInfoFlgLength, logger);
|
||||
|
||||
var aiRank = (uint)(userData.AiWinCount / 10);
|
||||
if (aiRank > 11)
|
||||
{
|
||||
aiRank = 11;
|
||||
}
|
||||
|
||||
return new CommonBaidResponse
|
||||
{
|
||||
IsNewUser = false,
|
||||
Baid = baid,
|
||||
MyDonName = userData.MyDonName,
|
||||
MyDonNameLanguage = userData.MyDonNameLanguage,
|
||||
AryCrownCounts = crownCount,
|
||||
AryScoreRankCounts = scoreRankCount,
|
||||
ColorBody = userData.ColorBody,
|
||||
ColorFace = userData.ColorFace,
|
||||
ColorLimb = userData.ColorLimb,
|
||||
CostumeData = costumeData,
|
||||
CostumeFlagArrays = costumeFlagArrays,
|
||||
DisplayDan = userData.DisplayDan,
|
||||
DispAchievementType = (uint)achievementDisplayDifficulty,
|
||||
GenericInfoFlg = genericInfoFlgArray,
|
||||
GotDanFlg = gotDanFlagArray,
|
||||
GotDanMax = maxDan,
|
||||
GotGaidenFlg = gotGaidenFlagArray,
|
||||
IsDispAchievementOn = userData.DisplayAchievement,
|
||||
LastPlayDatetime = userData.LastPlayDatetime.ToString(Constants.DATE_TIME_FORMAT),
|
||||
LastPlayMode = userData.LastPlayMode,
|
||||
SelectedToneId = userData.SelectedToneId,
|
||||
Title = userData.Title,
|
||||
TitlePlateId = userData.TitlePlateId
|
||||
};
|
||||
}
|
||||
}
|
35
TaikoLocalServer/Handlers/GetAiDataQuery.cs
Normal file
35
TaikoLocalServer/Handlers/GetAiDataQuery.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using GameDatabase.Context;
|
||||
using MediatR;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetAiDataQuery(uint Baid) : IRequest<CommonAiDataResponse>;
|
||||
|
||||
public class GetAiDataQueryHandler : IRequestHandler<GetAiDataQuery, CommonAiDataResponse>
|
||||
{
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
private readonly ILogger<GetAiDataQueryHandler> logger;
|
||||
|
||||
|
||||
public GetAiDataQueryHandler(TaikoDbContext context, ILogger<GetAiDataQueryHandler> logger)
|
||||
{
|
||||
this.context = context;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<CommonAiDataResponse> Handle(GetAiDataQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var user = await context.UserData.FirstOrDefaultAsync(datum => datum.Baid == request.Baid);
|
||||
user.ThrowIfNull($"User with baid {request.Baid} does not exist!");
|
||||
var response = new CommonAiDataResponse
|
||||
{
|
||||
TotalWinnings = (uint)user.AiWinCount,
|
||||
InputMedian = "1",
|
||||
InputVariance = "0"
|
||||
};
|
||||
return response;
|
||||
}
|
||||
}
|
34
TaikoLocalServer/Handlers/GetAiScoreQuery.cs
Normal file
34
TaikoLocalServer/Handlers/GetAiScoreQuery.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using GameDatabase.Context;
|
||||
using TaikoLocalServer.Mappers;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetAiScoreQuery(uint Baid, uint SongId, uint Level) : IRequest<CommonAiScoreResponse>;
|
||||
|
||||
public class GetAiScoreQueryHandler : IRequestHandler<GetAiScoreQuery, CommonAiScoreResponse>
|
||||
{
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
private readonly ILogger<GetAiScoreQueryHandler> logger;
|
||||
|
||||
public GetAiScoreQueryHandler(TaikoDbContext context, ILogger<GetAiScoreQueryHandler> logger)
|
||||
{
|
||||
this.context = context;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<CommonAiScoreResponse> Handle(GetAiScoreQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var difficulty = (Difficulty)request.Level;
|
||||
difficulty.Throw().IfOutOfRange();
|
||||
|
||||
var aiData = await context.AiScoreData.Where(datum => datum.Baid == request.Baid &&
|
||||
datum.SongId == request.SongId &&
|
||||
datum.Difficulty == difficulty)
|
||||
.Include(datum => datum.AiSectionScoreData)
|
||||
.FirstOrDefaultAsync(cancellationToken);
|
||||
return aiData is null ? new CommonAiScoreResponse() : AiScoreMappers.MapToCommonAiScoreResponse(aiData);
|
||||
}
|
||||
}
|
52
TaikoLocalServer/Handlers/GetDanOdaiQuery.cs
Normal file
52
TaikoLocalServer/Handlers/GetDanOdaiQuery.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using SharedProject.Models;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetDanOdaiQuery(uint[] DanIds, uint Type) : IRequest<List<DanData>>;
|
||||
|
||||
public class GetDanOdaiQueryHandler : IRequestHandler<GetDanOdaiQuery, List<DanData>>
|
||||
{
|
||||
private readonly IGameDataService gameDataService;
|
||||
|
||||
public GetDanOdaiQueryHandler(IGameDataService gameDataService)
|
||||
{
|
||||
this.gameDataService = gameDataService;
|
||||
}
|
||||
|
||||
public Task<List<DanData>> Handle(GetDanOdaiQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var type = (DanType)request.Type;
|
||||
type.Throw().IfOutOfRange();
|
||||
var danDataList = new List<DanData>();
|
||||
switch (type)
|
||||
{
|
||||
case DanType.Normal:
|
||||
var danDataDictionary = gameDataService.GetCommonDanDataDictionary();
|
||||
|
||||
foreach (var danId in request.DanIds)
|
||||
{
|
||||
if (danDataDictionary.TryGetValue(danId, out var danData))
|
||||
{
|
||||
danDataList.Add(danData);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DanType.Gaiden:
|
||||
var gaidenDataDictionary = gameDataService.GetCommonGaidenDataDictionary();
|
||||
|
||||
foreach (var danId in request.DanIds)
|
||||
{
|
||||
if (gaidenDataDictionary.TryGetValue(danId, out var danData))
|
||||
{
|
||||
danDataList.Add(danData);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ApplicationException("Impossible");
|
||||
}
|
||||
|
||||
return Task.FromResult(danDataList);
|
||||
}
|
||||
}
|
73
TaikoLocalServer/Handlers/GetDanScoreQuery.cs
Normal file
73
TaikoLocalServer/Handlers/GetDanScoreQuery.cs
Normal file
@ -0,0 +1,73 @@
|
||||
using GameDatabase.Context;
|
||||
using GameDatabase.Entities;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetDanScoreQuery(uint Baid, uint Type, uint[] DanIds) : IRequest<CommonDanScoreDataResponse>;
|
||||
|
||||
public class GetDanScoreQueryHandler : IRequestHandler<GetDanScoreQuery, CommonDanScoreDataResponse>
|
||||
{
|
||||
private readonly ILogger<GetDanScoreQueryHandler> logger;
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
|
||||
public GetDanScoreQueryHandler(ILogger<GetDanScoreQueryHandler> logger, TaikoDbContext context)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public async Task<CommonDanScoreDataResponse> Handle(GetDanScoreQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var danType = (DanType)request.Type;
|
||||
danType.Throw().IfOutOfRange();
|
||||
|
||||
var idList = request.DanIds.ToList();
|
||||
// Select the dan score data from the database where baid and type matches and danid is in the list of danids
|
||||
var danScoreData = await context.DanScoreData
|
||||
.Where(d => d.Baid == request.Baid && d.DanType == danType &&idList.Contains(d.DanId))
|
||||
.Include(d => d.DanStageScoreData)
|
||||
.ToListAsync(cancellationToken);
|
||||
var response = new CommonDanScoreDataResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
foreach (var danScoreDatum in danScoreData)
|
||||
{
|
||||
var responseData = new CommonDanScoreDataResponse.DanScoreData
|
||||
{
|
||||
DanId = danScoreDatum.DanId,
|
||||
ArrivalSongCnt = danScoreDatum.ArrivalSongCount,
|
||||
ComboCntTotal = danScoreDatum.ComboCountTotal,
|
||||
SoulGaugeTotal = danScoreDatum.SoulGaugeTotal
|
||||
};
|
||||
for (int i = 0; i < danScoreDatum.ArrivalSongCount; i++)
|
||||
{
|
||||
var songNumber = i;
|
||||
var stageScoreDatum = danScoreDatum.DanStageScoreData.FirstOrDefault(d => d.SongNumber == songNumber);
|
||||
if (stageScoreDatum is null)
|
||||
{
|
||||
logger.LogWarning("Stage score data for dan {DanId} song number {SongNumber} not found", danScoreDatum.DanId, songNumber);
|
||||
stageScoreDatum = new DanStageScoreDatum();
|
||||
}
|
||||
responseData.AryDanScoreDataStages.Add(new CommonDanScoreDataResponse.DanScoreDataStage
|
||||
{
|
||||
PlayScore = stageScoreDatum.PlayScore,
|
||||
GoodCnt = stageScoreDatum.GoodCount,
|
||||
OkCnt = stageScoreDatum.OkCount,
|
||||
NgCnt = stageScoreDatum.BadCount,
|
||||
PoundCnt = stageScoreDatum.DrumrollCount,
|
||||
HitCnt = stageScoreDatum.TotalHitCount,
|
||||
ComboCnt = stageScoreDatum.ComboCount,
|
||||
HighScore = stageScoreDatum.HighScore
|
||||
});
|
||||
}
|
||||
response.AryDanScoreDatas.Add(responseData);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
|
29
TaikoLocalServer/Handlers/GetFolderQuery.cs
Normal file
29
TaikoLocalServer/Handlers/GetFolderQuery.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetFolderQuery(uint[] FolderIds) : IRequest<CommonGetFolderResponse>;
|
||||
|
||||
public class GetFolderQueryHandler(ILogger<GetFolderQueryHandler> logger, IGameDataService gameDataService)
|
||||
: IRequestHandler<GetFolderQuery, CommonGetFolderResponse>
|
||||
{
|
||||
public Task<CommonGetFolderResponse> Handle(GetFolderQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = new CommonGetFolderResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
var eventFolders = gameDataService.GetEventFolderDictionary();
|
||||
foreach (var folderId in request.FolderIds)
|
||||
{
|
||||
eventFolders.TryGetValue(folderId, out var folderData);
|
||||
if (folderData is null)
|
||||
{
|
||||
logger.LogWarning("Folder data for folder {FolderId} not found", folderId);
|
||||
continue;
|
||||
}
|
||||
response.AryEventfolderDatas.Add(folderData);
|
||||
}
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
}
|
102
TaikoLocalServer/Handlers/GetInitialDataQuery.cs
Normal file
102
TaikoLocalServer/Handlers/GetInitialDataQuery.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SharedProject.Models;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using TaikoLocalServer.Settings;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetInitialDataQuery : IRequest<CommonInitialDataCheckResponse>;
|
||||
|
||||
public class GetInitialDataQueryHandler(IGameDataService gameDataService,
|
||||
ILogger<GetInitialDataQueryHandler> logger,
|
||||
IOptions<ServerSettings> settings)
|
||||
: IRequestHandler<GetInitialDataQuery, CommonInitialDataCheckResponse>
|
||||
{
|
||||
|
||||
private readonly ServerSettings settings = settings.Value;
|
||||
|
||||
public Task<CommonInitialDataCheckResponse> Handle(GetInitialDataQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var songIdMax = settings.EnableMoreSongs ? Constants.MUSIC_ID_MAX_EXPANDED : Constants.MUSIC_ID_MAX;
|
||||
|
||||
var musicList = gameDataService.GetMusicList();
|
||||
var lockedSongsList = gameDataService.GetLockedSongsList();
|
||||
|
||||
var enabledArray =
|
||||
FlagCalculator.GetBitArrayFromIds(musicList, songIdMax, logger);
|
||||
|
||||
var defaultSongList = musicList.Except(lockedSongsList);
|
||||
var defaultSongFlg =
|
||||
FlagCalculator.GetBitArrayFromIds(defaultSongList, songIdMax, logger);
|
||||
|
||||
var defaultSongWithUraList = gameDataService.GetMusicWithUraList();
|
||||
var uraReleaseBit =
|
||||
FlagCalculator.GetBitArrayFromIds(defaultSongWithUraList, songIdMax, logger);
|
||||
|
||||
var response = new CommonInitialDataCheckResponse
|
||||
{
|
||||
Result = 1,
|
||||
DefaultSongFlg = defaultSongFlg,
|
||||
AchievementSongBit = enabledArray,
|
||||
UraReleaseBit = uraReleaseBit,
|
||||
SongIntroductionEndDatetime = DateTime.Now.AddYears(10).ToString(Constants.DATE_TIME_FORMAT),
|
||||
ServerCurrentDatetime = (ulong)DateTimeOffset.Now.ToUnixTimeSeconds()
|
||||
};
|
||||
|
||||
var movieDataDictionary = gameDataService.GetMovieDataDictionary();
|
||||
foreach (var movieData in movieDataDictionary)
|
||||
{
|
||||
response.AryMovieInfoes.Add(movieData.Value);
|
||||
}
|
||||
|
||||
// TODO: Figure out what they are individually
|
||||
var verupNo1 = new uint[] { 2, 3, 4, 5, 6, 7, 8, 13, 15, 24, 25, 26, 27, 28, 29, 30, 31, 104 };
|
||||
var aryVerUp = verupNo1.Select(i => new CommonInitialDataCheckResponse.VerupNoData1
|
||||
{
|
||||
MasterType = i,
|
||||
VerupNo = 1
|
||||
}).ToList();
|
||||
response.AryVerupNoData1s.AddRange(aryVerUp);
|
||||
|
||||
var commonDanDataDictionary = gameDataService.GetCommonDanDataDictionary();
|
||||
var commonGaidenDataDictionary = gameDataService.GetCommonGaidenDataDictionary();
|
||||
var eventFolderDictionary = gameDataService.GetEventFolderDictionary();
|
||||
var songIntroDictionary = gameDataService.GetSongIntroductionDictionary();
|
||||
|
||||
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)
|
||||
];
|
||||
response.AryVerupNoData2s.AddRange(verupNo2List);
|
||||
|
||||
response.AryChassisFunctionIds =
|
||||
[
|
||||
Constants.FUNCTION_ID_DANI_AVAILABLE,
|
||||
Constants.FUNCTION_ID_DANI_FOLDER_AVAILABLE,
|
||||
Constants.FUNCTION_ID_AI_BATTLE_AVAILABLE
|
||||
];
|
||||
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
|
||||
private CommonInitialDataCheckResponse.VerupNoData2 GetVerupNoData2<T>(uint masterType, ImmutableDictionary<uint, T> dictionary)
|
||||
where T:IVerupNo
|
||||
{
|
||||
var infoData = dictionary.Select(pair => new CommonInitialDataCheckResponse.VerupNoData2.InformationData
|
||||
{
|
||||
InfoId = pair.Key,
|
||||
VerupNo = pair.Value.VerupNo
|
||||
}).ToList();
|
||||
return new CommonInitialDataCheckResponse.VerupNoData2
|
||||
{
|
||||
MasterType = masterType,
|
||||
AryInformationDatas = infoData
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
52
TaikoLocalServer/Handlers/GetSelfBestQuery.cs
Normal file
52
TaikoLocalServer/Handlers/GetSelfBestQuery.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using GameDatabase.Context;
|
||||
using MudBlazor.Extensions;
|
||||
using SharedProject.Models;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetSelfBestQuery(uint Baid, uint Difficulty, uint[] SongIdList) : IRequest<CommonSelfBestResponse>;
|
||||
|
||||
public class GetSelfBestQueryHandler(IGameDataService gameDataService, TaikoDbContext context, ILogger<GetSelfBestQueryHandler> logger)
|
||||
: IRequestHandler<GetSelfBestQuery, CommonSelfBestResponse>
|
||||
{
|
||||
public async Task<CommonSelfBestResponse> Handle(GetSelfBestQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestDifficulty = (Difficulty)request.Difficulty;
|
||||
requestDifficulty.Throw().IfOutOfRange();
|
||||
|
||||
var allSongSet = gameDataService.GetMusicList().ToHashSet();
|
||||
var requestSet = request.SongIdList.ToHashSet();
|
||||
if (!requestSet.IsSubsetOf(allSongSet))
|
||||
{
|
||||
var invalidSongIds = requestSet.Except(allSongSet);
|
||||
logger.LogWarning("Invalid song IDs: {InvalidSongIds}", invalidSongIds.Stringify());
|
||||
requestSet.ExceptWith(invalidSongIds);
|
||||
}
|
||||
|
||||
var selfbestScores = await context.SongBestData
|
||||
.Where(datum => datum.Baid == request.Baid &&
|
||||
requestSet.Contains(datum.SongId) &&
|
||||
(datum.Difficulty == requestDifficulty ||
|
||||
(datum.Difficulty == Difficulty.UraOni && requestDifficulty == Difficulty.Oni)))
|
||||
.OrderBy(datum => datum.SongId)
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
var response = new CommonSelfBestResponse
|
||||
{
|
||||
Result = 1,
|
||||
Level = request.Difficulty,
|
||||
ArySelfbestScores = selfbestScores.ConvertAll(datum => new CommonSelfBestResponse.SelfBestData
|
||||
{
|
||||
SongNo = datum.SongId,
|
||||
SelfBestScore = datum.BestScore,
|
||||
UraBestScore = datum.Difficulty == Difficulty.UraOni ? datum.BestScore : 0,
|
||||
SelfBestScoreRate = datum.BestRate,
|
||||
UraBestScoreRate = datum.Difficulty == Difficulty.UraOni ? datum.BestRate : 0
|
||||
})
|
||||
};
|
||||
|
||||
return response;
|
||||
}
|
||||
}
|
26
TaikoLocalServer/Handlers/GetShopFolderQuery.cs
Normal file
26
TaikoLocalServer/Handlers/GetShopFolderQuery.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetShopFolderQuery : IRequest<CommonGetShopFolderResponse>;
|
||||
|
||||
public class GetShopFolderHandler(IGameDataService gameDataService)
|
||||
: IRequestHandler<GetShopFolderQuery, CommonGetShopFolderResponse>
|
||||
{
|
||||
public Task<CommonGetShopFolderResponse> Handle(GetShopFolderQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
gameDataService.GetTokenDataDictionary().TryGetValue("shopTokenId", out var shopTokenId);
|
||||
|
||||
var shopFolderList = gameDataService.GetShopFolderList();
|
||||
|
||||
var response = new CommonGetShopFolderResponse
|
||||
{
|
||||
Result = 1,
|
||||
TokenId = shopTokenId > 0 ? (uint)shopTokenId : 1,
|
||||
VerupNo = 2,
|
||||
AryShopFolderDatas = shopFolderList
|
||||
};
|
||||
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
}
|
32
TaikoLocalServer/Handlers/GetSongIntroductionQuery.cs
Normal file
32
TaikoLocalServer/Handlers/GetSongIntroductionQuery.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetSongIntroductionQuery(uint[] SetIds) : IRequest<CommonGetSongIntroductionResponse>;
|
||||
|
||||
public class GetSongIntroductionQueryHandler(IGameDataService gameDataService, ILogger<GetSongIntroductionQueryHandler> logger)
|
||||
: IRequestHandler<GetSongIntroductionQuery, CommonGetSongIntroductionResponse>
|
||||
{
|
||||
|
||||
public Task<CommonGetSongIntroductionResponse> Handle(GetSongIntroductionQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = new CommonGetSongIntroductionResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
foreach (var setId in request.SetIds)
|
||||
{
|
||||
gameDataService.GetSongIntroductionDictionary().TryGetValue(setId, out var introData);
|
||||
if (introData is null)
|
||||
{
|
||||
logger.LogWarning("Requested set id {Id} does not exist!", setId);
|
||||
continue;
|
||||
}
|
||||
|
||||
response.ArySongIntroductionDatas.Add(introData);
|
||||
}
|
||||
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
}
|
||||
|
50
TaikoLocalServer/Handlers/GetTokenCountQuery.cs
Normal file
50
TaikoLocalServer/Handlers/GetTokenCountQuery.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using GameDatabase.Context;
|
||||
using GameDatabase.Entities;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Handlers;
|
||||
|
||||
public record GetTokenCountQuery(uint Baid) : IRequest<CommonGetTokenCountResponse>;
|
||||
|
||||
public class GetTokenCountQueryHandler(IGameDataService gameDataService,
|
||||
TaikoDbContext context,
|
||||
ILogger<GetTokenCountQueryHandler> logger)
|
||||
: IRequestHandler<GetTokenCountQuery, CommonGetTokenCountResponse>
|
||||
{
|
||||
public async Task<CommonGetTokenCountResponse> Handle(GetTokenCountQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = new CommonGetTokenCountResponse
|
||||
{
|
||||
Result = 1
|
||||
};
|
||||
|
||||
string[] tokenNames = ["shopTokenId", "kaTokenId", "onePieceTokenId", "soshinaTokenId", "Yatsushika1TokenId", "Yatsushika2TokenId",
|
||||
"Yatsushika3TokenId", "Yatsushika4TokenId", "MaskedKid1TokenId", "MaskedKid2TokenId", "MaskedKid3TokenId", "MaskedKid4TokenId",
|
||||
"Kiyoshi1TokenId", "Kiyoshi2TokenId", "Kiyoshi3TokenId", "Kiyoshi4TokenId", "Amitie1TokenId", "Amitie2TokenId", "Amitie3TokenId",
|
||||
"Amitie4TokenId", "Machina1TokenId", "Machina2TokenId", "Machina3TokenId", "Machina4TokenId"];
|
||||
|
||||
var tokenDataDictionary = gameDataService.GetTokenDataDictionary();
|
||||
foreach (var tokenName in tokenNames)
|
||||
{
|
||||
tokenDataDictionary.TryGetValue(tokenName, out var tokenId);
|
||||
if (tokenId <= 0) continue;
|
||||
var token = await context.Tokens.FirstOrDefaultAsync(t => t.Baid == request.Baid &&
|
||||
t.Id == tokenId,
|
||||
cancellationToken) ?? new Token
|
||||
{
|
||||
Id = tokenId,
|
||||
Count = 0
|
||||
};
|
||||
|
||||
response.AryTokenCountDatas.Add(new CommonTokenCountData
|
||||
{
|
||||
TokenId = (uint)token.Id,
|
||||
TokenCount = token.Count
|
||||
});
|
||||
context.Tokens.Update(token);
|
||||
}
|
||||
|
||||
await context.SaveChangesAsync(cancellationToken);
|
||||
return response;
|
||||
}
|
||||
}
|
12
TaikoLocalServer/Mappers/AddTokenCountRequestMapper.cs
Normal file
12
TaikoLocalServer/Mappers/AddTokenCountRequestMapper.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class AddTokenCountRequestMapper
|
||||
{
|
||||
public static partial CommonAddTokenCountRequest Map(AddTokenCountRequest request);
|
||||
|
||||
public static partial CommonAddTokenCountRequest Map(Models.v3209.AddTokenCountRequest request);
|
||||
}
|
12
TaikoLocalServer/Mappers/AiDataResponseMapper.cs
Normal file
12
TaikoLocalServer/Mappers/AiDataResponseMapper.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class AiDataResponseMapper
|
||||
{
|
||||
public static partial GetAiDataResponse MapTo3906(CommonAiDataResponse response);
|
||||
|
||||
public static partial Models.v3209.GetAiDataResponse MapTo3209(CommonAiDataResponse response);
|
||||
}
|
16
TaikoLocalServer/Mappers/AiScoreMappers.cs
Normal file
16
TaikoLocalServer/Mappers/AiScoreMappers.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using GameDatabase.Entities;
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class AiScoreMappers
|
||||
{
|
||||
[MapProperty(nameof(AiScoreDatum.AiSectionScoreData), nameof(CommonAiScoreResponse.AryBestSectionDatas))]
|
||||
public static partial CommonAiScoreResponse MapToCommonAiScoreResponse(AiScoreDatum datum);
|
||||
|
||||
public static partial GetAiScoreResponse MapTo3906(CommonAiScoreResponse response);
|
||||
|
||||
public static partial Models.v3209.GetAiScoreResponse MapTo3209(CommonAiScoreResponse response);
|
||||
}
|
50
TaikoLocalServer/Mappers/BaidResponseMapper.cs
Normal file
50
TaikoLocalServer/Mappers/BaidResponseMapper.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class BaidResponseMapper
|
||||
{
|
||||
public static partial BAIDResponse MapTo3906(CommonBaidResponse commonBaidResponse);
|
||||
|
||||
public static BAIDResponse Map3906WithPostProcess(CommonBaidResponse commonBaidResponse)
|
||||
{
|
||||
var response = MapTo3906(commonBaidResponse);
|
||||
response.AryCostumedata = new BAIDResponse.CostumeData
|
||||
{
|
||||
Costume1 = commonBaidResponse.CostumeData[0],
|
||||
Costume2 = commonBaidResponse.CostumeData[1],
|
||||
Costume3 = commonBaidResponse.CostumeData[2],
|
||||
Costume4 = commonBaidResponse.CostumeData[3],
|
||||
Costume5 = commonBaidResponse.CostumeData[4]
|
||||
};
|
||||
response.CostumeFlg1 = commonBaidResponse.CostumeFlagArrays[0];
|
||||
response.CostumeFlg2 = commonBaidResponse.CostumeFlagArrays[1];
|
||||
response.CostumeFlg3 = commonBaidResponse.CostumeFlagArrays[2];
|
||||
response.CostumeFlg4 = commonBaidResponse.CostumeFlagArrays[3];
|
||||
response.CostumeFlg5 = commonBaidResponse.CostumeFlagArrays[4];
|
||||
return response;
|
||||
}
|
||||
|
||||
public static partial Models.v3209.BAIDResponse MapTo3209(CommonBaidResponse commonBaidResponse);
|
||||
|
||||
public static Models.v3209.BAIDResponse Map3209WithPostProcess(CommonBaidResponse commonBaidResponse)
|
||||
{
|
||||
var response = MapTo3209(commonBaidResponse);
|
||||
response.AryCostumedata = new Models.v3209.BAIDResponse.CostumeData
|
||||
{
|
||||
Costume1 = commonBaidResponse.CostumeData[0],
|
||||
Costume2 = commonBaidResponse.CostumeData[1],
|
||||
Costume3 = commonBaidResponse.CostumeData[2],
|
||||
Costume4 = commonBaidResponse.CostumeData[3],
|
||||
Costume5 = commonBaidResponse.CostumeData[4]
|
||||
};
|
||||
response.CostumeFlg1 = commonBaidResponse.CostumeFlagArrays[0];
|
||||
response.CostumeFlg2 = commonBaidResponse.CostumeFlagArrays[1];
|
||||
response.CostumeFlg3 = commonBaidResponse.CostumeFlagArrays[2];
|
||||
response.CostumeFlg4 = commonBaidResponse.CostumeFlagArrays[3];
|
||||
response.CostumeFlg5 = commonBaidResponse.CostumeFlagArrays[4];
|
||||
return response;
|
||||
}
|
||||
}
|
12
TaikoLocalServer/Mappers/DanDataMappers.cs
Normal file
12
TaikoLocalServer/Mappers/DanDataMappers.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using SharedProject.Models;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class DanDataMappers
|
||||
{
|
||||
public static partial GetDanOdaiResponse.OdaiData To3906OdaiData(DanData data);
|
||||
|
||||
public static partial Models.v3209.GetDanOdaiResponse.OdaiData To3209OdaiData(DanData data);
|
||||
}
|
11
TaikoLocalServer/Mappers/DanScoreMappers.cs
Normal file
11
TaikoLocalServer/Mappers/DanScoreMappers.cs
Normal file
@ -0,0 +1,11 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class DanScoreMappers
|
||||
{
|
||||
public static partial GetDanScoreResponse MapTo3906(CommonDanScoreDataResponse response);
|
||||
public static partial Models.v3209.GetDanScoreResponse MapTo3209(CommonDanScoreDataResponse response);
|
||||
}
|
12
TaikoLocalServer/Mappers/FolderDataMappers.cs
Normal file
12
TaikoLocalServer/Mappers/FolderDataMappers.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class FolderDataMappers
|
||||
{
|
||||
public static partial GetfolderResponse MapTo3906(CommonGetFolderResponse response);
|
||||
|
||||
public static partial Models.v3209.GetfolderResponse MapTo3209(CommonGetFolderResponse response);
|
||||
}
|
12
TaikoLocalServer/Mappers/InitialDataMappers.cs
Normal file
12
TaikoLocalServer/Mappers/InitialDataMappers.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class InitialDataMappers
|
||||
{
|
||||
public static partial InitialdatacheckResponse MapTo3906(CommonInitialDataCheckResponse response);
|
||||
|
||||
public static partial Models.v3209.InitialdatacheckResponse MapTo3209(CommonInitialDataCheckResponse response);
|
||||
}
|
12
TaikoLocalServer/Mappers/MyDonEntryMappers.cs
Normal file
12
TaikoLocalServer/Mappers/MyDonEntryMappers.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class MyDonEntryMappers
|
||||
{
|
||||
public static partial MydonEntryResponse MapTo3906(CommonMyDonEntryResponse response);
|
||||
|
||||
public static partial Models.v3209.MydonEntryResponse MapTo3209(CommonMyDonEntryResponse response);
|
||||
}
|
12
TaikoLocalServer/Mappers/SelfBestMappers.cs
Normal file
12
TaikoLocalServer/Mappers/SelfBestMappers.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class SelfBestMappers
|
||||
{
|
||||
public static partial SelfBestResponse MapTo3906(CommonSelfBestResponse response);
|
||||
|
||||
public static partial Models.v3209.SelfBestResponse MapTo3209(CommonSelfBestResponse response);
|
||||
}
|
12
TaikoLocalServer/Mappers/ShopFolderDataMappers.cs
Normal file
12
TaikoLocalServer/Mappers/ShopFolderDataMappers.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class ShopFolderDataMappers
|
||||
{
|
||||
public static partial GetShopFolderResponse MapTo3906(CommonGetShopFolderResponse response);
|
||||
|
||||
public static partial Models.v3209.GetShopFolderResponse MapTo3209(CommonGetShopFolderResponse response);
|
||||
}
|
13
TaikoLocalServer/Mappers/SongIntroductionDataMappers.cs
Normal file
13
TaikoLocalServer/Mappers/SongIntroductionDataMappers.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class SongIntroductionDataMappers
|
||||
{
|
||||
public static partial GetSongIntroductionResponse MapTo3906(CommonGetSongIntroductionResponse response);
|
||||
|
||||
public static partial Models.v3209.GetSongIntroductionResponse
|
||||
MapTo3209(CommonGetSongIntroductionResponse response);
|
||||
}
|
12
TaikoLocalServer/Mappers/TokenCountDataMappers.cs
Normal file
12
TaikoLocalServer/Mappers/TokenCountDataMappers.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using Riok.Mapperly.Abstractions;
|
||||
using TaikoLocalServer.Models.Application;
|
||||
|
||||
namespace TaikoLocalServer.Mappers;
|
||||
|
||||
[Mapper]
|
||||
public static partial class TokenCountDataMappers
|
||||
{
|
||||
public static partial GetTokenCountResponse MapTo3906(CommonGetTokenCountResponse response);
|
||||
|
||||
public static partial Models.v3209.GetTokenCountResponse MapTo3209(CommonGetTokenCountResponse response);
|
||||
}
|
3225
TaikoLocalServer/Models/3209/Game.cs
Normal file
3225
TaikoLocalServer/Models/3209/Game.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -6,7 +6,7 @@
|
||||
|
||||
#region Designer generated code
|
||||
#pragma warning disable CS0612, CS0618, CS1591, CS3021, IDE0079, IDE1006, RCS1036, RCS1057, RCS1085, RCS1192
|
||||
namespace taiko.game
|
||||
namespace TaikoLocalServer.Models.v3906
|
||||
{
|
||||
[global::ProtoBuf.ProtoContract()]
|
||||
public partial class HeartBeatRequest : global::ProtoBuf.IExtensible
|
||||
@ -657,10 +657,10 @@ namespace taiko.game
|
||||
public string Title { get; set; }
|
||||
|
||||
[global::ProtoBuf.ProtoMember(4, Name = @"ary_odai_song")]
|
||||
public global::System.Collections.Generic.List<OdaiSong> AryOdaiSongs { get; } = new global::System.Collections.Generic.List<OdaiSong>();
|
||||
public global::System.Collections.Generic.List<OdaiSong> OdaiSongList { get; } = new global::System.Collections.Generic.List<OdaiSong>();
|
||||
|
||||
[global::ProtoBuf.ProtoMember(5, Name = @"ary_odai_border")]
|
||||
public global::System.Collections.Generic.List<OdaiBorder> AryOdaiBorders { get; } = new global::System.Collections.Generic.List<OdaiBorder>();
|
||||
public global::System.Collections.Generic.List<OdaiBorder> OdaiBorderList { get; } = new global::System.Collections.Generic.List<OdaiBorder>();
|
||||
|
||||
[global::ProtoBuf.ProtoContract()]
|
||||
public partial class OdaiSong : global::ProtoBuf.IExtensible
|
||||
@ -1260,7 +1260,7 @@ namespace taiko.game
|
||||
|
||||
[global::ProtoBuf.ProtoMember(12, Name = @"mydon_name")]
|
||||
[global::System.ComponentModel.DefaultValue("")]
|
||||
public string MydonName
|
||||
public string MyDonName
|
||||
{
|
||||
get => __pbn__MydonName ?? "";
|
||||
set => __pbn__MydonName = value;
|
||||
@ -1270,7 +1270,7 @@ namespace taiko.game
|
||||
private string __pbn__MydonName;
|
||||
|
||||
[global::ProtoBuf.ProtoMember(13, Name = @"mydon_name_language")]
|
||||
public uint MydonNameLanguage
|
||||
public uint MyDonNameLanguage
|
||||
{
|
||||
get => __pbn__MydonNameLanguage.GetValueOrDefault();
|
||||
set => __pbn__MydonNameLanguage = value;
|
||||
@ -1291,7 +1291,7 @@ namespace taiko.game
|
||||
private string __pbn__Title;
|
||||
|
||||
[global::ProtoBuf.ProtoMember(15, Name = @"titleplate_id")]
|
||||
public uint TitleplateId
|
||||
public uint TitlePlateId
|
||||
{
|
||||
get => __pbn__TitleplateId.GetValueOrDefault();
|
||||
set => __pbn__TitleplateId = value;
|
||||
@ -1395,7 +1395,7 @@ namespace taiko.game
|
||||
private string __pbn__LastPlayDatetime;
|
||||
|
||||
[global::ProtoBuf.ProtoMember(26, Name = @"is_disp_dan_on")]
|
||||
public bool IsDispDanOn
|
||||
public bool DisplayDan
|
||||
{
|
||||
get => __pbn__IsDispDanOn.GetValueOrDefault();
|
||||
set => __pbn__IsDispDanOn = value;
|
||||
@ -1425,17 +1425,17 @@ namespace taiko.game
|
||||
private byte[] __pbn__GotDanFlg;
|
||||
|
||||
[global::ProtoBuf.ProtoMember(29, Name = @"got_danextra_flg")]
|
||||
public byte[] GotDanextraFlg
|
||||
public byte[] GotGaidenFlg
|
||||
{
|
||||
get => __pbn__GotDanextraFlg;
|
||||
set => __pbn__GotDanextraFlg = value;
|
||||
get => pbnGotGaidenFlg;
|
||||
set => pbnGotGaidenFlg = value;
|
||||
}
|
||||
public bool ShouldSerializeGotDanextraFlg() => __pbn__GotDanextraFlg != null;
|
||||
public void ResetGotDanextraFlg() => __pbn__GotDanextraFlg = null;
|
||||
private byte[] __pbn__GotDanextraFlg;
|
||||
public bool ShouldSerializeGotDanextraFlg() => pbnGotGaidenFlg != null;
|
||||
public void ResetGotDanextraFlg() => pbnGotGaidenFlg = null;
|
||||
private byte[] pbnGotGaidenFlg;
|
||||
|
||||
[global::ProtoBuf.ProtoMember(30, Name = @"default_tone_setting")]
|
||||
public uint DefaultToneSetting
|
||||
public uint SelectedToneId
|
||||
{
|
||||
get => __pbn__DefaultToneSetting.GetValueOrDefault();
|
||||
set => __pbn__DefaultToneSetting = value;
|
||||
@ -2867,7 +2867,7 @@ namespace taiko.game
|
||||
=> global::ProtoBuf.Extensible.GetExtensionObject(ref __pbn__extensionData, createIfMissing);
|
||||
|
||||
[global::ProtoBuf.ProtoMember(1, Name = @"section_no", IsRequired = true)]
|
||||
public uint SectionNo { get; set; }
|
||||
public uint SectionIndex { get; set; }
|
||||
|
||||
[global::ProtoBuf.ProtoMember(2, Name = @"crown")]
|
||||
public uint Crown
|
||||
@ -2890,16 +2890,16 @@ namespace taiko.game
|
||||
private uint? __pbn__Score;
|
||||
|
||||
[global::ProtoBuf.ProtoMember(4, Name = @"good_cnt", IsRequired = true)]
|
||||
public uint GoodCnt { get; set; }
|
||||
public uint GoodCount { get; set; }
|
||||
|
||||
[global::ProtoBuf.ProtoMember(5, Name = @"ok_cnt", IsRequired = true)]
|
||||
public uint OkCnt { get; set; }
|
||||
public uint OkCount { get; set; }
|
||||
|
||||
[global::ProtoBuf.ProtoMember(6, Name = @"ng_cnt", IsRequired = true)]
|
||||
public uint NgCnt { get; set; }
|
||||
public uint MissCount { get; set; }
|
||||
|
||||
[global::ProtoBuf.ProtoMember(7, Name = @"pound_cnt", IsRequired = true)]
|
||||
public uint PoundCnt { get; set; }
|
||||
public uint DrumrollCount { get; set; }
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonAddTokenCountRequest
|
||||
{
|
||||
public uint Baid { get; set; }
|
||||
public List<AddTokenCountData> AryAddTokenCountDatas { get; set; } = new();
|
||||
}
|
||||
|
||||
public class AddTokenCountData
|
||||
{
|
||||
public uint TokenId { get; set; }
|
||||
public int AddTokenCount { get; set; }
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonAiDataResponse
|
||||
{
|
||||
public uint TotalWinnings { get; set; }
|
||||
public string InputMedian { get; set; } = "1";
|
||||
public string InputVariance { get; set; } = "0";
|
||||
}
|
17
TaikoLocalServer/Models/Application/CommonAiScoreResponse.cs
Normal file
17
TaikoLocalServer/Models/Application/CommonAiScoreResponse.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonAiScoreResponse
|
||||
{
|
||||
public List<CommonAiBestSectionData> AryBestSectionDatas { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CommonAiBestSectionData
|
||||
{
|
||||
public uint SectionIndex { get; set; }
|
||||
public uint Crown { get; set; }
|
||||
public uint Score { get; set; }
|
||||
public uint GoodCount { get; set; }
|
||||
public uint OkCount { get; set; }
|
||||
public uint MissCount { get; set; }
|
||||
public uint DrumrollCount { get; set; }
|
||||
}
|
32
TaikoLocalServer/Models/Application/CommonBaidResponse.cs
Normal file
32
TaikoLocalServer/Models/Application/CommonBaidResponse.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using GameDatabase.Entities;
|
||||
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonBaidResponse
|
||||
{
|
||||
public bool IsNewUser { get; set; }
|
||||
public uint Baid { get; set; }
|
||||
public string MyDonName { get; set; } = string.Empty;
|
||||
public uint MyDonNameLanguage { get; set; }
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public uint TitlePlateId { get; set; }
|
||||
public uint ColorFace { get; set; }
|
||||
public uint ColorBody { get; set; }
|
||||
public uint ColorLimb { get; set; }
|
||||
public List<uint> CostumeData { get; set; } = new() { 0, 0, 0, 0, 0 };
|
||||
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 bool DisplayDan { get; set; }
|
||||
public uint GotDanMax { get; set; }
|
||||
public byte[] GotDanFlg { get; set; } = Array.Empty<byte>();
|
||||
public byte[] GotGaidenFlg { get; set; } = Array.Empty<byte>();
|
||||
public uint SelectedToneId { get; set; }
|
||||
public byte[] GenericInfoFlg { get; set; } = Array.Empty<byte>();
|
||||
public uint[] AryCrownCounts { get; set; } = Array.Empty<uint>();
|
||||
public uint[] AryScoreRankCounts { get; set; } = Array.Empty<uint>();
|
||||
public bool IsDispAchievementOn { get; set; }
|
||||
public uint DispAchievementType { get; set; }
|
||||
public uint LastPlayMode { get; set; }
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonDanScoreDataResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
public List<DanScoreData> AryDanScoreDatas { get; set; } = [];
|
||||
|
||||
public class DanScoreData
|
||||
{
|
||||
public uint DanId { get; set; }
|
||||
public uint ArrivalSongCnt { get; set; }
|
||||
public uint SoulGaugeTotal { get; set; }
|
||||
public uint ComboCntTotal { get; set; }
|
||||
public List<DanScoreDataStage> AryDanScoreDataStages { get; set; } = [];
|
||||
}
|
||||
|
||||
public class DanScoreDataStage
|
||||
{
|
||||
public uint PlayScore { get; set; }
|
||||
public uint GoodCnt { get; set; }
|
||||
public uint OkCnt { get; set; }
|
||||
public uint NgCnt { get; set; }
|
||||
public uint PoundCnt { get; set; }
|
||||
public uint HitCnt { get; set; }
|
||||
public uint ComboCnt { get; set; }
|
||||
public uint HighScore { get; set; }
|
||||
}
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using SharedProject.Models;
|
||||
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonGetFolderResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
|
||||
public List<EventFolderData> AryEventfolderDatas { get; set; } = [];
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
using SharedProject.Models;
|
||||
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonGetShopFolderResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
public uint VerupNo { get; set; }
|
||||
public uint TokenId { get; set; }
|
||||
public List<ShopFolderData> AryShopFolderDatas { get; set; } = [];
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
using SharedProject.Models;
|
||||
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonGetSongIntroductionResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
|
||||
public List<SongIntroductionData> ArySongIntroductionDatas { get; set; } = [];
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonGetTokenCountResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
|
||||
public List<CommonTokenCountData> AryTokenCountDatas { get; set; } = [];
|
||||
}
|
||||
|
||||
public class CommonTokenCountData
|
||||
{
|
||||
public uint TokenId { get; set; }
|
||||
public int TokenCount { get; set; }
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
using SharedProject.Models;
|
||||
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonInitialDataCheckResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
public byte[] DefaultSongFlg { get; set; } = [];
|
||||
public byte[] AchievementSongBit { get; set; } = [];
|
||||
public byte[] UraReleaseBit { get; set; } = [];
|
||||
|
||||
public string SongIntroductionEndDatetime { get; set; } =
|
||||
DateTime.Now.AddYears(10).ToString(Constants.DATE_TIME_FORMAT);
|
||||
|
||||
public List<MovieData> AryMovieInfoes { get; set; } = [];
|
||||
public List<AiEventData> AryAiEventDatas { get; set; } = [];
|
||||
public List<VerupNoData1> AryVerupNoData1s { get; set; } = [];
|
||||
public List<VerupNoData2> AryVerupNoData2s { get; set; } = [];
|
||||
public uint[] AryChassisFunctionIds { get; set; } = [1, 2, 3];
|
||||
|
||||
public ulong ServerCurrentDatetime { get; set; } = (ulong)DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||
|
||||
public class AiEventData
|
||||
{
|
||||
public uint AiEventId { get; set; }
|
||||
public uint TokenId { get; set; }
|
||||
}
|
||||
|
||||
public class VerupNoData1
|
||||
{
|
||||
public uint MasterType { get; set; }
|
||||
public uint VerupNo { get; set; }
|
||||
}
|
||||
|
||||
public class VerupNoData2
|
||||
{
|
||||
public uint MasterType { get; set; }
|
||||
public List<InformationData> AryInformationDatas { get; set; } = [];
|
||||
|
||||
public class InformationData
|
||||
{
|
||||
public uint InfoId { get; set; }
|
||||
public uint VerupNo { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonMyDonEntryResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
public uint Baid { get; set; }
|
||||
public string MydonName { get; set; } = string.Empty;
|
||||
public uint MydonNameLanguage { get; set; }
|
||||
public string AccessCode { get; set; } = string.Empty;
|
||||
public uint ComSvrResult { get; set; }
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
namespace TaikoLocalServer.Models.Application;
|
||||
|
||||
public class CommonSelfBestResponse
|
||||
{
|
||||
public uint Result { get; set; }
|
||||
|
||||
public uint Level { get; set; }
|
||||
|
||||
public List<SelfBestData> ArySelfbestScores { get; set; } = [];
|
||||
|
||||
public class SelfBestData
|
||||
{
|
||||
public uint SongNo { get; set; }
|
||||
public uint SelfBestScore { get; set; }
|
||||
public uint UraBestScore { get; set; }
|
||||
public uint SelfBestScoreRate { get; set; }
|
||||
public uint UraBestScoreRate { get; set; }
|
||||
}
|
||||
}
|
@ -60,6 +60,7 @@ try
|
||||
}
|
||||
|
||||
// Add services to the container.
|
||||
builder.Services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(typeof(Program).Assembly));
|
||||
builder.Services.AddOptions();
|
||||
builder.Services.AddSingleton<IGameDataService, GameDataService>();
|
||||
builder.Services.Configure<ServerSettings>(builder.Configuration.GetSection(nameof(ServerSettings)));
|
||||
|
@ -18,11 +18,6 @@ public class CardService : ICardService
|
||||
return await context.Cards.FindAsync(accessCode);
|
||||
}
|
||||
|
||||
public uint GetNextBaid()
|
||||
{
|
||||
return context.Cards.Any() ? context.Cards.ToList().Max(card => card.Baid) + 1 : 1;
|
||||
}
|
||||
|
||||
public async Task<List<User>> GetUsersFromCards()
|
||||
{
|
||||
var cardEntries = await context.Cards.ToListAsync();
|
||||
|
@ -1,5 +1,4 @@
|
||||
using ICSharpCode.SharpZipLib.GZip;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SharedProject.Models;
|
||||
using SharedProject.Utils;
|
||||
using Swan.Mapping;
|
||||
@ -14,461 +13,377 @@ namespace TaikoLocalServer.Services;
|
||||
|
||||
public class GameDataService : IGameDataService
|
||||
{
|
||||
private ImmutableDictionary<uint, MusicInfoEntry> musicInfoes =
|
||||
ImmutableDictionary<uint, MusicInfoEntry>.Empty;
|
||||
private ImmutableDictionary<uint, DanData> commonDanDataDictionary =
|
||||
ImmutableDictionary<uint, DanData>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> danDataDictionary =
|
||||
ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData>.Empty;
|
||||
private ImmutableDictionary<uint, DanData> commonGaidenDataDictionary =
|
||||
ImmutableDictionary<uint, DanData>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> gaidenDataDictionary =
|
||||
ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData>.Empty;
|
||||
private ImmutableDictionary<uint, MusicInfoEntry> musicInfoes =
|
||||
ImmutableDictionary<uint, MusicInfoEntry>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, MovieData> movieDataDictionary =
|
||||
ImmutableDictionary<uint, MovieData>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> introDataDictionary =
|
||||
ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData>.Empty;
|
||||
private ImmutableDictionary<uint, SongIntroductionData> songIntroductionDictionary =
|
||||
ImmutableDictionary<uint, SongIntroductionData>.Empty;
|
||||
|
||||
private ImmutableDictionary<string, uint> qrCodeDataDictionary = ImmutableDictionary<string, uint>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, EventFolderData> eventFolderDictionary =
|
||||
ImmutableDictionary<uint, EventFolderData>.Empty;
|
||||
|
||||
private ImmutableDictionary<uint, InitialdatacheckResponse.MovieData> movieDataDictionary =
|
||||
ImmutableDictionary<uint, InitialdatacheckResponse.MovieData>.Empty;
|
||||
private List<ShopFolderData> shopFolderList = new();
|
||||
|
||||
private ImmutableDictionary<uint, GetfolderResponse.EventfolderData> folderDictionary =
|
||||
ImmutableDictionary<uint, GetfolderResponse.EventfolderData>.Empty;
|
||||
private List<uint> musics = new();
|
||||
|
||||
private ImmutableDictionary<string, uint> qrCodeDataDictionary = ImmutableDictionary<string, uint>.Empty;
|
||||
|
||||
private List<GetShopFolderResponse.ShopFolderData> shopFolderList = new();
|
||||
private List<uint> musicsWithUra = new();
|
||||
|
||||
private List<uint> musics = new();
|
||||
private List<uint> lockedSongsList = new();
|
||||
|
||||
private List<uint> musicsWithUra = new();
|
||||
private List<int> costumeFlagArraySizes = new();
|
||||
|
||||
private List<uint> lockedSongsList = new();
|
||||
|
||||
private List<int> costumeFlagArraySizes = new();
|
||||
|
||||
private int titleFlagArraySize;
|
||||
|
||||
private int toneFlagArraySize;
|
||||
private int titleFlagArraySize;
|
||||
|
||||
private Dictionary<string, int> tokenDataDictionary = new();
|
||||
private int toneFlagArraySize;
|
||||
|
||||
private readonly DataSettings settings;
|
||||
private Dictionary<string, int> tokenDataDictionary = new();
|
||||
|
||||
public GameDataService(IOptions<DataSettings> settings)
|
||||
{
|
||||
this.settings = settings.Value;
|
||||
}
|
||||
private readonly DataSettings settings;
|
||||
|
||||
public List<uint> GetMusicList()
|
||||
{
|
||||
return musics;
|
||||
}
|
||||
public GameDataService(IOptions<DataSettings> settings)
|
||||
{
|
||||
this.settings = settings.Value;
|
||||
}
|
||||
|
||||
public List<uint> GetMusicWithUraList()
|
||||
{
|
||||
return musicsWithUra;
|
||||
}
|
||||
public List<uint> GetMusicList()
|
||||
{
|
||||
return musics;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, MusicInfoEntry> GetMusicInfoes()
|
||||
{
|
||||
return musicInfoes;
|
||||
}
|
||||
public List<uint> GetMusicWithUraList()
|
||||
{
|
||||
return musicsWithUra;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary()
|
||||
{
|
||||
return danDataDictionary;
|
||||
}
|
||||
public ImmutableDictionary<uint, MusicInfoEntry> GetMusicInfoes()
|
||||
{
|
||||
return musicInfoes;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetGaidenDataDictionary()
|
||||
{
|
||||
return gaidenDataDictionary;
|
||||
}
|
||||
public ImmutableDictionary<uint, MovieData> GetMovieDataDictionary()
|
||||
{
|
||||
return movieDataDictionary;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary()
|
||||
{
|
||||
return introDataDictionary;
|
||||
}
|
||||
public ImmutableDictionary<uint, EventFolderData> GetEventFolderDictionary()
|
||||
{
|
||||
return eventFolderDictionary;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, InitialdatacheckResponse.MovieData> GetMovieDataDictionary()
|
||||
{
|
||||
return movieDataDictionary;
|
||||
}
|
||||
public ImmutableDictionary<uint, DanData> GetCommonDanDataDictionary()
|
||||
{
|
||||
return commonDanDataDictionary;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, GetfolderResponse.EventfolderData> GetFolderDictionary()
|
||||
{
|
||||
return folderDictionary;
|
||||
}
|
||||
public ImmutableDictionary<uint, DanData> GetCommonGaidenDataDictionary()
|
||||
{
|
||||
return commonGaidenDataDictionary;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<uint, SongIntroductionData> GetSongIntroductionDictionary()
|
||||
{
|
||||
return songIntroductionDictionary;
|
||||
}
|
||||
|
||||
public List<GetShopFolderResponse.ShopFolderData> GetShopFolderList()
|
||||
{
|
||||
return shopFolderList;
|
||||
}
|
||||
public List<ShopFolderData> GetShopFolderList()
|
||||
{
|
||||
return shopFolderList;
|
||||
}
|
||||
|
||||
public Dictionary<string, int> GetTokenDataDictionary()
|
||||
{
|
||||
return tokenDataDictionary;
|
||||
}
|
||||
public Dictionary<string, int> GetTokenDataDictionary()
|
||||
{
|
||||
return tokenDataDictionary;
|
||||
}
|
||||
|
||||
public List<uint> GetLockedSongsList()
|
||||
{
|
||||
return lockedSongsList;
|
||||
}
|
||||
|
||||
public List<int> GetCostumeFlagArraySizes()
|
||||
{
|
||||
return costumeFlagArraySizes;
|
||||
}
|
||||
|
||||
public int GetTitleFlagArraySize()
|
||||
{
|
||||
return titleFlagArraySize;
|
||||
}
|
||||
|
||||
public int GetToneFlagArraySize()
|
||||
{
|
||||
return toneFlagArraySize;
|
||||
}
|
||||
public List<uint> GetLockedSongsList()
|
||||
{
|
||||
return lockedSongsList;
|
||||
}
|
||||
|
||||
public ImmutableDictionary<string, uint> GetQRCodeDataDictionary()
|
||||
{
|
||||
return qrCodeDataDictionary;
|
||||
}
|
||||
public List<int> GetCostumeFlagArraySizes()
|
||||
{
|
||||
return costumeFlagArraySizes;
|
||||
}
|
||||
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var dataPath = PathHelper.GetDataPath();
|
||||
var datatablePath = PathHelper.GetDatatablePath();
|
||||
public int GetTitleFlagArraySize()
|
||||
{
|
||||
return titleFlagArraySize;
|
||||
}
|
||||
|
||||
var musicInfoPath = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.json");
|
||||
var encryptedInfo = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.bin");
|
||||
|
||||
var wordlistPath = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.json");
|
||||
var encryptedWordlist = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.bin");
|
||||
|
||||
var musicOrderPath = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.json");
|
||||
var encryptedMusicOrder = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.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 shougouPath = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.json");
|
||||
var encryptedShougou = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.bin");
|
||||
|
||||
var neiroPath = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.json");
|
||||
var encryptedNeiro = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.bin");
|
||||
|
||||
var danDataPath = Path.Combine(dataPath, settings.DanDataFileName);
|
||||
var gaidenDataPath = Path.Combine(dataPath, settings.GaidenDataFileName);
|
||||
var songIntroDataPath = Path.Combine(dataPath, settings.IntroDataFileName);
|
||||
var movieDataPath = Path.Combine(dataPath, settings.MovieDataFileName);
|
||||
var eventFolderDataPath = Path.Combine(dataPath, settings.EventFolderDataFileName);
|
||||
var shopFolderDataPath = Path.Combine(dataPath, settings.ShopFolderDataFileName);
|
||||
var tokenDataPath = Path.Combine(dataPath, settings.TokenDataFileName);
|
||||
var lockedSongsDataPath = Path.Combine(dataPath, settings.LockedSongsDataFileName);
|
||||
var qrCodeDataPath = Path.Combine(dataPath, settings.QRCodeDataFileName);
|
||||
public int GetToneFlagArraySize()
|
||||
{
|
||||
return toneFlagArraySize;
|
||||
}
|
||||
|
||||
if (File.Exists(encryptedInfo))
|
||||
{
|
||||
DecryptDataTable(encryptedInfo, musicInfoPath);
|
||||
}
|
||||
if (File.Exists(encryptedWordlist))
|
||||
{
|
||||
DecryptDataTable(encryptedWordlist, wordlistPath);
|
||||
}
|
||||
if (File.Exists(encryptedMusicOrder))
|
||||
{
|
||||
DecryptDataTable(encryptedMusicOrder, musicOrderPath);
|
||||
}
|
||||
if (File.Exists(encryptedDonCosReward))
|
||||
{
|
||||
DecryptDataTable(encryptedDonCosReward, donCosRewardPath);
|
||||
}
|
||||
if (File.Exists(encryptedShougou))
|
||||
{
|
||||
DecryptDataTable(encryptedShougou, shougouPath);
|
||||
}
|
||||
if (File.Exists(encryptedNeiro))
|
||||
{
|
||||
DecryptDataTable(encryptedNeiro, neiroPath);
|
||||
}
|
||||
|
||||
if (!File.Exists(musicInfoPath))
|
||||
{
|
||||
throw new FileNotFoundException("Music info file not found!");
|
||||
}
|
||||
if (!File.Exists(wordlistPath))
|
||||
{
|
||||
throw new FileNotFoundException("Wordlist file not found!");
|
||||
}
|
||||
if (!File.Exists(musicOrderPath))
|
||||
{
|
||||
throw new FileNotFoundException("Music order file not found!");
|
||||
}
|
||||
if (!File.Exists(donCosRewardPath))
|
||||
{
|
||||
throw new FileNotFoundException("Don cos reward file not found!");
|
||||
}
|
||||
if (!File.Exists(shougouPath))
|
||||
{
|
||||
throw new FileNotFoundException("Shougou file not found!");
|
||||
}
|
||||
if (!File.Exists(neiroPath))
|
||||
{
|
||||
throw new FileNotFoundException("Neiro file not found!");
|
||||
}
|
||||
|
||||
await using var musicInfoFile = File.OpenRead(musicInfoPath);
|
||||
await using var danDataFile = File.OpenRead(danDataPath);
|
||||
await using var gaidenDataFile = File.OpenRead(gaidenDataPath);
|
||||
await using var songIntroDataFile = File.OpenRead(songIntroDataPath);
|
||||
await using var movieDataFile = File.OpenRead(movieDataPath);
|
||||
await using var eventFolderDataFile = File.OpenRead(eventFolderDataPath);
|
||||
await using var shopFolderDataFile = File.OpenRead(shopFolderDataPath);
|
||||
await using var tokenDataFile = File.OpenRead(tokenDataPath);
|
||||
await using var lockedSongsDataFile = File.OpenRead(lockedSongsDataPath);
|
||||
await using var donCosRewardFile = File.OpenRead(donCosRewardPath);
|
||||
await using var shougouFile = File.OpenRead(shougouPath);
|
||||
await using var neiroFile = File.OpenRead(neiroPath);
|
||||
await using var qrCodeDataFile = File.OpenRead(qrCodeDataPath);
|
||||
public ImmutableDictionary<string, uint> GetQRCodeDataDictionary()
|
||||
{
|
||||
return qrCodeDataDictionary;
|
||||
}
|
||||
|
||||
var infoesData = await JsonSerializer.DeserializeAsync<MusicInfoes>(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);
|
||||
var movieData = await JsonSerializer.DeserializeAsync<List<MovieData>>(movieDataFile);
|
||||
var eventFolderData = await JsonSerializer.DeserializeAsync<List<EventFolderData>>(eventFolderDataFile);
|
||||
var shopFolderData = await JsonSerializer.DeserializeAsync<List<ShopFolderData>>(shopFolderDataFile);
|
||||
var tokenData = await JsonSerializer.DeserializeAsync<Dictionary<string, int>>(tokenDataFile);
|
||||
var lockedSongsData = await JsonSerializer.DeserializeAsync<Dictionary<string, uint[]>>(lockedSongsDataFile);
|
||||
var donCosRewardData = await JsonSerializer.DeserializeAsync<DonCosRewards>(donCosRewardFile);
|
||||
var shougouData = await JsonSerializer.DeserializeAsync<Shougous>(shougouFile);
|
||||
var neiroData = await JsonSerializer.DeserializeAsync<Neiros>(neiroFile);
|
||||
var qrCodeData = await JsonSerializer.DeserializeAsync<List<QRCodeData>>(qrCodeDataFile);
|
||||
public async Task InitializeAsync()
|
||||
{
|
||||
var dataPath = PathHelper.GetDataPath();
|
||||
var datatablePath = PathHelper.GetDatatablePath();
|
||||
|
||||
InitializeMusicInfoes(infoesData);
|
||||
var musicInfoPath = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.json");
|
||||
var encryptedInfo = Path.Combine(datatablePath, $"{Constants.MUSIC_INFO_BASE_NAME}.bin");
|
||||
|
||||
InitializeDanData(danData);
|
||||
var wordlistPath = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.json");
|
||||
var encryptedWordlist = Path.Combine(datatablePath, $"{Constants.WORDLIST_BASE_NAME}.bin");
|
||||
|
||||
InitializeGaidenData(gaidenData);
|
||||
var musicOrderPath = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.json");
|
||||
var encryptedMusicOrder = Path.Combine(datatablePath, $"{Constants.MUSIC_ORDER_BASE_NAME}.bin");
|
||||
|
||||
InitializeIntroData(introData);
|
||||
var donCosRewardPath = Path.Combine(datatablePath, $"{Constants.DON_COS_REWARD_BASE_NAME}.json");
|
||||
var encryptedDonCosReward = Path.Combine(datatablePath, $"{Constants.DON_COS_REWARD_BASE_NAME}.bin");
|
||||
|
||||
InitializeMovieData(movieData);
|
||||
var shougouPath = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.json");
|
||||
var encryptedShougou = Path.Combine(datatablePath, $"{Constants.SHOUGOU_BASE_NAME}.bin");
|
||||
|
||||
InitializeEventFolderData(eventFolderData);
|
||||
var neiroPath = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.json");
|
||||
var encryptedNeiro = Path.Combine(datatablePath, $"{Constants.NEIRO_BASE_NAME}.bin");
|
||||
|
||||
InitializeShopFolderData(shopFolderData);
|
||||
var danDataPath = Path.Combine(dataPath, settings.DanDataFileName);
|
||||
var gaidenDataPath = Path.Combine(dataPath, settings.GaidenDataFileName);
|
||||
var songIntroDataPath = Path.Combine(dataPath, settings.IntroDataFileName);
|
||||
var movieDataPath = Path.Combine(dataPath, settings.MovieDataFileName);
|
||||
var eventFolderDataPath = Path.Combine(dataPath, settings.EventFolderDataFileName);
|
||||
var shopFolderDataPath = Path.Combine(dataPath, settings.ShopFolderDataFileName);
|
||||
var tokenDataPath = Path.Combine(dataPath, settings.TokenDataFileName);
|
||||
var lockedSongsDataPath = Path.Combine(dataPath, settings.LockedSongsDataFileName);
|
||||
var qrCodeDataPath = Path.Combine(dataPath, settings.QRCodeDataFileName);
|
||||
|
||||
InitializeTokenData(tokenData);
|
||||
var encryptedFiles = new List<string>
|
||||
{
|
||||
encryptedInfo,
|
||||
encryptedWordlist,
|
||||
encryptedMusicOrder,
|
||||
encryptedDonCosReward,
|
||||
encryptedShougou,
|
||||
encryptedNeiro
|
||||
};
|
||||
|
||||
InitializeLockedSongsData(lockedSongsData);
|
||||
|
||||
InitializeCostumeFlagArraySizes(donCosRewardData);
|
||||
|
||||
InitializeTitleFlagArraySize(shougouData);
|
||||
|
||||
InitializeToneFlagArraySize(neiroData);
|
||||
var outputPaths = new List<string>
|
||||
{
|
||||
musicInfoPath,
|
||||
wordlistPath,
|
||||
musicOrderPath,
|
||||
donCosRewardPath,
|
||||
shougouPath,
|
||||
neiroPath
|
||||
};
|
||||
|
||||
InitializeQrCodeData(qrCodeData);
|
||||
}
|
||||
for (var i = 0; i < encryptedFiles.Count; i++)
|
||||
{
|
||||
if (File.Exists(encryptedFiles[i]))
|
||||
{
|
||||
DecryptDataTable(encryptedFiles[i], outputPaths[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private static void DecryptDataTable(string inputFileName, string outputFileName)
|
||||
{
|
||||
var aes = Aes.Create();
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.KeySize = 256;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.Key = Convert.FromHexString("3530304242323633353537423431384139353134383346433246464231354534");
|
||||
var iv = new byte[16];
|
||||
using var fs = File.OpenRead(inputFileName);
|
||||
var count = fs.Read(iv, 0, 16);
|
||||
count.Throw("Read IV for datatable failed!").IfNotEquals(16);
|
||||
aes.IV = iv;
|
||||
using var cs = new CryptoStream(fs, aes.CreateDecryptor(), CryptoStreamMode.Read);
|
||||
using var ms = new MemoryStream();
|
||||
cs.CopyTo(ms);
|
||||
ms.Position = 0;
|
||||
using var gz = new GZipStream(ms, CompressionMode.Decompress);
|
||||
using var output = File.Create(outputFileName);
|
||||
gz.CopyTo(output);
|
||||
}
|
||||
foreach (var filePath in outputPaths)
|
||||
{
|
||||
if (!File.Exists(filePath))
|
||||
{
|
||||
throw new FileNotFoundException($"{Path.GetFileName(filePath)} file not found!");
|
||||
}
|
||||
}
|
||||
|
||||
private void InitializeIntroData(List<SongIntroductionData>? introData)
|
||||
{
|
||||
introData.ThrowIfNull("Shouldn't happen!");
|
||||
introDataDictionary = introData.ToImmutableDictionary(data => data.SetId, ToResponseIntroData);
|
||||
}
|
||||
await using var musicInfoFile = File.OpenRead(musicInfoPath);
|
||||
await using var danDataFile = File.OpenRead(danDataPath);
|
||||
await using var gaidenDataFile = File.OpenRead(gaidenDataPath);
|
||||
await using var songIntroDataFile = File.OpenRead(songIntroDataPath);
|
||||
await using var movieDataFile = File.OpenRead(movieDataPath);
|
||||
await using var eventFolderDataFile = File.OpenRead(eventFolderDataPath);
|
||||
await using var shopFolderDataFile = File.OpenRead(shopFolderDataPath);
|
||||
await using var tokenDataFile = File.OpenRead(tokenDataPath);
|
||||
await using var lockedSongsDataFile = File.OpenRead(lockedSongsDataPath);
|
||||
await using var donCosRewardFile = File.OpenRead(donCosRewardPath);
|
||||
await using var shougouFile = File.OpenRead(shougouPath);
|
||||
await using var neiroFile = File.OpenRead(neiroPath);
|
||||
await using var qrCodeDataFile = File.OpenRead(qrCodeDataPath);
|
||||
|
||||
private void InitializeMovieData(List<MovieData>? movieData)
|
||||
{
|
||||
movieData.ThrowIfNull("Shouldn't happen!");
|
||||
movieDataDictionary = movieData.ToImmutableDictionary(data => data.MovieId, ToResponseMovieData);
|
||||
}
|
||||
var infoesData = await JsonSerializer.DeserializeAsync<MusicInfoes>(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);
|
||||
var movieData = await JsonSerializer.DeserializeAsync<List<MovieData>>(movieDataFile);
|
||||
var eventFolderData = await JsonSerializer.DeserializeAsync<List<EventFolderData>>(eventFolderDataFile);
|
||||
var shopFolderData = await JsonSerializer.DeserializeAsync<List<ShopFolderData>>(shopFolderDataFile);
|
||||
var tokenData = await JsonSerializer.DeserializeAsync<Dictionary<string, int>>(tokenDataFile);
|
||||
var lockedSongsData = await JsonSerializer.DeserializeAsync<Dictionary<string, uint[]>>(lockedSongsDataFile);
|
||||
var donCosRewardData = await JsonSerializer.DeserializeAsync<DonCosRewards>(donCosRewardFile);
|
||||
var shougouData = await JsonSerializer.DeserializeAsync<Shougous>(shougouFile);
|
||||
var neiroData = await JsonSerializer.DeserializeAsync<Neiros>(neiroFile);
|
||||
var qrCodeData = await JsonSerializer.DeserializeAsync<List<QRCodeData>>(qrCodeDataFile);
|
||||
|
||||
private void InitializeDanData(List<DanData>? danData)
|
||||
{
|
||||
danData.ThrowIfNull("Shouldn't happen!");
|
||||
danDataDictionary = danData.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData);
|
||||
}
|
||||
InitializeMusicInfoes(infoesData);
|
||||
|
||||
private void InitializeGaidenData(List<DanData>? gaidenData)
|
||||
{
|
||||
gaidenData.ThrowIfNull("Shouldn't happen!");
|
||||
gaidenDataDictionary = gaidenData.ToImmutableDictionary(data => data.DanId, ToResponseOdaiData);
|
||||
}
|
||||
InitializeDanData(danData);
|
||||
|
||||
private void InitializeEventFolderData(List<EventFolderData>? eventFolderData)
|
||||
{
|
||||
eventFolderData.ThrowIfNull("Shouldn't happen!");
|
||||
folderDictionary = eventFolderData.ToImmutableDictionary(data => data.FolderId, ToResponseEventFolderData);
|
||||
}
|
||||
InitializeGaidenData(gaidenData);
|
||||
|
||||
private void InitializeMusicInfoes(MusicInfoes? infoesData)
|
||||
{
|
||||
infoesData.ThrowIfNull("Shouldn't happen!");
|
||||
InitializeIntroData(introData);
|
||||
|
||||
musicInfoes = infoesData.MusicInfoEntries.ToImmutableDictionary(info => info.MusicId);
|
||||
InitializeMovieData(movieData);
|
||||
|
||||
musics = musicInfoes.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
musics.Sort();
|
||||
|
||||
musicsWithUra = musicInfoes.Where(info => info.Value.StarUra > 0)
|
||||
.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
musicsWithUra.Sort();
|
||||
}
|
||||
InitializeEventFolderData(eventFolderData);
|
||||
|
||||
private void InitializeShopFolderData(List<ShopFolderData>? shopFolderData)
|
||||
{
|
||||
shopFolderData.ThrowIfNull("Shouldn't happen!");
|
||||
foreach (var folderData in shopFolderData)
|
||||
{
|
||||
shopFolderList.Add(ToResponseShopFolderData(folderData));
|
||||
}
|
||||
}
|
||||
InitializeShopFolderData(shopFolderData);
|
||||
|
||||
private void InitializeTokenData(Dictionary<string, int>? tokenData)
|
||||
{
|
||||
tokenData.ThrowIfNull("Shouldn't happen!");
|
||||
tokenDataDictionary = tokenData;
|
||||
}
|
||||
InitializeTokenData(tokenData);
|
||||
|
||||
private void InitializeLockedSongsData(Dictionary<string, uint[]>? lockedSongsData)
|
||||
{
|
||||
lockedSongsData.ThrowIfNull("Shouldn't happen!");
|
||||
lockedSongsList = lockedSongsData["songNo"].ToList();
|
||||
}
|
||||
|
||||
private void InitializeCostumeFlagArraySizes(DonCosRewards? donCosRewardData)
|
||||
{
|
||||
donCosRewardData.ThrowIfNull("Shouldn't happen!");
|
||||
var kigurumiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "kigurumi")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var headUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "head")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var bodyUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "body")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var faceUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "face")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var puchiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "puchi")
|
||||
.Select(entry => entry.UniqueId);
|
||||
|
||||
costumeFlagArraySizes = new List<int>
|
||||
{
|
||||
(int)kigurumiUniqueIdList.Max() + 1,
|
||||
(int)headUniqueIdList.Max() + 1,
|
||||
(int)bodyUniqueIdList.Max() + 1,
|
||||
(int)faceUniqueIdList.Max() + 1,
|
||||
(int)puchiUniqueIdList.Max() + 1
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeTitleFlagArraySize(Shougous? shougouData)
|
||||
{
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
titleFlagArraySize = (int)shougouData.ShougouEntries.Max(entry => entry.UniqueId) + 1;
|
||||
}
|
||||
|
||||
private void InitializeToneFlagArraySize(Neiros? neiroData)
|
||||
{
|
||||
neiroData.ThrowIfNull("Shouldn't happen!");
|
||||
toneFlagArraySize = (int)neiroData.NeiroEntries.Max(entry => entry.UniqueId) + 1;
|
||||
}
|
||||
|
||||
private void InitializeQrCodeData(List<QRCodeData>? qrCodeData)
|
||||
{
|
||||
qrCodeData.ThrowIfNull("Shouldn't happen!");
|
||||
qrCodeDataDictionary = qrCodeData.ToImmutableDictionary(data => data.Serial, data => data.Id);
|
||||
}
|
||||
InitializeLockedSongsData(lockedSongsData);
|
||||
|
||||
private static GetDanOdaiResponse.OdaiData ToResponseOdaiData(DanData data)
|
||||
{
|
||||
var responseOdaiData = new GetDanOdaiResponse.OdaiData
|
||||
{
|
||||
DanId = data.DanId,
|
||||
Title = data.Title,
|
||||
VerupNo = data.VerupNo
|
||||
};
|
||||
InitializeCostumeFlagArraySizes(donCosRewardData);
|
||||
|
||||
var odaiSongs = data.OdaiSongList.Select(song => song.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiSong>());
|
||||
responseOdaiData.AryOdaiSongs.AddRange(odaiSongs);
|
||||
InitializeTitleFlagArraySize(shougouData);
|
||||
|
||||
var odaiBorders = data.OdaiBorderList.Select(border => border.CopyPropertiesToNew<GetDanOdaiResponse.OdaiData.OdaiBorder>());
|
||||
responseOdaiData.AryOdaiBorders.AddRange(odaiBorders);
|
||||
InitializeToneFlagArraySize(neiroData);
|
||||
|
||||
return responseOdaiData;
|
||||
}
|
||||
InitializeQrCodeData(qrCodeData);
|
||||
}
|
||||
|
||||
private static GetSongIntroductionResponse.SongIntroductionData ToResponseIntroData(SongIntroductionData data)
|
||||
{
|
||||
var responseIntroData = new GetSongIntroductionResponse.SongIntroductionData
|
||||
{
|
||||
SetId = data.SetId,
|
||||
VerupNo = data.VerupNo,
|
||||
MainSongNo = data.MainSongNo,
|
||||
SubSongNoes = data.SubSongNo
|
||||
};
|
||||
private static void DecryptDataTable(string inputFileName, string outputFileName)
|
||||
{
|
||||
var aes = Aes.Create();
|
||||
aes.Mode = CipherMode.CBC;
|
||||
aes.KeySize = 256;
|
||||
aes.Padding = PaddingMode.PKCS7;
|
||||
aes.Key = Convert.FromHexString("3530304242323633353537423431384139353134383346433246464231354534");
|
||||
var iv = new byte[16];
|
||||
using var fs = File.OpenRead(inputFileName);
|
||||
var count = fs.Read(iv, 0, 16);
|
||||
count.Throw("Read IV for datatable failed!").IfNotEquals(16);
|
||||
aes.IV = iv;
|
||||
using var cs = new CryptoStream(fs, aes.CreateDecryptor(), CryptoStreamMode.Read);
|
||||
using var ms = new MemoryStream();
|
||||
cs.CopyTo(ms);
|
||||
ms.Position = 0;
|
||||
using var gz = new GZipStream(ms, CompressionMode.Decompress);
|
||||
using var output = File.Create(outputFileName);
|
||||
gz.CopyTo(output);
|
||||
}
|
||||
|
||||
return responseIntroData;
|
||||
}
|
||||
private void InitializeIntroData(List<SongIntroductionData>? introData)
|
||||
{
|
||||
introData.ThrowIfNull("Shouldn't happen!");
|
||||
songIntroductionDictionary = introData.ToImmutableDictionary(data => data.SetId);
|
||||
}
|
||||
|
||||
private static InitialdatacheckResponse.MovieData ToResponseMovieData(MovieData data)
|
||||
{
|
||||
var responseMovieData = new InitialdatacheckResponse.MovieData
|
||||
{
|
||||
MovieId = data.MovieId,
|
||||
EnableDays = data.EnableDays
|
||||
};
|
||||
private void InitializeMovieData(List<MovieData>? movieData)
|
||||
{
|
||||
movieData.ThrowIfNull("Shouldn't happen!");
|
||||
movieDataDictionary = movieData.ToImmutableDictionary(data => data.MovieId);
|
||||
}
|
||||
|
||||
return responseMovieData;
|
||||
}
|
||||
private void InitializeDanData(List<DanData>? danData)
|
||||
{
|
||||
danData.ThrowIfNull("Shouldn't happen!");
|
||||
commonDanDataDictionary = danData.ToImmutableDictionary(data => data.DanId);
|
||||
}
|
||||
|
||||
private static GetfolderResponse.EventfolderData ToResponseEventFolderData(EventFolderData data)
|
||||
{
|
||||
var responseEventFolderData = new GetfolderResponse.EventfolderData
|
||||
{
|
||||
FolderId = data.FolderId,
|
||||
VerupNo = data.VerupNo,
|
||||
Priority = data.Priority,
|
||||
SongNoes = data.SongNo,
|
||||
ParentFolderId = data.ParentFolderId
|
||||
};
|
||||
private void InitializeGaidenData(List<DanData>? gaidenData)
|
||||
{
|
||||
gaidenData.ThrowIfNull("Shouldn't happen!");
|
||||
commonGaidenDataDictionary = gaidenData.ToImmutableDictionary(data => data.DanId);
|
||||
}
|
||||
|
||||
return responseEventFolderData;
|
||||
}
|
||||
private void InitializeEventFolderData(List<EventFolderData>? eventFolderData)
|
||||
{
|
||||
eventFolderData.ThrowIfNull("Shouldn't happen!");
|
||||
eventFolderDictionary = eventFolderData.ToImmutableDictionary(d => d.FolderId);
|
||||
}
|
||||
|
||||
private static GetShopFolderResponse.ShopFolderData ToResponseShopFolderData(ShopFolderData data)
|
||||
{
|
||||
var responseShopFolderData = new GetShopFolderResponse.ShopFolderData
|
||||
{
|
||||
SongNo = data.SongNo,
|
||||
Price = data.Price
|
||||
};
|
||||
private void InitializeMusicInfoes(MusicInfoes? infoesData)
|
||||
{
|
||||
infoesData.ThrowIfNull("Shouldn't happen!");
|
||||
|
||||
return responseShopFolderData;
|
||||
}
|
||||
musicInfoes = infoesData.MusicInfoEntries.ToImmutableDictionary(info => info.MusicId);
|
||||
|
||||
musics = musicInfoes.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
musics.Sort();
|
||||
|
||||
musicsWithUra = musicInfoes.Where(info => info.Value.StarUra > 0)
|
||||
.Select(pair => pair.Key)
|
||||
.ToList();
|
||||
musicsWithUra.Sort();
|
||||
}
|
||||
|
||||
private void InitializeShopFolderData(List<ShopFolderData>? shopFolderData)
|
||||
{
|
||||
shopFolderData.ThrowIfNull("Shouldn't happen!");
|
||||
shopFolderList = shopFolderData;
|
||||
}
|
||||
|
||||
private void InitializeTokenData(Dictionary<string, int>? tokenData)
|
||||
{
|
||||
tokenData.ThrowIfNull("Shouldn't happen!");
|
||||
tokenDataDictionary = tokenData;
|
||||
}
|
||||
|
||||
private void InitializeLockedSongsData(Dictionary<string, uint[]>? lockedSongsData)
|
||||
{
|
||||
lockedSongsData.ThrowIfNull("Shouldn't happen!");
|
||||
lockedSongsList = lockedSongsData["songNo"].ToList();
|
||||
}
|
||||
|
||||
private void InitializeCostumeFlagArraySizes(DonCosRewards? donCosRewardData)
|
||||
{
|
||||
donCosRewardData.ThrowIfNull("Shouldn't happen!");
|
||||
var kigurumiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "kigurumi")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var headUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "head")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var bodyUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "body")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var faceUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "face")
|
||||
.Select(entry => entry.UniqueId);
|
||||
var puchiUniqueIdList = donCosRewardData.DonCosRewardEntries
|
||||
.Where(entry => entry.CosType == "puchi")
|
||||
.Select(entry => entry.UniqueId);
|
||||
|
||||
costumeFlagArraySizes = new List<int>
|
||||
{
|
||||
(int)kigurumiUniqueIdList.Max() + 1,
|
||||
(int)headUniqueIdList.Max() + 1,
|
||||
(int)bodyUniqueIdList.Max() + 1,
|
||||
(int)faceUniqueIdList.Max() + 1,
|
||||
(int)puchiUniqueIdList.Max() + 1
|
||||
};
|
||||
}
|
||||
|
||||
private void InitializeTitleFlagArraySize(Shougous? shougouData)
|
||||
{
|
||||
shougouData.ThrowIfNull("Shouldn't happen!");
|
||||
titleFlagArraySize = (int)shougouData.ShougouEntries.Max(entry => entry.UniqueId) + 1;
|
||||
}
|
||||
|
||||
private void InitializeToneFlagArraySize(Neiros? neiroData)
|
||||
{
|
||||
neiroData.ThrowIfNull("Shouldn't happen!");
|
||||
toneFlagArraySize = (int)neiroData.NeiroEntries.Max(entry => entry.UniqueId) + 1;
|
||||
}
|
||||
|
||||
private void InitializeQrCodeData(List<QRCodeData>? qrCodeData)
|
||||
{
|
||||
qrCodeData.ThrowIfNull("Shouldn't happen!");
|
||||
qrCodeDataDictionary = qrCodeData.ToImmutableDictionary(data => data.Serial, data => data.Id);
|
||||
}
|
||||
}
|
@ -7,8 +7,6 @@ public interface ICardService
|
||||
{
|
||||
public Task<Card?> GetCardByAccessCode(string accessCode);
|
||||
|
||||
public uint GetNextBaid();
|
||||
|
||||
public Task<List<User>> GetUsersFromCards();
|
||||
|
||||
public Task AddCard(Card card);
|
||||
|
@ -12,18 +12,18 @@ public interface IGameDataService
|
||||
public List<uint> GetMusicWithUraList();
|
||||
|
||||
public ImmutableDictionary<uint, MusicInfoEntry> GetMusicInfoes();
|
||||
|
||||
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetDanDataDictionary();
|
||||
|
||||
public ImmutableDictionary<uint, GetDanOdaiResponse.OdaiData> GetGaidenDataDictionary();
|
||||
public ImmutableDictionary<uint, SongIntroductionData> GetSongIntroductionDictionary();
|
||||
|
||||
public ImmutableDictionary<uint, GetSongIntroductionResponse.SongIntroductionData> GetSongIntroDictionary();
|
||||
public ImmutableDictionary<uint, MovieData> GetMovieDataDictionary();
|
||||
|
||||
public ImmutableDictionary<uint, InitialdatacheckResponse.MovieData> GetMovieDataDictionary();
|
||||
public ImmutableDictionary<uint, EventFolderData> GetEventFolderDictionary();
|
||||
|
||||
public ImmutableDictionary<uint, DanData> GetCommonDanDataDictionary();
|
||||
|
||||
public ImmutableDictionary<uint, DanData> GetCommonGaidenDataDictionary();
|
||||
|
||||
public ImmutableDictionary<uint, GetfolderResponse.EventfolderData> GetFolderDictionary();
|
||||
|
||||
public List<GetShopFolderResponse.ShopFolderData> GetShopFolderList();
|
||||
public List<ShopFolderData> GetShopFolderList();
|
||||
|
||||
public Dictionary<string, int> GetTokenDataDictionary();
|
||||
|
||||
|
@ -75,8 +75,9 @@ public class UserDatumService : IUserDatumService
|
||||
{
|
||||
var userDatum = await context.UserData.FindAsync(baid);
|
||||
userDatum.ThrowIfNull($"User with baid: {baid} not found!");
|
||||
return userDatum.FavoriteSongsArray.ToList();
|
||||
|
||||
using var stringStream = GZipBytesUtil.GenerateStreamFromString(userDatum.FavoriteSongsArray);
|
||||
/*using var stringStream = GZipBytesUtil.GenerateStreamFromString(userDatum.FavoriteSongsArray);
|
||||
List<uint>? result;
|
||||
try
|
||||
{
|
||||
@ -88,7 +89,7 @@ public class UserDatumService : IUserDatumService
|
||||
result = new List<uint>();
|
||||
}
|
||||
result.ThrowIfNull("Song favorite array should never be null!");
|
||||
return result;
|
||||
return result;*/
|
||||
}
|
||||
|
||||
public async Task UpdateFavoriteSong(uint baid, uint songId, bool isFavorite)
|
||||
@ -96,7 +97,7 @@ public class UserDatumService : IUserDatumService
|
||||
var userDatum = await context.UserData.FindAsync(baid);
|
||||
userDatum.ThrowIfNull($"User with baid: {baid} not found!");
|
||||
|
||||
using var stringStream = GZipBytesUtil.GenerateStreamFromString(userDatum.FavoriteSongsArray);
|
||||
/*using var stringStream = GZipBytesUtil.GenerateStreamFromString(userDatum.FavoriteSongsArray);
|
||||
List<uint>? favoriteSongIds;
|
||||
try
|
||||
{
|
||||
@ -107,8 +108,8 @@ public class UserDatumService : IUserDatumService
|
||||
logger.LogError(e, "Parse favorite song array json failed! Is the user initialized correctly?");
|
||||
favoriteSongIds = new List<uint>();
|
||||
}
|
||||
favoriteSongIds.ThrowIfNull("Song favorite array should never be null!");
|
||||
var favoriteSet = new HashSet<uint>(favoriteSongIds);
|
||||
favoriteSongIds.ThrowIfNull("Song favorite array should never be null!");*/
|
||||
var favoriteSet = new HashSet<uint>(userDatum.FavoriteSongsArray);
|
||||
if (isFavorite)
|
||||
{
|
||||
favoriteSet.Add(songId);
|
||||
@ -123,8 +124,8 @@ public class UserDatumService : IUserDatumService
|
||||
newFavoriteSongStream.Position = 0;
|
||||
using var reader = new StreamReader(newFavoriteSongStream);
|
||||
|
||||
userDatum.FavoriteSongsArray = await reader.ReadToEndAsync();
|
||||
logger.LogInformation("Favorite songs are: {Favorite}", userDatum.FavoriteSongsArray);
|
||||
userDatum.FavoriteSongsArray = favoriteSet.ToArray();//await reader.ReadToEndAsync();
|
||||
//logger.LogInformation("Favorite songs are: {Favorite}", userDatum.FavoriteSongsArray);
|
||||
context.Update(userDatum);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Version>1.0.0-beta</Version>
|
||||
<LangVersion>11</LangVersion>
|
||||
<LangVersion>12</LangVersion>
|
||||
<EnableConfigurationBindingGenerator>false</EnableConfigurationBindingGenerator>
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
</PropertyGroup>
|
||||
@ -15,6 +15,7 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MediatR" Version="12.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="8.0.0-rc.1.23421.29" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0-rc.2.23480.1" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.0-rc.2.23480.1" />
|
||||
@ -22,9 +23,10 @@
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="protobuf-net" Version="3.2.26" />
|
||||
<PackageReference Include="protobuf-net" Version="3.2.30" />
|
||||
<PackageReference Include="protobuf-net.AspNetCore" Version="3.2.12" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="7.0.0" />
|
||||
<PackageReference Include="Riok.Mapperly" Version="3.5.0-next.1" />
|
||||
<PackageReference Include="Serilog.AspNetCore" Version="8.0.2-dev-00334" />
|
||||
<PackageReference Include="Serilog.Expressions" Version="4.0.0-dev-00137" />
|
||||
<PackageReference Include="Serilog.Sinks.File.Header" Version="1.0.2" />
|
||||
<PackageReference Include="SharpZipLib" Version="1.4.2" />
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
{
|
||||
"serial": "",
|
||||
"id": 0
|
||||
"serial": "TOURNAMENT_2021_01",
|
||||
"id": 12345
|
||||
}
|
||||
]
|
Loading…
Reference in New Issue
Block a user