224 lines
8.9 KiB
C#
Raw Normal View History

2025-01-20 23:19:14 +01:00
using GameDatabase.Context;
using Throw;
namespace TaikoLocalServer.Handlers;
public record BaidQuery(string AccessCode) : IRequest<CommonBaidResponse>;
public class BaidQueryHandler(
TaikoDbContext context,
ILogger<BaidQueryHandler> logger,
IGameDataService gameDataService)
: IRequestHandler<BaidQuery, CommonBaidResponse>
{
public async Task<CommonBaidResponse> Handle(BaidQuery request, CancellationToken cancellationToken)
{
var card = await context.Cards.FindAsync(request.AccessCode);
var oldAccesscode = ConvertOldUID(request.AccessCode);
var oldcard = await context.Cards.FindAsync(oldAccesscode);
if (oldcard is not null)
{
logger.LogInformation("{AccessCode} converts to {Converted}, Updating...", request.AccessCode, oldcard.AccessCode);
if (card is null)
{
logger.LogInformation("{newCard} wasn't bound !, Updating...", request.AccessCode);
Card newCard = new Card();
newCard.Baid = oldcard.Baid;
newCard.AccessCode = request.AccessCode;
await context.Cards.AddAsync(newCard);
card = newCard;
}
else logger.LogInformation("{newCard} was already bound !", request.AccessCode);
context.Cards.Remove(oldcard);
await context.SaveChangesAsync(cancellationToken);
}
if (card is null)
{
logger.LogInformation("New user with access code {AccessCode}", request.AccessCode);
return new CommonBaidResponse
{
Result = 1,
IsNewUser = true,
Baid = context.Cards.Any() ? context.Cards.AsEnumerable().Max(c => c.Baid) + 1 : 1
};
}
var baid = card.Baid;
var credential = context.Credentials.Where(cred => cred.Baid == baid).First();
var userData = await context.UserData.FindAsync(baid, cancellationToken);
userData.ThrowIfNull($"User not found for card with Baid {baid}!");
var songBestData = context.SongBestData.Where(datum => datum.Baid == baid).ToList();
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 = songBestData
.Where(datum => datum.BestCrown >= CrownType.Clear)
.GroupBy(datum => datum.BestCrown)
.ToDictionary(datums => datums.Key, datums => (uint)datums.Count());
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 = songBestData
.Where(datum => datum.BestCrown >= CrownType.Clear)
.GroupBy(datum => datum.BestScoreRank)
.ToDictionary(datums => datums.Key, datums => (uint)datums.Count());
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);
}
}
List<uint> costumeData = [userData.CurrentKigurumi, userData.CurrentHead, userData.CurrentBody, userData.CurrentFace, String.IsNullOrEmpty(credential.Password) ? 200 : userData.CurrentPuchi];
List<List<uint>> costumeArrays =
[userData.UnlockedKigurumi, userData.UnlockedHead, userData.UnlockedBody, userData.UnlockedFace, userData.UnlockedPuchi];
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 > 10)
{
aiRank = 10;
}
return new CommonBaidResponse
{
Result = 1,
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.DateTimeFormat),
LastPlayMode = userData.LastPlayMode,
SelectedToneId = userData.SelectedToneId,
Title = String.IsNullOrEmpty(credential.Password) ? FormatStringInGroupsOfFour(request.AccessCode) : userData.Title,
TitlePlateId = userData.TitlePlateId,
AiTotalWin = (uint)userData.AiWinCount,
AiRank = aiRank
};
static string FormatStringInGroupsOfFour(string input)
{
if (string.IsNullOrEmpty(input))
return input;
// Use a StringBuilder for efficient string manipulation
var stringBuilder = new System.Text.StringBuilder();
int length = input.Length;
for (int i = 0; i < length; i++)
{
if (i > 0 && i % 4 == 0)
{
stringBuilder.Append(' ');
}
stringBuilder.Append(input[i]);
}
return stringBuilder.ToString();
}
string PadLeftWithZeros(string input, int desiredLength)
{
int zerosToAdd = Math.Max(0, desiredLength - input.Length);
return new string('0', zerosToAdd) + input;
}
string ConvertOldUID(string inputCardNum)
{
// Convert hexadecimal string to a byte array
inputCardNum = inputCardNum.ToUpper().Trim();
//Console.WriteLine(inputCardNum);
try
{
byte[] byteArray = new byte[inputCardNum.Length / 2];
for (int i = 0; i < inputCardNum.Length; i += 2)
{
byteArray[i / 2] = Convert.ToByte(inputCardNum.Substring(i, 2), 16);
}
// Reverse the array if needed (depends on endianness)
Array.Reverse(byteArray);
// Convert byte array to an unsigned long integer
string convertedNumber = PadLeftWithZeros(BitConverter.ToUInt64(byteArray, 0).ToString(), 20);
//Console.WriteLine($"Hexadecimal: {inputCardNum}");
//Console.WriteLine($"Decimal: {convertedNumber}");
return convertedNumber;
}
catch { }
return "";
}
}
}