Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82e0ecd9c3 | ||
|
|
bd2cb39b63 | ||
|
|
22eff77e88 | ||
|
|
449cd579d4 | ||
|
|
0896e92598 | ||
|
|
e159a427a0 | ||
|
|
7edcd07723 | ||
|
|
dbc776ddda | ||
|
|
66aaf027e2 | ||
|
|
48956e758f | ||
|
|
64da380363 | ||
|
|
5997452412 | ||
|
|
c19437baf6 | ||
|
|
eebbf05b10 | ||
|
|
a0eefdc3a9 | ||
|
|
cd5c06c97d | ||
|
|
f0a1dbc5ce | ||
|
|
0fd5fc7227 | ||
|
|
32a1886cf4 | ||
|
|
5afd885a00 | ||
|
|
ae2fe531a6 | ||
|
|
addee9ccdd | ||
|
|
f1edf55883 | ||
|
|
46d9a63a45 | ||
|
|
728415902b | ||
|
|
fe6ff27ffa | ||
|
|
c16b083b99 | ||
|
|
a911a9054c | ||
|
|
57e379817f | ||
|
|
a6dbf26bdf | ||
|
|
7c5c2fafb7 | ||
|
|
eb4380b6d5 | ||
|
|
e5eee66ff2 | ||
|
|
4d0e351abd | ||
|
|
8900cca29e | ||
|
|
2ff32b9693 | ||
|
|
6de389cf2b | ||
|
|
ef11e98da7 | ||
|
|
7b3fae51b7 | ||
|
|
9d58e71e06 | ||
|
|
02a241567c | ||
|
|
5c85e83c3e | ||
|
|
1fccca42c6 | ||
|
|
1db9fdf6d3 | ||
|
|
14f171792e | ||
|
|
805611027c | ||
|
|
7093997658 | ||
|
|
aefc9ca326 | ||
|
|
6eb71437cf | ||
|
|
9c759c3b1a | ||
|
|
f7761f200f | ||
|
|
aea09c2c8b |
@@ -0,0 +1,18 @@
|
||||
namespace Application.Api;
|
||||
|
||||
public record GetCardsQuery() : IRequestWrapper<List<ClientCardDto>>;
|
||||
|
||||
public class GetCardsQueryHandler : RequestHandlerBase<GetCardsQuery, List<ClientCardDto>>
|
||||
{
|
||||
public GetCardsQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<List<ClientCardDto>>> Handle(GetCardsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var cards = await CardDbContext.CardMains.ToListAsync(cancellationToken: cancellationToken);
|
||||
var dtoList = cards.Select(card => card.CardMainToClientDto()).ToList();
|
||||
|
||||
return new ServiceResult<List<ClientCardDto>>(dtoList);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using Shared.Models;
|
||||
|
||||
namespace Application.Api;
|
||||
|
||||
public record GetPlayOptionQuery(long CardId) : IRequestWrapper<PlayOptionData>;
|
||||
|
||||
public class GetPlayOptionQueryHandler : RequestHandlerBase<GetPlayOptionQuery, PlayOptionData>
|
||||
{
|
||||
public GetPlayOptionQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<PlayOptionData>> Handle(GetPlayOptionQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var optionDetail1 = await CardDbContext.CardDetails.FirstOrDefaultAsync(detail =>
|
||||
detail.CardId == request.CardId &&
|
||||
detail.Pcol1 == 0 &&
|
||||
detail.Pcol2 == 0 &&
|
||||
detail.Pcol3 == 0,
|
||||
cancellationToken: cancellationToken);
|
||||
var optionDetail2 = await CardDbContext.CardDetails.FirstOrDefaultAsync(detail =>
|
||||
detail.CardId == request.CardId &&
|
||||
detail.Pcol1 == 1 &&
|
||||
detail.Pcol2 == 0 &&
|
||||
detail.Pcol3 == 0,
|
||||
cancellationToken: cancellationToken);
|
||||
if (optionDetail1 is null ||
|
||||
optionDetail2 is null)
|
||||
{
|
||||
return ServiceResult.Failed<PlayOptionData>(ServiceError.CustomMessage("At least one of the play option records not found"));
|
||||
}
|
||||
|
||||
var result = new PlayOptionData
|
||||
{
|
||||
CardId = request.CardId,
|
||||
OptionPart1 = optionDetail1.CardDetailToFirstOption(),
|
||||
OptionPart2 = optionDetail2.CardDetailToSecondOption()
|
||||
};
|
||||
|
||||
return new ServiceResult<PlayOptionData>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Domain.Entities;
|
||||
using Domain.Enums;
|
||||
|
||||
namespace Application.Api;
|
||||
|
||||
public record GetSongPlayRecordsQuery(long cardId) : IRequestWrapper<List<SongPlayRecord>>;
|
||||
|
||||
public class GetSongPlayRecordsQueryHandler : RequestHandlerBase<GetSongPlayRecordsQuery, List<SongPlayRecord>>
|
||||
{
|
||||
public GetSongPlayRecordsQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records")]
|
||||
public override async Task<ServiceResult<List<SongPlayRecord>>> Handle(GetSongPlayRecordsQuery request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = await CardDbContext.CardDetails.AnyAsync(detail => detail.CardId == request.cardId);
|
||||
if (!exists)
|
||||
{
|
||||
return ServiceResult.Failed<List<SongPlayRecord>>(ServiceError.CustomMessage("No play record"));
|
||||
}
|
||||
var results = new List<SongPlayRecord>();
|
||||
|
||||
var musics = await MusicDbContext.MusicUnlocks.ToDictionaryAsync(unlock => unlock.MusicId, cancellationToken);
|
||||
|
||||
var playCounts = await CardDbContext.CardDetails
|
||||
.Where(detail => detail.CardId == request.cardId &&
|
||||
detail.Pcol1 == 20)
|
||||
.Select(detail => new
|
||||
{
|
||||
MusicId = detail.Pcol2,
|
||||
Difficulty = (Difficulty)detail.Pcol3,
|
||||
Detail = detail
|
||||
})
|
||||
.ToDictionaryAsync(arg => new { arg.MusicId, arg.Difficulty }, cancellationToken: cancellationToken);
|
||||
|
||||
var stageDetails = await CardDbContext.CardDetails
|
||||
.Where(detail => detail.CardId == request.cardId &&
|
||||
detail.Pcol1 == 21)
|
||||
.Select(detail => new
|
||||
{
|
||||
MusicId = detail.Pcol2,
|
||||
Difficulty = (Difficulty)detail.Pcol3,
|
||||
Score = detail.ScoreUi1,
|
||||
MaxChain = detail.ScoreUi3,
|
||||
})
|
||||
.ToDictionaryAsync(arg => new { arg.MusicId, arg.Difficulty }, cancellationToken);
|
||||
|
||||
var favorites = await CardDbContext.CardDetails
|
||||
.Where(detail => detail.CardId == request.cardId &&
|
||||
detail.Pcol1 == 10)
|
||||
.Select(detail => new { MusicId = detail.Pcol2, IsFavorite = detail.Fcol1 == 1 })
|
||||
.ToListAsync(cancellationToken);
|
||||
|
||||
foreach (var song in favorites)
|
||||
{
|
||||
var musicId = song.MusicId;
|
||||
var music = musics.GetValueOrDefault(musicId);
|
||||
var songPlayRecord = new SongPlayRecord
|
||||
{
|
||||
MusicId = (int)musicId,
|
||||
Title = music?.Title ?? string.Empty,
|
||||
Artist = music?.Artist ?? string.Empty,
|
||||
IsFavorite = song.IsFavorite
|
||||
};
|
||||
foreach (var difficulty in DifficultyExtensions.GetValues())
|
||||
{
|
||||
var key = new { MusicId = musicId, Difficulty = difficulty };
|
||||
if (!playCounts.ContainsKey(key) || !stageDetails.ContainsKey(key)) continue;
|
||||
var playCountDetail = playCounts[key].Detail;
|
||||
var playCount = playCountDetail.ScoreUi1;
|
||||
var stageDetail = stageDetails[key];
|
||||
var score = stageDetail.Score;
|
||||
var maxChain = stageDetail.MaxChain;
|
||||
var clearState = GetClearState(playCountDetail);
|
||||
var stagePlayRecord = new StagePlayRecord
|
||||
{
|
||||
Difficulty = difficulty,
|
||||
ClearState = clearState,
|
||||
PlayCount = (int)playCount,
|
||||
Score = (int)score,
|
||||
MaxChain = (int)maxChain,
|
||||
LastPlayTime = playCountDetail?.LastPlayTime ?? DateTime.MinValue
|
||||
};
|
||||
songPlayRecord.StagePlayRecords.Add(stagePlayRecord);
|
||||
}
|
||||
|
||||
songPlayRecord.TotalPlayCount = songPlayRecord.StagePlayRecords.Sum(record => record.PlayCount);
|
||||
if (songPlayRecord.StagePlayRecords.Count > 0)
|
||||
{
|
||||
results.Add(songPlayRecord);
|
||||
}
|
||||
}
|
||||
|
||||
return new ServiceResult<List<SongPlayRecord>>(results);
|
||||
}
|
||||
|
||||
private static ClearState GetClearState(CardDetail detail)
|
||||
{
|
||||
var result = ClearState.Failed;
|
||||
if (detail.ScoreUi2 > 0)
|
||||
{
|
||||
result = ClearState.Clear;
|
||||
}
|
||||
|
||||
if (detail.ScoreUi3 > 0)
|
||||
{
|
||||
result = ClearState.NoMiss;
|
||||
}
|
||||
|
||||
if (detail.ScoreUi4 > 0)
|
||||
{
|
||||
result = ClearState.FullChain;
|
||||
}
|
||||
|
||||
if (detail.ScoreUi6 > 0)
|
||||
{
|
||||
result = ClearState.Perfect;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Shared.Models;
|
||||
|
||||
namespace Application.Api;
|
||||
|
||||
public record GetTotalResultQuery(long CardId) : IRequestWrapper<TotalResultData>;
|
||||
|
||||
public class GetTotalResultQueryHandler : RequestHandlerBase<GetTotalResultQuery, TotalResultData>
|
||||
{
|
||||
private const int S_SCORE = 900000;
|
||||
private const int SS_SCORE = 950000;
|
||||
private const int SSS_SCORE = 990000;
|
||||
|
||||
private readonly ILogger<GetTotalResultQueryHandler> logger;
|
||||
|
||||
public GetTotalResultQueryHandler(ICardDependencyAggregate aggregate, ILogger<GetTotalResultQueryHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<TotalResultData>> Handle(GetTotalResultQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var card = await CardDbContext.CardMains.FirstOrDefaultAsync(card => card.CardId == request.CardId, cancellationToken);
|
||||
if (card is null)
|
||||
{
|
||||
logger.LogWarning("Trying to get total result for non existing card: {CardId}", request.CardId);
|
||||
return ServiceResult.Failed<TotalResultData>(ServiceError.UserNotFound);
|
||||
}
|
||||
|
||||
var result = new TotalResultData
|
||||
{
|
||||
CardId = card.CardId,
|
||||
PlayerName = card.PlayerName
|
||||
};
|
||||
|
||||
var totalSongCount = await MusicDbContext.MusicUnlocks.CountAsync(cancellationToken: cancellationToken);
|
||||
var totalExtraCount = await MusicDbContext.MusicExtras.CountAsync(cancellationToken: cancellationToken);
|
||||
var totalStageCount = totalSongCount * 3 + totalExtraCount;
|
||||
result.PlayerData.TotalSongCount = totalSongCount;
|
||||
result.StageCountData.Total = totalStageCount;
|
||||
|
||||
var playedStageDetails = await CardDbContext.CardDetails.Where(detail =>
|
||||
detail.CardId == request.CardId &&
|
||||
detail.Pcol1 == 20).ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
var playedStageScores = await CardDbContext.CardDetails.Where(detail =>
|
||||
detail.CardId == request.CardId &&
|
||||
detail.Pcol1 == 21).ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
var playedSongCount = playedStageDetails.DistinctBy(detail => detail.Pcol2).Count();
|
||||
var playedStageCount = playedStageDetails.Count;
|
||||
var clearedStageCount = playedStageDetails.Count(detail => detail.ScoreUi2 > 0);
|
||||
var noMissStageCount = playedStageDetails.Count(detail => detail.ScoreUi3 > 0);
|
||||
var fullChainStageCount = playedStageDetails.Count(detail => detail.ScoreUi4 > 0);
|
||||
var perfectStageCount = playedStageDetails.Count(detail => detail.ScoreUi6 > 0);
|
||||
|
||||
var sStageCount = playedStageScores.Count(detail => detail.ScoreUi1 > S_SCORE);
|
||||
var ssStageCount = playedStageScores.Count(detail => detail.ScoreUi1 > SS_SCORE);
|
||||
var sssStageCount = playedStageScores.Count(detail => detail.ScoreUi1 > SSS_SCORE);
|
||||
result.PlayerData.PlayedSongCount = playedSongCount;
|
||||
result.StageCountData.Cleared = clearedStageCount;
|
||||
result.StageCountData.NoMiss = noMissStageCount;
|
||||
result.StageCountData.FullChain = fullChainStageCount;
|
||||
result.StageCountData.Perfect = perfectStageCount;
|
||||
result.StageCountData.S = sStageCount;
|
||||
result.StageCountData.Ss = ssStageCount;
|
||||
result.StageCountData.Sss = sssStageCount;
|
||||
|
||||
var totalScore = playedStageScores.Sum(detail => detail.ScoreUi1);
|
||||
var averageScore = playedStageCount == 0 ? 0 : totalScore / playedStageCount;
|
||||
result.PlayerData.TotalScore = totalScore;
|
||||
result.PlayerData.AverageScore = (int)averageScore;
|
||||
|
||||
var rank = await CardDbContext.GlobalScoreRanks.FirstOrDefaultAsync(rank => rank.CardId == request.CardId,
|
||||
cancellationToken: cancellationToken);
|
||||
result.PlayerData.Rank = (int)(rank?.Rank ?? -1);
|
||||
|
||||
return new ServiceResult<TotalResultData>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Api;
|
||||
|
||||
public record SetFavoriteMusicCommand(MusicFavoriteDto Data) : IRequestWrapper<bool>;
|
||||
|
||||
public class SetFavoriteMusicCommandHandler : RequestHandlerBase<SetFavoriteMusicCommand, bool>
|
||||
{
|
||||
private readonly ILogger<SetFavoriteMusicCommandHandler> logger;
|
||||
|
||||
public SetFavoriteMusicCommandHandler(ICardDependencyAggregate aggregate, ILogger<SetFavoriteMusicCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<bool>> Handle(SetFavoriteMusicCommand request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var musicDetail = await CardDbContext.CardDetails.FirstOrDefaultAsync(detail =>
|
||||
detail.CardId == request.Data.CardId &&
|
||||
detail.Pcol1 == 10 &&
|
||||
detail.Pcol2 == request.Data.MusicId &&
|
||||
detail.Pcol3 == 0,
|
||||
cancellationToken);
|
||||
|
||||
if (musicDetail is null)
|
||||
{
|
||||
logger.LogWarning("Attempt to set favorite for non existing music, card id: {CardId}, music id: {MusicId}",
|
||||
request.Data.CardId, request.Data.MusicId);
|
||||
return ServiceResult.Failed<bool>(ServiceError.CustomMessage("Music record not found"));
|
||||
}
|
||||
|
||||
musicDetail.Fcol1 = request.Data.IsFavorite ? 1 : 0;
|
||||
CardDbContext.CardDetails.Update(musicDetail);
|
||||
var count = await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return count == 1 ? new ServiceResult<bool>(true) : ServiceResult.Failed<bool>(ServiceError.DatabaseSaveFailed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Shared.Models;
|
||||
|
||||
namespace Application.Api;
|
||||
|
||||
public record SetPlayOptionCommand(PlayOptionData Data) : IRequestWrapper<bool>;
|
||||
|
||||
public class SetPlayOptionCommandHandler : RequestHandlerBase<SetPlayOptionCommand, bool>
|
||||
{
|
||||
private readonly ILogger<SetPlayOptionCommandHandler> logger;
|
||||
|
||||
public SetPlayOptionCommandHandler(ICardDependencyAggregate aggregate, ILogger<SetPlayOptionCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<bool>> Handle(SetPlayOptionCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var optionDetail1 = await CardDbContext.CardDetails.FirstOrDefaultAsync(detail =>
|
||||
detail.CardId == request.Data.CardId &&
|
||||
detail.Pcol1 == 0 &&
|
||||
detail.Pcol2 == 0 &&
|
||||
detail.Pcol3 == 0,
|
||||
cancellationToken: cancellationToken);
|
||||
var optionDetail2 = await CardDbContext.CardDetails.FirstOrDefaultAsync(detail =>
|
||||
detail.CardId == request.Data.CardId &&
|
||||
detail.Pcol1 == 1 &&
|
||||
detail.Pcol2 == 0 &&
|
||||
detail.Pcol3 == 0,
|
||||
cancellationToken: cancellationToken);
|
||||
|
||||
if (optionDetail1 is null ||
|
||||
optionDetail2 is null)
|
||||
{
|
||||
logger.LogWarning("Attempt to set play options for card id {CardId} failed due to missing data",
|
||||
request.Data.CardId);
|
||||
return ServiceResult.Failed<bool>(ServiceError.CustomMessage("At least one of the play option records not found"));
|
||||
}
|
||||
|
||||
request.Data.OptionPart1.MapFirstOptionDetail(optionDetail1);
|
||||
request.Data.OptionPart2.MapSecondOptionDetail(optionDetail2);
|
||||
|
||||
CardDbContext.CardDetails.Update(optionDetail1);
|
||||
CardDbContext.CardDetails.Update(optionDetail2);
|
||||
|
||||
var count = await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
return count == 1 ? new ServiceResult<bool>(true) : ServiceResult.Failed<bool>(ServiceError.DatabaseSaveFailed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using Application.Common.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Api;
|
||||
|
||||
public record SetPlayerNameCommand(ClientCardDto Card) : IRequestWrapper<bool>;
|
||||
|
||||
public class SetPlayerNameCommandHandler : RequestHandlerBase<SetPlayerNameCommand, bool>
|
||||
{
|
||||
private readonly ILogger<SetPlayerNameCommandHandler> logger;
|
||||
public SetPlayerNameCommandHandler(ICardDependencyAggregate aggregate, ILogger<SetPlayerNameCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<bool>> Handle(SetPlayerNameCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var card = await CardDbContext.CardMains.FirstOrDefaultAsync(card => card.CardId == request.Card.CardId, cancellationToken: cancellationToken);
|
||||
|
||||
if (card is null)
|
||||
{
|
||||
logger.LogWarning("Attempt to set name for a non existing card {CardId}", request.Card.CardId);
|
||||
return ServiceResult.Failed<bool>(ServiceError.UserNotFound);
|
||||
}
|
||||
|
||||
card.PlayerName = request.Card.PlayerName;
|
||||
card.Modified = TimeHelper.CurrentTimeToString();
|
||||
|
||||
CardDbContext.CardMains.Update(card);
|
||||
var count = await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
return count == 1 ? new ServiceResult<bool>(true) : ServiceResult.Failed<bool>(ServiceError.DatabaseSaveFailed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using ChoETL;
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Api;
|
||||
|
||||
public record UnlockAllMusicCommand(long CardId) : IRequestWrapper<bool>;
|
||||
|
||||
public class UnlockAllMusicCommandHandler : RequestHandlerBase<UnlockAllMusicCommand, bool>
|
||||
{
|
||||
private readonly ILogger<UnlockAllMusicCommandHandler> logger;
|
||||
|
||||
public UnlockAllMusicCommandHandler(ICardDependencyAggregate aggregate,
|
||||
ILogger<UnlockAllMusicCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records")]
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0006: Large number of DB commands")]
|
||||
public override async Task<ServiceResult<bool>> Handle(UnlockAllMusicCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = await CardDbContext.CardDetails.AnyAsync(
|
||||
detail => detail.CardId == request.CardId, cancellationToken);
|
||||
|
||||
if (!exists)
|
||||
{
|
||||
logger.LogWarning("Attempt to unlock for card {Card} that does not exist or is empty!", request.CardId);
|
||||
return ServiceResult.Failed<bool>(ServiceError.CustomMessage("Unlock failed"));
|
||||
}
|
||||
|
||||
var unlockables = Config.UnlockRewards
|
||||
.Where(config => config.RewardType == RewardType.Music)
|
||||
.Select(config => new CardDetailDto
|
||||
{
|
||||
CardId = request.CardId,
|
||||
Pcol1 = 10,
|
||||
Pcol2 = config.TargetId,
|
||||
Pcol3 = 0,
|
||||
LastPlayTenpoId = "1337",
|
||||
LastPlayTime = DateTime.Now,
|
||||
ScoreUi2 = 1,
|
||||
ScoreUi6 = 1
|
||||
}.DtoToCardDetail());
|
||||
|
||||
await CardDbContext.CardDetails.UpsertRange(unlockables).RunAsync(cancellationToken);
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new ServiceResult<bool>(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Domain\Domain.csproj" />
|
||||
<ProjectReference Include="..\Shared\Shared.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ChoETL" Version="1.2.1.64" />
|
||||
<PackageReference Include="FlexLabs.EntityFrameworkCore.Upsert" Version="7.0.0" />
|
||||
<PackageReference Include="MediatR" Version="12.1.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.Extensions.Options" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="6.0.0-preview.4.21253.7" />
|
||||
<PackageReference Include="Quartz.AspNetCore" Version="3.6.0" />
|
||||
<PackageReference Include="Riok.Mapperly" Version="2.7.0-next.2" />
|
||||
<PackageReference Include="Throw" Version="1.3.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -0,0 +1,21 @@
|
||||
using Domain.Config;
|
||||
|
||||
namespace Application.Common.Base;
|
||||
|
||||
public abstract class RequestHandlerBase<TIn, TOut>: IRequestHandlerWrapper<TIn, TOut>
|
||||
where TIn : IRequestWrapper<TOut>
|
||||
{
|
||||
protected ICardDbContext CardDbContext { get; }
|
||||
protected IMusicDbContext MusicDbContext { get; }
|
||||
|
||||
protected GameConfig Config { get; }
|
||||
|
||||
public RequestHandlerBase(ICardDependencyAggregate aggregate)
|
||||
{
|
||||
CardDbContext = aggregate.CardDbContext;
|
||||
MusicDbContext = aggregate.MusicDbContext;
|
||||
Config = aggregate.Options.Value;
|
||||
}
|
||||
|
||||
public abstract Task<ServiceResult<TOut>> Handle(TIn request, CancellationToken cancellationToken);
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using MediatR.Pipeline;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Common.Behaviours;
|
||||
|
||||
public class LoggingBehaviour<TRequest> : IRequestPreProcessor<TRequest> where TRequest : notnull
|
||||
{
|
||||
private readonly ILogger<TRequest> logger;
|
||||
|
||||
// ReSharper disable once ContextualLoggerProblem
|
||||
public LoggingBehaviour(ILogger<TRequest> logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public Task Process(TRequest request, CancellationToken cancellationToken)
|
||||
{
|
||||
var requestName = typeof(TRequest).Name;
|
||||
|
||||
logger.LogInformation("Received request: {RequestName}, content: {Request}", requestName, request);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Common.Behaviours;
|
||||
|
||||
public class UnhandledExceptionBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
|
||||
where TRequest : IRequest<TResponse>
|
||||
{
|
||||
private readonly ILogger<TRequest> logger;
|
||||
|
||||
// ReSharper disable once ContextualLoggerProblem
|
||||
public UnhandledExceptionBehaviour(ILogger<TRequest> logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await next();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
var requestName = typeof(TRequest).Name;
|
||||
|
||||
logger.LogError(ex, "Unhandled Exception for Request {Name} {@Request}", requestName, request);
|
||||
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
namespace Application.Common.Exceptions;
|
||||
|
||||
public class CardExistsException : Exception
|
||||
{
|
||||
public CardExistsException(string? message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
using System.Text;
|
||||
using ChoETL;
|
||||
using Throw;
|
||||
|
||||
namespace Application.Common.Extensions;
|
||||
|
||||
public static class XmlSerializationExtensions
|
||||
{
|
||||
public static T DeserializeCardData<T>(this string source) where T : class
|
||||
{
|
||||
using var reader = new ChoXmlReader<T>(new StringReader(source)).WithXPath("/root/data");
|
||||
reader.Configuration.IgnoreFieldValueMode = ChoIgnoreFieldValueMode.Any;
|
||||
|
||||
var result = reader.Read();
|
||||
result.ThrowIfNull();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string SerializeCardData<T>(this T source, string xpath) where T : class
|
||||
{
|
||||
var buffer = new StringBuilder();
|
||||
using (var writer = new ChoXmlWriter<T>(buffer).WithXPath(xpath).UseXmlSerialization())
|
||||
{
|
||||
writer.Configuration.OmitXmlDeclaration = false;
|
||||
writer.Configuration.DoNotEmitXmlNamespace = true;
|
||||
writer.Write(source);
|
||||
}
|
||||
return buffer.ToString();
|
||||
}
|
||||
|
||||
public static string SerializeCardData<T>(this T source) where T : class
|
||||
{
|
||||
var buffer = new StringBuilder();
|
||||
using (var writer = new ChoXmlWriter<T>(buffer).UseXmlSerialization())
|
||||
{
|
||||
writer.Configuration.OmitXmlDeclaration = false;
|
||||
writer.Configuration.DoNotEmitXmlNamespace = true;
|
||||
writer.Configuration.IgnoreRootName = true;
|
||||
writer.Write(source);
|
||||
}
|
||||
return buffer.ToString();
|
||||
}
|
||||
|
||||
public static string SerializeCardDataList<T>(this IEnumerable<T> source, string xpath) where T : class
|
||||
{
|
||||
var buffer = new StringBuilder();
|
||||
using (var writer = new ChoXmlWriter<T>(buffer).WithXPath(xpath).UseXmlSerialization())
|
||||
{
|
||||
writer.Configuration.OmitXmlDeclaration = false;
|
||||
writer.Configuration.DoNotEmitXmlNamespace = true;
|
||||
writer.Write(source);
|
||||
}
|
||||
|
||||
return buffer.ToString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Common.Helpers;
|
||||
|
||||
public static class TimeHelper
|
||||
{
|
||||
public static string CurrentTimeToString()
|
||||
{
|
||||
return DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss");
|
||||
}
|
||||
|
||||
public static string DateToString(DateTime time)
|
||||
{
|
||||
return time.ToString("yyyy/MM/dd hh:mm:ss");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
using System.Reflection;
|
||||
using Application.Common.Behaviours;
|
||||
using Application.Game.Card;
|
||||
using Application.Jobs;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Quartz;
|
||||
|
||||
namespace Application;
|
||||
|
||||
public static class DependencyInjection
|
||||
{
|
||||
public static IServiceCollection AddApplication(this IServiceCollection services, int refreshIntervalHours = 24)
|
||||
{
|
||||
services.AddMediatR(configuration => configuration.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
|
||||
|
||||
services.AddScoped<ICardDependencyAggregate, CardDependencyAggregate>();
|
||||
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>));
|
||||
services.AddQuartz(q =>
|
||||
{
|
||||
q.UseMicrosoftDependencyInjectionJobFactory();
|
||||
|
||||
q.AddJob<UpdatePlayNumRankJob>(options => options.WithIdentity(UpdatePlayNumRankJob.KEY));
|
||||
q.AddTrigger(options =>
|
||||
{
|
||||
options.ForJob(UpdatePlayNumRankJob.KEY)
|
||||
.WithIdentity("UpdatePlayNumRankJob-trigger")
|
||||
.StartNow()
|
||||
.WithSimpleSchedule(x =>
|
||||
{
|
||||
x.WithIntervalInHours(refreshIntervalHours).RepeatForever();
|
||||
});
|
||||
});
|
||||
|
||||
q.AddJob<UpdateGlobalScoreRankJob>(options => options.WithIdentity(UpdateGlobalScoreRankJob.KEY));
|
||||
q.AddTrigger(options =>
|
||||
{
|
||||
options.ForJob(UpdateGlobalScoreRankJob.KEY)
|
||||
.WithIdentity("UpdateGlobalScoreRankJob-trigger")
|
||||
.StartNow()
|
||||
.WithSimpleSchedule(x =>
|
||||
{
|
||||
x.WithIntervalInHours(refreshIntervalHours).RepeatForever();
|
||||
});
|
||||
});
|
||||
|
||||
q.AddJob<UpdateMonthlyScoreRankJob>(options => options.WithIdentity(UpdateMonthlyScoreRankJob.KEY));
|
||||
q.AddTrigger(options =>
|
||||
{
|
||||
options.ForJob(UpdateMonthlyScoreRankJob.KEY)
|
||||
.WithIdentity("UpdateMonthlyScoreRankJob-trigger")
|
||||
.StartNow()
|
||||
.WithSimpleSchedule(x =>
|
||||
{
|
||||
x.WithIntervalInHours(refreshIntervalHours).RepeatForever();
|
||||
});
|
||||
});
|
||||
|
||||
q.AddJob<MaintainNullValuesJob>(options => options.WithIdentity(MaintainNullValuesJob.KEY));
|
||||
q.AddTrigger(options =>
|
||||
{
|
||||
options.ForJob(MaintainNullValuesJob.KEY)
|
||||
.WithIdentity("MaintainNullValuesJob-trigger")
|
||||
.StartNow()
|
||||
.WithSimpleSchedule(x =>
|
||||
{
|
||||
x.WithIntervalInHours(refreshIntervalHours).RepeatForever();
|
||||
});
|
||||
});
|
||||
});
|
||||
services.AddQuartzHostedService(options =>
|
||||
{
|
||||
options.WaitForJobsToComplete = true;
|
||||
});
|
||||
return services;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class AvatarDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "avatar_id")]
|
||||
public int AvatarId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
[DefaultValue("")]
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
[DefaultValue("")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class CardBDatumDto
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "bdata")]
|
||||
public string CardBdata { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "bdata_size")]
|
||||
public int BDataSize { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class CardDetailDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; } = -1;
|
||||
|
||||
public bool ShouldSerializeId()
|
||||
{
|
||||
return Id != -1;
|
||||
}
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pcol1")]
|
||||
public int Pcol1 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pcol2")]
|
||||
public int Pcol2 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pcol3")]
|
||||
public int Pcol3 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_i1")]
|
||||
public long ScoreI1 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_ui1")]
|
||||
public long ScoreUi1 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_ui2")]
|
||||
public long ScoreUi2 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_ui3")]
|
||||
public long ScoreUi3 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_ui4")]
|
||||
public long ScoreUi4 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_ui5")]
|
||||
public long ScoreUi5 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_ui6")]
|
||||
public long ScoreUi6 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_bi1")]
|
||||
public long ScoreBi1 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "last_play_tenpo_id")]
|
||||
[DefaultValue("1337")]
|
||||
public string LastPlayTenpoId { get; set; } = "1337";
|
||||
|
||||
[XmlElement("fcol1")]
|
||||
public int Fcol1 { get; set; }
|
||||
|
||||
[XmlElement("fcol2")]
|
||||
public int Fcol2 { get; set; }
|
||||
|
||||
[XmlElement("fcol3")]
|
||||
public int Fcol3 { get; set; }
|
||||
|
||||
[XmlIgnore]
|
||||
public DateTime LastPlayTime { get; set; } = DateTime.MinValue;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class CardDto
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "player_name")]
|
||||
[DefaultValue("")]
|
||||
public string PlayerName { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("score_i1")]
|
||||
public long ScoreI1 { get; set; }
|
||||
|
||||
[XmlElement("fcol1")]
|
||||
public long Fcol1 { get; set; }
|
||||
|
||||
[XmlElement("fcol2")]
|
||||
public long Fcol2 { get; set; }
|
||||
|
||||
[XmlElement("fcol3")]
|
||||
public long Fcol3 { get; set; }
|
||||
|
||||
[XmlElement("achieve_status")]
|
||||
[DefaultValue("")]
|
||||
public string AchieveStatus { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("created")]
|
||||
[DefaultValue("")]
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
[DefaultValue("")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Xml.Serialization;
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Coin
|
||||
public class CoinDto
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
@@ -17,8 +15,8 @@ public class Coin
|
||||
public int MonthlyCoins { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using System.Xml.Serialization;
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Item : Record, IIdModel, ICardIdModel
|
||||
public class ItemDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
@@ -24,14 +25,4 @@ public class Item : Record, IIdModel, ICardIdModel
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
|
||||
public void SetId(int id)
|
||||
{
|
||||
ItemId = id;
|
||||
}
|
||||
|
||||
public void SetCardId(long cardId)
|
||||
{
|
||||
CardId = cardId;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class MusicAouDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "music_id")]
|
||||
public int MusicId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class MusicDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement("music_id")]
|
||||
public int MusicId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "title")]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "artist")]
|
||||
public string Artist { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "release_date")]
|
||||
public string ReleaseDate { get; set; } = "2013-01-01 08:00:00";
|
||||
|
||||
[XmlElement(ElementName = "end_date")]
|
||||
public string EndDate { get; set; } = "2030-01-01 08:00:00";
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
|
||||
[XmlElement("calc_flag")]
|
||||
public int CalcFlag { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class MusicExtraDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "music_id")]
|
||||
public int MusicId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class NavigatorDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "navigator_id")]
|
||||
public int NavigatorId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class OnlineMatchEntryDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "machine_id")]
|
||||
public long MachineId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "event_id")]
|
||||
public long EventId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "matching_id")]
|
||||
public long MatchId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "entry_no")]
|
||||
public long EntryId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "entry_start")]
|
||||
public string StartTime { get; set; } = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
[XmlElement(ElementName = "status")]
|
||||
public long Status { get; set; } = 1;
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "player_name")]
|
||||
public string PlayerName { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "avatar_id")]
|
||||
public long AvatarId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "title_id")]
|
||||
public long TitleId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "class_id")]
|
||||
public long ClassId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "group_id")]
|
||||
public long GroupId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "tenpo_id")]
|
||||
public long TenpoId { get; set; } = 1337;
|
||||
|
||||
[XmlElement(ElementName = "tenpo_name")]
|
||||
public string TenpoName { get; set; } = "GCLocalServer";
|
||||
|
||||
[XmlElement(ElementName = "pref_id")]
|
||||
public long PrefId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pref")]
|
||||
public string Pref { get; set; } = "nesys";
|
||||
|
||||
[XmlElement(ElementName = "message_id")]
|
||||
public long MessageId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "matching_timeout")]
|
||||
public long MatchTimeout { get; set; } = 99;
|
||||
|
||||
[XmlElement(ElementName = "matching_wait_time")]
|
||||
public long MatchWaitTime { get; set; } = 10;
|
||||
|
||||
[XmlElement(ElementName = "matching_remaining_time")]
|
||||
public long MatchRemainingTime { get; set; } = 89;
|
||||
}
|
||||
+6
-9
@@ -1,9 +1,6 @@
|
||||
using System.Xml.Serialization;
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
[XmlType("record")]
|
||||
public class PlayNumRankRecord
|
||||
public class PlayNumRankDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
@@ -26,9 +23,9 @@ public class PlayNumRankRecord
|
||||
[XmlElement("score_bi1")]
|
||||
public int ScoreBi1 { get; set; }
|
||||
|
||||
[XmlElement("title")]
|
||||
public string? Title { get; set; }
|
||||
[XmlElement("title")]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("artist")]
|
||||
public string? Artist { get; set; }
|
||||
[XmlElement("artist")]
|
||||
public string Artist { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class ScoreRankDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "player_name")]
|
||||
public string PlayerName { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "rank")]
|
||||
public long Rank { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "rank2")]
|
||||
public long Rank2 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_bi1")]
|
||||
public long TotalScore { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "score_i1")]
|
||||
public int AvatarId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "fcol2")]
|
||||
public long TitleId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "fcol1")]
|
||||
public long Fcol1 { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pref_id")]
|
||||
public int PrefId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "pref")]
|
||||
public string Pref { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "area_id")]
|
||||
public int AreaId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "area")]
|
||||
public string Area { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "last_play_tenpo_id")]
|
||||
public int LastPlayTenpoId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "tenpo_name")]
|
||||
public string TenpoName { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement(ElementName = "title")]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -1,8 +1,6 @@
|
||||
using System.Xml.Serialization;
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class Session
|
||||
public class SessionDto
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class SkinDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "skin_id")]
|
||||
public int SkinId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class SoundEffectDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "sound_effect_id")]
|
||||
public int SoundEffectId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
public class TitleDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "title_id")]
|
||||
public int TitleId { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("new_flag")]
|
||||
public int NewFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
}
|
||||
+2
-4
@@ -1,8 +1,6 @@
|
||||
using System.Xml.Serialization;
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class TotalTrophy
|
||||
public class TotalTrophyDto
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
+9
-8
@@ -1,9 +1,10 @@
|
||||
using System.Xml.Serialization;
|
||||
namespace Application.Dto.Game;
|
||||
|
||||
namespace GCLocalServerRewrite.models;
|
||||
|
||||
public class UnlockKeynum : Record
|
||||
public class UnlockKeyNumDto
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
@@ -20,14 +21,14 @@ public class UnlockKeynum : Record
|
||||
public int ExpiredFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; } = 1;
|
||||
public int UseFlag { get; set; }
|
||||
|
||||
[XmlElement("cash_flag")]
|
||||
public int CashFlag { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = "1";
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = "1";
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Domain.Config;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Application.Game.Card;
|
||||
|
||||
public class CardDependencyAggregate : ICardDependencyAggregate
|
||||
{
|
||||
public CardDependencyAggregate(ICardDbContext cardDbContext, IMusicDbContext musicDbContext, IOptions<GameConfig> options)
|
||||
{
|
||||
CardDbContext = cardDbContext;
|
||||
MusicDbContext = musicDbContext;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
public ICardDbContext CardDbContext { get; }
|
||||
public IMusicDbContext MusicDbContext { get; }
|
||||
|
||||
public IOptions<GameConfig> Options { get; }
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Application.Game.Card;
|
||||
|
||||
public class CardRequest
|
||||
{
|
||||
[ModelBinder(Name = "mac_addr")]
|
||||
public string Mac { get; set; } = string.Empty;
|
||||
|
||||
[ModelBinder(Name = "cmd_str")]
|
||||
public int CardCommandType { get; set; }
|
||||
|
||||
[ModelBinder(Name = "type")]
|
||||
public int CardRequestType { get; set; }
|
||||
|
||||
[ModelBinder(Name = "card_no")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[ModelBinder(Name = "tenpo_id")]
|
||||
public string TenpoId { get; set; } = "1337";
|
||||
|
||||
[ModelBinder(Name = "data")]
|
||||
public string Data { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Application.Common.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Management;
|
||||
|
||||
public record CardRegisterCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class RegisterCommandHandler : RequestHandlerBase<CardRegisterCommand, string>
|
||||
{
|
||||
private readonly ILogger<RegisterCommandHandler> logger;
|
||||
public RegisterCommandHandler(ICardDependencyAggregate aggregate, ILogger<RegisterCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(CardRegisterCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = CardDbContext.CardMains.Any(card => card.CardId == request.CardId);
|
||||
if (exists)
|
||||
{
|
||||
return ServiceResult.Failed<string>(ServiceError.CustomMessage($"Card {request.CardId} already exists!"));
|
||||
}
|
||||
|
||||
var card = request.Data.DeserializeCardData<CardDto>().CardDtoToCardMain();
|
||||
card.CardId = request.CardId;
|
||||
card.Created = TimeHelper.CurrentTimeToString();
|
||||
card.Modified = card.Created;
|
||||
logger.LogInformation("New card {{Id: {Id}, Player Name: {Name}}} registered", card.CardId, card.PlayerName);
|
||||
CardDbContext.CardMains.Add(card);
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new ServiceResult<string>(request.Data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
namespace Application.Game.Card.Management;
|
||||
|
||||
public record CardReissueCommand(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReissueCommandHandler : RequestHandlerBase<CardReissueCommand, string>
|
||||
{
|
||||
public ReissueCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(CardReissueCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Support actual reissue
|
||||
return Task.FromResult(ServiceResult.Failed<string>(ServiceError.NotReissue));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
using Application.Common.Helpers;
|
||||
using Domain.Entities;
|
||||
using Microsoft.EntityFrameworkCore.Query;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.OnlineMatching;
|
||||
|
||||
public record StartOnlineMatchingCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class StartOnlineMatchingCommandHandler : RequestHandlerBase<StartOnlineMatchingCommand, string>
|
||||
{
|
||||
private const int MAX_RETRY = 5;
|
||||
|
||||
private const string MATCH_ENRTY_XPATH = "/root/online_matching";
|
||||
|
||||
private const string RECORD_XPATH = $"{MATCH_ENRTY_XPATH}/record";
|
||||
|
||||
private readonly ILogger<StartOnlineMatchingCommandHandler> logger;
|
||||
|
||||
public StartOnlineMatchingCommandHandler(ICardDependencyAggregate aggregate, ILogger<StartOnlineMatchingCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(StartOnlineMatchingCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var dto = request.Data.DeserializeCardData<OnlineMatchEntryDto>();
|
||||
dto.CardId = request.CardId;
|
||||
dto.StartTime = TimeHelper.CurrentTimeToString();
|
||||
dto.MatchTimeout = 20;
|
||||
dto.MatchRemainingTime = 5;
|
||||
dto.MatchWaitTime = 5;
|
||||
dto.Status = 1;
|
||||
var entry = dto.DtoToOnlineMatchEntry();
|
||||
|
||||
var matchId = await CardDbContext.OnlineMatches.CountAsync(cancellationToken);
|
||||
for (int i = 0; i < MAX_RETRY; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var onlineMatch = await CardDbContext.OnlineMatches
|
||||
.Include(match => match.Entries)
|
||||
.FirstOrDefaultAsync(match => match.IsOpen && match.Entries.Count < 4, cancellationToken);
|
||||
string result;
|
||||
if (onlineMatch is not null)
|
||||
{
|
||||
entry.EntryId = onlineMatch.Entries.Count;
|
||||
onlineMatch.Entries.Add(entry);
|
||||
onlineMatch.Guid = Guid.NewGuid();
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
result = onlineMatch.Entries.Select((matchEntry, id) =>
|
||||
{
|
||||
var entryDto = matchEntry.OnlineMatchEntryToDto();
|
||||
entryDto.Id = id;
|
||||
return entryDto;
|
||||
}).SerializeCardDataList(RECORD_XPATH);
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
|
||||
entry.EntryId = 0;
|
||||
onlineMatch = new OnlineMatch
|
||||
{
|
||||
MatchId = matchId,
|
||||
Entries = { entry },
|
||||
Guid = Guid.NewGuid(),
|
||||
IsOpen = true
|
||||
};
|
||||
CardDbContext.OnlineMatches.Add(onlineMatch);
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
result = onlineMatch.Entries.Select((matchEntry, id) =>
|
||||
{
|
||||
var entryDto = matchEntry.OnlineMatchEntryToDto();
|
||||
entryDto.Id = id;
|
||||
return entryDto;
|
||||
}).SerializeCardDataList(RECORD_XPATH);
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
logger.LogWarning(e, "Concurrent DB update when starting online match");
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
when (e.InnerException != null
|
||||
&& e.InnerException.Message.StartsWith("Cannot insert duplicate key row in object"))
|
||||
{
|
||||
logger.LogWarning(e, "Concurrent insert when starting online match");
|
||||
}
|
||||
}
|
||||
logger.LogError("Cannot update DB after {Number} trials for online match!", MAX_RETRY);
|
||||
return ServiceResult.Failed<string>(ServiceError.DatabaseSaveFailed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.OnlineMatching;
|
||||
|
||||
public record UpdateOnlineMatchingCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class UpdateOnlineMatchingCommandHandler : RequestHandlerBase<UpdateOnlineMatchingCommand, string>
|
||||
{
|
||||
private readonly ILogger<UpdateOnlineMatchingCommandHandler> logger;
|
||||
|
||||
private const string MATCH_ENRTY_XPATH = "/root/online_matching";
|
||||
|
||||
private const string RECORD_XPATH = $"{MATCH_ENRTY_XPATH}/record";
|
||||
|
||||
private const int MAX_RETRY = 5;
|
||||
|
||||
public UpdateOnlineMatchingCommandHandler(ICardDependencyAggregate aggregate,
|
||||
ILogger<UpdateOnlineMatchingCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0006: Large number of DB commands")]
|
||||
public override async Task<ServiceResult<string>> Handle(UpdateOnlineMatchingCommand request,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var data = request.Data.DeserializeCardData<OnlineMatchEntryDto>();
|
||||
for (int i = 0; i < MAX_RETRY; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
var match = await CardDbContext.OnlineMatches
|
||||
.Include(onlineMatch => onlineMatch.Entries)
|
||||
.FirstOrDefaultAsync(onlineMatch =>
|
||||
onlineMatch.MatchId == data.MatchId, cancellationToken);
|
||||
if (match is null)
|
||||
{
|
||||
logger.LogWarning("Match id {MatchId} not found", data.MatchId);
|
||||
return ServiceResult.Failed<string>(ServiceError.CustomMessage("Match with this id does not exist"));
|
||||
}
|
||||
|
||||
match.Entries.ForEach(entry =>
|
||||
{
|
||||
if (entry.CardId == request.CardId)
|
||||
{
|
||||
entry.MessageId = data.MessageId;
|
||||
}
|
||||
|
||||
entry.MatchRemainingTime--;
|
||||
});
|
||||
|
||||
if (match.Entries.TrueForAll(entry => entry.MatchRemainingTime <= 0))
|
||||
{
|
||||
match.Entries.ForEach(entry => entry.Status = 3);
|
||||
match.IsOpen = false;
|
||||
}
|
||||
|
||||
match.Guid = Guid.NewGuid();
|
||||
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
var result = match.Entries.Select((matchEntry, id) =>
|
||||
{
|
||||
var entryDto = matchEntry.OnlineMatchEntryToDto();
|
||||
entryDto.Id = id;
|
||||
return entryDto;
|
||||
}).SerializeCardDataList(RECORD_XPATH);
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
catch (DbUpdateConcurrencyException e)
|
||||
{
|
||||
logger.LogWarning(e, "Concurrent DB update when starting online match");
|
||||
}
|
||||
}
|
||||
logger.LogError("Cannot update DB after {Number} trials for online match!", MAX_RETRY);
|
||||
return ServiceResult.Failed<string>(ServiceError.DatabaseSaveFailed);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Application.Game.Card.OnlineMatching;
|
||||
|
||||
public record UploadOnlineMatchingResultCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class UploadOnlineMatchingResultCommandHandler : RequestHandlerBase<UploadOnlineMatchingResultCommand, string>
|
||||
{
|
||||
private const string XPATH = "/root/online_battle_result";
|
||||
|
||||
public UploadOnlineMatchingResultCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(UploadOnlineMatchingResultCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new OnlineMatchingResult { Status = 1 }.SerializeCardData(XPATH);
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
|
||||
public class OnlineMatchingResult
|
||||
{
|
||||
[XmlElement(ElementName = "status")]
|
||||
public int Status { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadAllCardDetailsQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadAllDetailsQueryHandler : RequestHandlerBase<ReadAllCardDetailsQuery, string>
|
||||
{
|
||||
private const string CARD_DETAILS_XPATH = "/root/card_detail";
|
||||
private const string RECORD_XPATH = $"{CARD_DETAILS_XPATH}/record";
|
||||
|
||||
private readonly ILogger<ReadAllDetailsQueryHandler> logger;
|
||||
|
||||
public ReadAllDetailsQueryHandler(ICardDependencyAggregate aggregate, ILogger<ReadAllDetailsQueryHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records",
|
||||
Justification = "Card details will return all records by design, which results in a large number of DB records")]
|
||||
public override async Task<ServiceResult<string>> Handle(ReadAllCardDetailsQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = await CardDbContext.CardMains.AnyAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
logger.LogWarning("Card id: {CardId} does not exist!", request.CardId);
|
||||
return ServiceResult.Failed<string>(
|
||||
new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered));
|
||||
}
|
||||
|
||||
var cardDetails = await CardDbContext.CardDetails
|
||||
.Where(detail => detail.CardId == request.CardId)
|
||||
.ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
string result;
|
||||
if (cardDetails.Count == 0)
|
||||
{
|
||||
result = new object().SerializeCardData(CARD_DETAILS_XPATH);
|
||||
}
|
||||
else
|
||||
{
|
||||
var dtoList = cardDetails.Select((detail, i) =>
|
||||
{
|
||||
var dto = detail.CardDetailToDto();
|
||||
dto.Id = i;
|
||||
return dto;
|
||||
});
|
||||
result = dtoList.SerializeCardDataList(RECORD_XPATH);
|
||||
}
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadAvatarQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadAvatarQueryHandler : RequestHandlerBase<ReadAvatarQuery, string>
|
||||
{
|
||||
private const string AVATAR_XPATH = "/root/avatar/record";
|
||||
|
||||
public ReadAvatarQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadAvatarQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = Config.AvatarCount;
|
||||
var list = new List<AvatarDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var avatar = new AvatarDto
|
||||
{
|
||||
Id = i,
|
||||
CardId = request.CardId,
|
||||
AvatarId = i + 1,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2013-01-01 08:00:00",
|
||||
NewFlag = 0,
|
||||
UseFlag = 1
|
||||
};
|
||||
list.Add(avatar);
|
||||
}
|
||||
|
||||
var result = list.SerializeCardDataList(AVATAR_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadCardBDataQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadBDataQueryHandler : RequestHandlerBase<ReadCardBDataQuery, string>
|
||||
{
|
||||
private const string CARD_BDATA_XPATH = "/root/card_bdata";
|
||||
|
||||
private readonly ILogger<ReadBDataQueryHandler> logger;
|
||||
|
||||
public ReadBDataQueryHandler(ICardDependencyAggregate aggregate, ILogger<ReadBDataQueryHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(ReadCardBDataQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = await CardDbContext.CardMains.AnyAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
logger.LogWarning("Card id: {CardId} does not exist!", request.CardId);
|
||||
return ServiceResult.Failed<string>(
|
||||
new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered));
|
||||
}
|
||||
|
||||
var bdata = await CardDbContext.CardBdata.FirstOrDefaultAsync(
|
||||
card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
|
||||
var result = bdata?.CardBDatumToDto().SerializeCardData(CARD_BDATA_XPATH)
|
||||
?? new object().SerializeCardData(CARD_BDATA_XPATH);
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadCardDetailQuery(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadDetailQueryHandler : RequestHandlerBase<ReadCardDetailQuery, string>
|
||||
{
|
||||
private const string CARD_DETAILS_XPATH = "/root/card_detail";
|
||||
|
||||
private readonly ILogger<ReadDetailQueryHandler> logger;
|
||||
|
||||
public ReadDetailQueryHandler(ICardDependencyAggregate aggregate, ILogger<ReadDetailQueryHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(ReadCardDetailQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = await CardDbContext.CardMains.AnyAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
logger.LogWarning("Card id: {CardId} does not exist!", request.CardId);
|
||||
return ServiceResult.Failed<string>(
|
||||
new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered));
|
||||
}
|
||||
|
||||
var queryCondition = request.Data.DeserializeCardData<CardDetailDto>();
|
||||
var detail = await CardDbContext.CardDetails.FirstOrDefaultAsync(cardDetail =>
|
||||
cardDetail.CardId == request.CardId &&
|
||||
cardDetail.Pcol1 == queryCondition.Pcol1 &&
|
||||
cardDetail.Pcol2 == queryCondition.Pcol2 &&
|
||||
cardDetail.Pcol3 == queryCondition.Pcol3, cancellationToken: cancellationToken);
|
||||
|
||||
var dto = detail?.CardDetailToDto();
|
||||
|
||||
var result = dto?.SerializeCardData(CARD_DETAILS_XPATH) ??
|
||||
new object().SerializeCardData(CARD_DETAILS_XPATH);
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
public record ReadCardQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadQueryHandler : RequestHandlerBase<ReadCardQuery, string>
|
||||
{
|
||||
private readonly ILogger<ReadQueryHandler> logger;
|
||||
|
||||
public ReadQueryHandler(ICardDependencyAggregate aggregate, ILogger<ReadQueryHandler> logger) : base(aggregate) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(ReadCardQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var card = await CardDbContext.CardMains.FirstOrDefaultAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
if (card is null)
|
||||
{
|
||||
logger.LogInformation("Card of id: {CardId} does not exist! Registering a new one...", request.CardId);
|
||||
return ServiceResult.Failed<string>(new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered));
|
||||
}
|
||||
|
||||
var result = card.CardMainToCardDto().SerializeCardData("/root/card");
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadCoinQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadCoinQueryHandler : RequestHandlerBase<ReadCoinQuery, string>
|
||||
{
|
||||
private const string COIN_XPATH = "/root/coin";
|
||||
|
||||
public ReadCoinQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadCoinQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var dto = new CoinDto
|
||||
{
|
||||
CardId = request.CardId,
|
||||
CurrentCoins = 900000,
|
||||
MonthlyCoins = 900000,
|
||||
TotalCoins = 900000,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2013-01-01 08:00:00"
|
||||
};
|
||||
|
||||
var result = dto.SerializeCardData(COIN_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadCondQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadCondQueryHandler : RequestHandlerBase<ReadCondQuery, string>
|
||||
{
|
||||
private const string COND_XPATH = "/root/cond";
|
||||
|
||||
public ReadCondQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadCondQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new object().SerializeCardData(COND_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadEventRewardQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadEventRewardQueryHandler : RequestHandlerBase<ReadEventRewardQuery, string>
|
||||
{
|
||||
private const string EVENT_REWARD_XPATH = "/root/event_reward";
|
||||
|
||||
public ReadEventRewardQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadEventRewardQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new object().SerializeCardData(EVENT_REWARD_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadGetMessageQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadGetMessageQueryHandler : RequestHandlerBase<ReadGetMessageQuery, string>
|
||||
{
|
||||
private const string GET_MESSAGE_XPATH = "/root/get_message";
|
||||
|
||||
public ReadGetMessageQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadGetMessageQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var result = new object().SerializeCardData(GET_MESSAGE_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
public record ReadItemQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadItemQueryHandler : RequestHandlerBase<ReadItemQuery, string>
|
||||
{
|
||||
private const string ITEM_XPATH = "/root/item/record";
|
||||
|
||||
public ReadItemQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadItemQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = Config.ItemCount;
|
||||
var list = new List<ItemDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var item = new ItemDto
|
||||
{
|
||||
Id = i,
|
||||
CardId = request.CardId,
|
||||
ItemId = i + 1,
|
||||
ItemNum = 90,
|
||||
Created = "2013-01-01",
|
||||
Modified = "2013-01-01",
|
||||
NewFlag = 0,
|
||||
UseFlag = 1
|
||||
};
|
||||
list.Add(item);
|
||||
}
|
||||
|
||||
var result = list.SerializeCardDataList(ITEM_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadMusicAouQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadMusicAouQueryHandler : RequestHandlerBase<ReadMusicAouQuery, string>
|
||||
{
|
||||
private const string MUSIC_AOU_XPATH = "/root/music_aou";
|
||||
|
||||
private const string RECORD_XPATH = $"{MUSIC_AOU_XPATH}/record";
|
||||
|
||||
public ReadMusicAouQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records",
|
||||
Justification = "To return all musics, the whole table need to be returned")]
|
||||
public override async Task<ServiceResult<string>> Handle(ReadMusicAouQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var musics = await MusicDbContext.MusicAous.ToListAsync(cancellationToken: cancellationToken);
|
||||
var dtoList = musics.Select((aou, i) =>
|
||||
{
|
||||
var dto = aou.MusicAouToDto();
|
||||
dto.Id = i;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var result = dtoList.Count == 0 ? new object().SerializeCardData(MUSIC_AOU_XPATH)
|
||||
: dtoList.SerializeCardDataList(RECORD_XPATH);
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadMusicExtraQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadMusicExtraQueryHandler : RequestHandlerBase<ReadMusicExtraQuery, string>
|
||||
{
|
||||
private const string MUSIC_EXTRA_XPATH = "/root/music_extra";
|
||||
|
||||
private const string RECORD_XPATH = $"{MUSIC_EXTRA_XPATH}/record";
|
||||
|
||||
public ReadMusicExtraQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(ReadMusicExtraQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var musics = await MusicDbContext.MusicExtras.ToListAsync(cancellationToken: cancellationToken);
|
||||
var dtoList = musics.Select((aou, i) =>
|
||||
{
|
||||
var dto = aou.MusicExtraToDto();
|
||||
dto.Id = i;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var result = dtoList.Count == 0 ? new object().SerializeCardData(MUSIC_EXTRA_XPATH)
|
||||
: dtoList.SerializeCardDataList(RECORD_XPATH);
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadMusicQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadMusicQueryHandler : RequestHandlerBase<ReadMusicQuery, string>
|
||||
{
|
||||
private const string MUSIC_XPATH = "/root/music/record";
|
||||
public ReadMusicQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records",
|
||||
Justification = "To return all musics, the whole table need to be returned")]
|
||||
public override async Task<ServiceResult<string>> Handle(ReadMusicQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var musics = await MusicDbContext.MusicUnlocks.ToListAsync(cancellationToken: cancellationToken);
|
||||
var dtoList = musics.Select((unlock, i) =>
|
||||
{
|
||||
var dto = unlock.MusicToDto();
|
||||
dto.Id = i;
|
||||
return dto;
|
||||
});
|
||||
|
||||
var result = dtoList.SerializeCardDataList(MUSIC_XPATH);
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadNavigatorQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadNavigatorQueryHandler : RequestHandlerBase<ReadNavigatorQuery, string>
|
||||
{
|
||||
private const string NAVIGATOR_XPATH = "/root/navigator/record";
|
||||
|
||||
public ReadNavigatorQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadNavigatorQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = Config.NavigatorCount;
|
||||
|
||||
var list = new List<NavigatorDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var navigator = new NavigatorDto
|
||||
{
|
||||
Id = i,
|
||||
CardId = request.CardId,
|
||||
NavigatorId = i + 1,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2013-01-01 08:00:00",
|
||||
NewFlag = 0,
|
||||
UseFlag = 1
|
||||
};
|
||||
list.Add(navigator);
|
||||
}
|
||||
|
||||
var result = list.SerializeCardDataList(NAVIGATOR_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadSkinQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadSkinQueryHandler : RequestHandlerBase<ReadSkinQuery, string>
|
||||
{
|
||||
private const string SKIN_XPATH = "/root/skin/record";
|
||||
|
||||
public ReadSkinQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadSkinQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = Config.SkinCount;
|
||||
|
||||
var list = new List<SkinDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var skin = new SkinDto
|
||||
{
|
||||
Id = i,
|
||||
CardId = request.CardId,
|
||||
SkinId = i + 1,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2013-01-01 08:00:00",
|
||||
NewFlag = 0,
|
||||
UseFlag = 1
|
||||
};
|
||||
list.Add(skin);
|
||||
}
|
||||
|
||||
var result = list.SerializeCardDataList(SKIN_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadSoundEffectQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadSoundEffectQueryHandler : RequestHandlerBase<ReadSoundEffectQuery, string>
|
||||
{
|
||||
private const string SOUND_EFFECT_XPATH = "/root/sound_effect/record";
|
||||
public ReadSoundEffectQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadSoundEffectQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = Config.SeCount;
|
||||
|
||||
var list = new List<SoundEffectDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var soundEffect = new SoundEffectDto
|
||||
{
|
||||
Id = i,
|
||||
CardId = request.CardId,
|
||||
SoundEffectId = i + 1,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2013-01-01 08:00:00",
|
||||
NewFlag = 0,
|
||||
UseFlag = 1
|
||||
};
|
||||
list.Add(soundEffect);
|
||||
}
|
||||
|
||||
var result = list.SerializeCardDataList(SOUND_EFFECT_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadTitleQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadTitleQueryHandler : RequestHandlerBase<ReadTitleQuery, string>
|
||||
{
|
||||
private const string TITLE_XPATH = "/root/title/record";
|
||||
|
||||
public ReadTitleQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadTitleQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var count = Config.TitleCount;
|
||||
|
||||
var list = new List<TitleDto>();
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var soundEffect = new TitleDto
|
||||
{
|
||||
Id = i,
|
||||
CardId = request.CardId,
|
||||
TitleId = i + 1,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2013-01-01 08:00:00",
|
||||
NewFlag = 0,
|
||||
UseFlag = 1
|
||||
};
|
||||
list.Add(soundEffect);
|
||||
}
|
||||
|
||||
var result = list.SerializeCardDataList(TITLE_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadTotalTrophyQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadTotalTrophyQueryHandler : RequestHandlerBase<ReadTotalTrophyQuery, string>
|
||||
{
|
||||
private const string TOTAL_TROPHY_XPATH = "/root/total_trophy";
|
||||
|
||||
public ReadTotalTrophyQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadTotalTrophyQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var trophy = new TotalTrophyDto
|
||||
{
|
||||
CardId = request.CardId,
|
||||
TrophyNum = 8
|
||||
};
|
||||
|
||||
var result = trophy.SerializeCardData(TOTAL_TROPHY_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadUnlockKeynumQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadUnlockKeynumQueryHandler : RequestHandlerBase<ReadUnlockKeynumQuery, string>
|
||||
{
|
||||
private const string UNLOCK_KEYNUM_XPATH = "/root/unlock_keynum/record";
|
||||
public ReadUnlockKeynumQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadUnlockKeynumQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var unlockables = Config.UnlockRewards;
|
||||
var list = unlockables.Select((unlockable, index) => new UnlockKeyNumDto
|
||||
{
|
||||
Id = index,
|
||||
CardId = request.CardId,
|
||||
RewardId = unlockable.RewardId,
|
||||
KeyNum = 0,
|
||||
RewardCount = 0,
|
||||
CashFlag = 0,
|
||||
ExpiredFlag = 0,
|
||||
UseFlag = 1,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2020-01-01 08:00:00"
|
||||
})
|
||||
.ToList();
|
||||
var result = list.SerializeCardDataList(UNLOCK_KEYNUM_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
namespace Application.Game.Card.Read;
|
||||
|
||||
|
||||
public record ReadUnlockRewardQuery(long CardId) : IRequestWrapper<string>;
|
||||
|
||||
public class ReadUnlockRewardQueryHandler : RequestHandlerBase<ReadUnlockRewardQuery, string>
|
||||
{
|
||||
private const string UNLOCK_REWARD_XPATH = "/root/unlock_reward/record";
|
||||
|
||||
public ReadUnlockRewardQueryHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(ReadUnlockRewardQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var config = Config.UnlockRewards;
|
||||
var list = config.Select((rewardConfig, i) => new UnlockRewardModel
|
||||
{
|
||||
Id = i,
|
||||
CardId = request.CardId,
|
||||
RewardId = rewardConfig.RewardId,
|
||||
RewardType = (int)rewardConfig.RewardType,
|
||||
TargetId = rewardConfig.TargetId,
|
||||
TargetNum = rewardConfig.TargetNum,
|
||||
KeyNum = rewardConfig.KeyNum,
|
||||
DisplayFlag = 1,
|
||||
UseFlag = 1,
|
||||
LimitedFlag = 0,
|
||||
Created = "2013-01-01 08:00:00",
|
||||
Modified = "2013-01-01 08:00:00",
|
||||
OpenDate = "2013-01-01",
|
||||
CloseDate = "2030-01-01",
|
||||
OpenTime = "00:00:01",
|
||||
CloseTime = "23:59:59",
|
||||
OpenUnixTime = new DateTimeOffset(2013, 1, 1, 0, 0, 1, TimeSpan.Zero).ToUnixTimeSeconds(),
|
||||
CloseUnixTime = new DateTimeOffset(2030, 1, 1, 23, 59, 59, TimeSpan.Zero).ToUnixTimeSeconds()
|
||||
});
|
||||
|
||||
var result = list.SerializeCardDataList(UNLOCK_REWARD_XPATH);
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(result));
|
||||
}
|
||||
}
|
||||
|
||||
public class UnlockRewardModel
|
||||
{
|
||||
[XmlAttribute(AttributeName = "id")]
|
||||
public int Id { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "reward_id")]
|
||||
public int RewardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "reward_type")]
|
||||
public int RewardType { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "open_date")]
|
||||
public string OpenDate { get; set; } = "2013-01-01";
|
||||
|
||||
[XmlElement(ElementName = "close_date")]
|
||||
public string CloseDate { get; set; } = "2030-01-01";
|
||||
|
||||
[XmlElement(ElementName = "open_time")]
|
||||
public string OpenTime { get; set; } = "00:00:01";
|
||||
|
||||
[XmlElement(ElementName = "close_time")]
|
||||
public string CloseTime { get; set; } = "23:59:59";
|
||||
|
||||
[XmlElement(ElementName = "target_id")]
|
||||
public int TargetId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "target_num")]
|
||||
public int TargetNum { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "key_num")]
|
||||
public int KeyNum { get; set; }
|
||||
|
||||
[XmlElement("display_flag")]
|
||||
public int DisplayFlag { get; set; }
|
||||
|
||||
[XmlElement("use_flag")]
|
||||
public int UseFlag { get; set; }
|
||||
|
||||
[XmlElement("limited_flag")]
|
||||
public int LimitedFlag { get; set; }
|
||||
|
||||
[XmlElement("open_unixtime")]
|
||||
public long OpenUnixTime { get; set; }
|
||||
|
||||
[XmlElement("close_unixtime")]
|
||||
public long CloseUnixTime { get; set; }
|
||||
|
||||
[XmlElement("created")]
|
||||
public string Created { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("modified")]
|
||||
public string Modified { get; set; } = string.Empty;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Application.Game.Card.Session;
|
||||
|
||||
public record GetSessionCommand(long CardId, string Mac) : IRequestWrapper<string>;
|
||||
|
||||
public class GetSessionCommandHandler : RequestHandlerBase<GetSessionCommand, string>
|
||||
{
|
||||
private const string SESSION_XPATH = "/root/session";
|
||||
|
||||
public GetSessionCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate)
|
||||
{
|
||||
}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(GetSessionCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var session = new SessionDto
|
||||
{
|
||||
CardId = request.CardId,
|
||||
Mac = request.Mac,
|
||||
PlayerId = 1,
|
||||
Expires = 9999,
|
||||
SessionId = "12345678901234567890123456789012"
|
||||
};
|
||||
return Task.FromResult(new ServiceResult<string>(session.SerializeCardData(SESSION_XPATH)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteAvatarCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteAvatarCommandHandler : RequestHandlerBase<WriteAvatarCommand, string>
|
||||
{
|
||||
public WriteAvatarCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteAvatarCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using Domain.Entities;
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteCardBDataCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteBDataCommandHandler : RequestHandlerBase<WriteCardBDataCommand, string>
|
||||
{
|
||||
private readonly ILogger<WriteBDataCommandHandler> logger;
|
||||
|
||||
public WriteBDataCommandHandler(ICardDependencyAggregate aggregate, ILogger<WriteBDataCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(WriteCardBDataCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = await CardDbContext.CardMains.AnyAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
logger.LogWarning("Card id: {CardId} does not exist!", request.CardId);
|
||||
return ServiceResult.Failed<string>(
|
||||
new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered));
|
||||
}
|
||||
|
||||
var dto = request.Data.DeserializeCardData<CardBDatumDto>();
|
||||
var data = dto.DtoToCardBDatum();
|
||||
data.CardId = request.CardId;
|
||||
await CardDbContext.CardBdata.Upsert(data).RunAsync(cancellationToken);
|
||||
|
||||
var cardPlayCount = await CardDbContext.CardPlayCounts
|
||||
.FirstOrDefaultAsync(count => count.CardId == request.CardId, cancellationToken);
|
||||
if (cardPlayCount is null)
|
||||
{
|
||||
cardPlayCount = new CardPlayCount
|
||||
{
|
||||
CardId = request.CardId,
|
||||
PlayCount = 0,
|
||||
LastPlayedTime = DateTime.Now
|
||||
};
|
||||
}
|
||||
cardPlayCount.PlayCount++;
|
||||
cardPlayCount.LastPlayedTime = DateTime.Now;
|
||||
await CardDbContext.CardPlayCounts.Upsert(cardPlayCount).RunAsync(cancellationToken);
|
||||
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new ServiceResult<string>(request.Data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Application.Common.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteCardCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteCommandHandler : RequestHandlerBase<WriteCardCommand, string>
|
||||
{
|
||||
private readonly ILogger<WriteCommandHandler> logger;
|
||||
|
||||
public WriteCommandHandler(ICardDependencyAggregate aggregate, ILogger<WriteCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(WriteCardCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var dto = request.Data.DeserializeCardData<CardDto>();
|
||||
dto.CardId = request.CardId;
|
||||
|
||||
var card = await CardDbContext.CardMains.FirstOrDefaultAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
|
||||
if (card is null)
|
||||
{
|
||||
logger.LogInformation("Creating new card {CardId}", request.CardId);
|
||||
card = dto.CardDtoToCardMain();
|
||||
card.Created = TimeHelper.CurrentTimeToString();
|
||||
card.Modified = TimeHelper.CurrentTimeToString();
|
||||
CardDbContext.CardMains.Add(card);
|
||||
}
|
||||
else
|
||||
{
|
||||
logger.LogInformation("Updating {CardId}", request.CardId);
|
||||
card.Fcol1 = dto.Fcol1;
|
||||
card.Fcol2 = dto.Fcol2;
|
||||
card.Fcol3 = dto.Fcol3;
|
||||
card.ScoreI1 = dto.ScoreI1;
|
||||
card.Modified = TimeHelper.CurrentTimeToString();
|
||||
CardDbContext.CardMains.Update(card);
|
||||
}
|
||||
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new ServiceResult<string>(request.Data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteCardDetailCommand(long CardId, string TenpoId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteDetailCommandHandler : RequestHandlerBase<WriteCardDetailCommand, string>
|
||||
{
|
||||
private readonly ILogger<WriteDetailCommandHandler> logger;
|
||||
|
||||
public WriteDetailCommandHandler(ICardDependencyAggregate aggregate, ILogger<WriteDetailCommandHandler> logger) : base(aggregate)
|
||||
{
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public override async Task<ServiceResult<string>> Handle(WriteCardDetailCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
var exists = await CardDbContext.CardMains.AnyAsync(card => card.CardId == request.CardId, cancellationToken: cancellationToken);
|
||||
if (!exists)
|
||||
{
|
||||
logger.LogWarning("Card id: {CardId} does not exist!", request.CardId);
|
||||
return ServiceResult.Failed<string>(
|
||||
new ServiceError($"Card id: {request.CardId} does not exist!", (int)CardReturnCode.CardNotRegistered));
|
||||
}
|
||||
|
||||
var dto = request.Data.DeserializeCardData<CardDetailDto>();
|
||||
var detail = dto.DtoToCardDetail();
|
||||
detail.CardId = request.CardId;
|
||||
detail.LastPlayTime = DateTime.Now;
|
||||
detail.LastPlayTenpoId = request.TenpoId;
|
||||
await CardDbContext.CardDetails.Upsert(detail).RunAsync(cancellationToken);
|
||||
|
||||
await CardDbContext.SaveChangesAsync(cancellationToken);
|
||||
|
||||
return new ServiceResult<string>(request.Data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteCoinCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteCoinCommandHandler : RequestHandlerBase<WriteCoinCommand, string>
|
||||
{
|
||||
public WriteCoinCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteCoinCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteCondCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteCondCommandHandler : RequestHandlerBase<WriteCondCommand, string>
|
||||
{
|
||||
public WriteCondCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteCondCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteItemCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteItemCommandHandler : RequestHandlerBase<WriteItemCommand, string>
|
||||
{
|
||||
public WriteItemCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteItemCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteMusicDetailCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteMusicDetailCommandHandler : RequestHandlerBase<WriteMusicDetailCommand, string>
|
||||
{
|
||||
public WriteMusicDetailCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteMusicDetailCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteNavigatorCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteNavigatorCommandHandler : RequestHandlerBase<WriteNavigatorCommand, string>
|
||||
{
|
||||
public WriteNavigatorCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteNavigatorCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteSkinCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteSkinCommandHandler : RequestHandlerBase<WriteSkinCommand, string>
|
||||
{
|
||||
public WriteSkinCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteSkinCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteSoundEffectCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteSoundEffectCommandHandler : RequestHandlerBase<WriteSoundEffectCommand, string>
|
||||
{
|
||||
public WriteSoundEffectCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteSoundEffectCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteTitleCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteTitleCommandHandler : RequestHandlerBase<WriteTitleCommand, string>
|
||||
{
|
||||
public WriteTitleCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteTitleCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
namespace Application.Game.Card.Write;
|
||||
|
||||
public record WriteUnlockKeynumCommand(long CardId, string Data) : IRequestWrapper<string>;
|
||||
|
||||
public class WriteUnlockKeynumCommandHandler : RequestHandlerBase<WriteUnlockKeynumCommand, string>
|
||||
{
|
||||
public WriteUnlockKeynumCommandHandler(ICardDependencyAggregate aggregate) : base(aggregate) {}
|
||||
|
||||
public override Task<ServiceResult<string>> Handle(WriteUnlockKeynumCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
// TODO: Add proper implementation
|
||||
return Task.FromResult(new ServiceResult<string>(request.Data));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Application.Game.Option;
|
||||
|
||||
public record PlayCountQuery(long CardId) : IRequest<long>;
|
||||
|
||||
public class PlayCountQueryHandler : IRequestHandler<PlayCountQuery, long>
|
||||
{
|
||||
private readonly ICardDbContext context;
|
||||
|
||||
private readonly ILogger<PlayCountQueryHandler> logger;
|
||||
|
||||
public PlayCountQueryHandler(ICardDbContext context, ILogger<PlayCountQueryHandler> logger)
|
||||
{
|
||||
this.context = context;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public async Task<long> Handle(PlayCountQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
return await GetPlayCount(request.CardId);
|
||||
}
|
||||
|
||||
private async Task<long> GetPlayCount(long cardId)
|
||||
{
|
||||
var record = await context.CardPlayCounts.FirstOrDefaultAsync(count => count.CardId == cardId);
|
||||
if (record is null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var now = DateTime.Now;
|
||||
var lastPlayedTime = record.LastPlayedTime;
|
||||
|
||||
if (now <= lastPlayedTime)
|
||||
{
|
||||
logger.LogWarning("Clock skew detected! " +
|
||||
"Current time: {Now}," +
|
||||
"Last Play Time: {Last}", now, lastPlayedTime);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DateTime start;
|
||||
DateTime end;
|
||||
if (now.Hour >= 8)
|
||||
{
|
||||
start = DateTime.Today.AddHours(8);
|
||||
end = start.AddHours(24);
|
||||
}
|
||||
else
|
||||
{
|
||||
end = DateTime.Today.AddHours(8);
|
||||
start = end.AddHours(-24);
|
||||
}
|
||||
|
||||
var inBetween = lastPlayedTime >= start && lastPlayedTime <= end;
|
||||
return inBetween ? record.PlayCount : 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetEventRankQuery() : IRequestWrapper<string>;
|
||||
|
||||
public class GetEventRankQueryHandler : IRequestHandlerWrapper<GetEventRankQuery, string>
|
||||
{
|
||||
public Task<ServiceResult<string>> Handle(GetEventRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var container = new EventRankContainer
|
||||
{
|
||||
Ranks = new List<object>(),
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "EventRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = 0,
|
||||
Status = 0
|
||||
}
|
||||
};
|
||||
|
||||
return Task.FromResult(new ServiceResult<string>(container.SerializeCardData()));
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class EventRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "event_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<object> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetGlobalScoreRankQuery(string Param) : IRequestWrapper<string>;
|
||||
|
||||
public class GetGlobalScoreRankQueryHandler : IRequestHandlerWrapper<GetGlobalScoreRankQuery, string>
|
||||
{
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
public GetGlobalScoreRankQueryHandler(ICardDbContext cardDbContext)
|
||||
{
|
||||
this.cardDbContext = cardDbContext;
|
||||
}
|
||||
|
||||
public async Task<ServiceResult<string>> Handle(GetGlobalScoreRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var param = request.Param.DeserializeCardData<RankParam>();
|
||||
return param switch
|
||||
{
|
||||
{ CardId: 0, TenpoId: 0 } => await GetAllRanks(cancellationToken),
|
||||
{ CardId: > 0, TenpoId: 0 } => await GetCardRank(param.CardId, cancellationToken),
|
||||
{ CardId: 0, TenpoId: > 0 } => await GetTenpoRanks(param.TenpoId, cancellationToken),
|
||||
_ => ServiceResult.Failed<string>(ServiceError.ValidationFormat)
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetCardRank(long cardId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var rank = await cardDbContext.GlobalScoreRanks.FirstOrDefaultAsync(scoreRank => scoreRank.CardId == cardId,
|
||||
cancellationToken: cancellationToken);
|
||||
var container = new GlobalScoreRankContainer
|
||||
{
|
||||
Ranks = new List<ScoreRankDto>(),
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "GlobalScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = 0,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
if (rank is null)
|
||||
{
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = 0;
|
||||
container.Ranks.Add(dto);
|
||||
container.Status.Rows++;
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetAllRanks(CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.GlobalScoreRanks.OrderBy(rank => rank.Rank)
|
||||
.Take(30).ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = i;
|
||||
dto.Rank2 = dto.Rank;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new GlobalScoreRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "GlobalScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = dtoList.Count,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetTenpoRanks(int tenpoId, CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.GlobalScoreRanks.Where(rank => rank.LastPlayTenpoId == tenpoId)
|
||||
.OrderByDescending(rank => rank.TotalScore)
|
||||
.Take(30)
|
||||
.ToListAsync(cancellationToken: cancellationToken);
|
||||
ranks = ranks.Select((rank, i) =>
|
||||
{
|
||||
rank.Rank = i + 1;
|
||||
return rank;
|
||||
}).ToList();
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = i;
|
||||
dto.Rank2 = dto.Rank;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new GlobalScoreRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "TenpoScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = dtoList.Count,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class GlobalScoreRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "score_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<ScoreRankDto> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetMonthlyScoreRankQuery() : IRequestWrapper<string>;
|
||||
|
||||
public class GetMonthlyScoreRankQueryHandler : IRequestHandlerWrapper<GetMonthlyScoreRankQuery, string>
|
||||
{
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
public GetMonthlyScoreRankQueryHandler(ICardDbContext cardDbContext)
|
||||
{
|
||||
this.cardDbContext = cardDbContext;
|
||||
}
|
||||
|
||||
public async Task<ServiceResult<string>> Handle(GetMonthlyScoreRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.MonthlyScoreRanks.OrderBy(rank => rank.Rank)
|
||||
.Take(30).ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = i;
|
||||
dto.Rank2 = dto.Rank;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new MonthlyScoreRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "MonthlyScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = dtoList.Count,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class MonthlyScoreRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "m_score_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<ScoreRankDto> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Diagnostics;
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetPlayNumRankQuery(): IRequestWrapper<string>;
|
||||
|
||||
public class GetPlayNumRankQueryHandler : IRequestHandlerWrapper<GetPlayNumRankQuery, string>
|
||||
{
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
public GetPlayNumRankQueryHandler(ICardDbContext cardDbContext)
|
||||
{
|
||||
this.cardDbContext = cardDbContext;
|
||||
}
|
||||
|
||||
public async Task<ServiceResult<string>> Handle(GetPlayNumRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.PlayNumRanks.OrderBy(rank => rank.Rank)
|
||||
.Take(30).ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
var status = new RankStatus
|
||||
{
|
||||
TableName = "PlayNumRank",
|
||||
StartDate = TimeHelper.DateToString(Process.GetCurrentProcess().StartTime.Date),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = ranks.Count,
|
||||
Status = 1
|
||||
};
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.PlayNumRankToDto();
|
||||
dto.Id = i;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new PlayNumRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = status
|
||||
};
|
||||
|
||||
var result = container.SerializeCardData();
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class PlayNumRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "play_num_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<PlayNumRankDto> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetTenpoScoreRankQuery(int TenpoId, string Param) : IRequestWrapper<string>;
|
||||
|
||||
public class GetTenpoScoreRankQueryHandler : IRequestHandlerWrapper<GetTenpoScoreRankQuery, string>
|
||||
{
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
public GetTenpoScoreRankQueryHandler(ICardDbContext cardDbContext)
|
||||
{
|
||||
this.cardDbContext = cardDbContext;
|
||||
}
|
||||
|
||||
public async Task<ServiceResult<string>> Handle(GetTenpoScoreRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var param = request.Param.DeserializeCardData<RankParam>();
|
||||
if (param.CardId == 0)
|
||||
{
|
||||
return await GetAllRanks(request.TenpoId, cancellationToken);
|
||||
}
|
||||
return await GetCardRank(param.CardId, request.TenpoId, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetCardRank(long cardId, int tenpoId, CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.GlobalScoreRanks.Where(rank => rank.LastPlayTenpoId == tenpoId)
|
||||
.OrderByDescending(rank => rank.TotalScore)
|
||||
.ToListAsync(cancellationToken: cancellationToken);
|
||||
ranks = ranks.Select((rank, i) =>
|
||||
{
|
||||
rank.Rank = i + 1;
|
||||
return rank;
|
||||
}).ToList();
|
||||
|
||||
var rank = ranks.FirstOrDefault(rank => rank.CardId == cardId);
|
||||
|
||||
var container = new TenpoScoreRankContainer
|
||||
{
|
||||
Ranks = new List<ScoreRankDto>(),
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "CardTenpoScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = 0,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
if (rank is null)
|
||||
{
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = 0;
|
||||
container.Ranks.Add(dto);
|
||||
container.Status.Rows++;
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetAllRanks(int tenpoId, CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.GlobalScoreRanks.Where(rank => rank.LastPlayTenpoId == tenpoId)
|
||||
.OrderByDescending(rank => rank.TotalScore)
|
||||
.Take(30)
|
||||
.ToListAsync(cancellationToken: cancellationToken);
|
||||
ranks = ranks.Select((rank, i) =>
|
||||
{
|
||||
rank.Rank = i + 1;
|
||||
return rank;
|
||||
}).ToList();
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = i;
|
||||
dto.Rank2 = dto.Rank;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new TenpoScoreRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "CardTenpoScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = dtoList.Count,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
using System.Diagnostics;
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetWPlayNumRankQuery(): IRequestWrapper<string>;
|
||||
|
||||
public class GetWPlayNumRankQueryHandler : IRequestHandlerWrapper<GetWPlayNumRankQuery, string>
|
||||
{
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
public GetWPlayNumRankQueryHandler(ICardDbContext cardDbContext)
|
||||
{
|
||||
this.cardDbContext = cardDbContext;
|
||||
}
|
||||
|
||||
public async Task<ServiceResult<string>> Handle(GetWPlayNumRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.PlayNumRanks.OrderBy(rank => rank.Rank)
|
||||
.Take(30).ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
var status = new RankStatus
|
||||
{
|
||||
TableName = "PlayNumRank",
|
||||
StartDate = TimeHelper.DateToString(Process.GetCurrentProcess().StartTime.Date),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = ranks.Count,
|
||||
Status = 1
|
||||
};
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.PlayNumRankToDto();
|
||||
dto.Id = i;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new WPlayNumRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = status
|
||||
};
|
||||
|
||||
var result = container.SerializeCardData();
|
||||
|
||||
return new ServiceResult<string>(result);
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class WPlayNumRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "w_play_num_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<PlayNumRankDto> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetWScoreRankQuery(string Param) : IRequestWrapper<string>;
|
||||
|
||||
public class GetWScoreRankQueryHandler : IRequestHandlerWrapper<GetWScoreRankQuery, string>
|
||||
{
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
public GetWScoreRankQueryHandler(ICardDbContext cardDbContext)
|
||||
{
|
||||
this.cardDbContext = cardDbContext;
|
||||
}
|
||||
|
||||
public async Task<ServiceResult<string>> Handle(GetWScoreRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var param = request.Param.DeserializeCardData<RankParam>();
|
||||
if (param.CardId == 0)
|
||||
{
|
||||
return await GetAllRanks(cancellationToken);
|
||||
}
|
||||
return await GetCardRank(param.CardId, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetCardRank(long cardId,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
var rank = await cardDbContext.GlobalScoreRanks.FirstOrDefaultAsync(scoreRank => scoreRank.CardId == cardId,
|
||||
cancellationToken: cancellationToken);
|
||||
var container = new GlobalScoreRankContainer
|
||||
{
|
||||
Ranks = new List<ScoreRankDto>(),
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "GlobalScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = 0,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
if (rank is null)
|
||||
{
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = 0;
|
||||
container.Ranks.Add(dto);
|
||||
container.Status.Rows++;
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetAllRanks(CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.GlobalScoreRanks.OrderBy(rank => rank.Rank)
|
||||
.Take(30).ToListAsync(cancellationToken: cancellationToken);
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = i;
|
||||
dto.Rank2 = dto.Rank;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new WScoreRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "GlobalScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = dtoList.Count,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class WScoreRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "w_score_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<ScoreRankDto> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
using Application.Common.Helpers;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public record GetWTenpoScoreRankQuery(int TenpoId, string Param) : IRequestWrapper<string>;
|
||||
|
||||
public class GetWTenpoScoreRankQueryHandler : IRequestHandlerWrapper<GetWTenpoScoreRankQuery, string>
|
||||
{
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
public GetWTenpoScoreRankQueryHandler(ICardDbContext cardDbContext)
|
||||
{
|
||||
this.cardDbContext = cardDbContext;
|
||||
}
|
||||
|
||||
public async Task<ServiceResult<string>> Handle(GetWTenpoScoreRankQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var param = request.Param.DeserializeCardData<RankParam>();
|
||||
if (param.CardId == 0)
|
||||
{
|
||||
return await GetAllRanks(request.TenpoId, cancellationToken);
|
||||
}
|
||||
return await GetCardRank(param.CardId, request.TenpoId, cancellationToken);
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetCardRank(long cardId, int tenpoId, CancellationToken cancellationToken)
|
||||
{
|
||||
var rank = await cardDbContext.GlobalScoreRanks.FirstOrDefaultAsync(scoreRank => scoreRank.CardId == cardId &&
|
||||
scoreRank.LastPlayTenpoId == tenpoId,
|
||||
cancellationToken: cancellationToken);
|
||||
var container = new TenpoScoreRankContainer
|
||||
{
|
||||
Ranks = new List<ScoreRankDto>(),
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "TenpoScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = 0,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
if (rank is null)
|
||||
{
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = 0;
|
||||
container.Ranks.Add(dto);
|
||||
container.Status.Rows++;
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
|
||||
private async Task<ServiceResult<string>> GetAllRanks(int tenpoId, CancellationToken cancellationToken)
|
||||
{
|
||||
var ranks = await cardDbContext.GlobalScoreRanks.Where(rank => rank.LastPlayTenpoId == tenpoId)
|
||||
.OrderByDescending(rank => rank.TotalScore)
|
||||
.Take(30)
|
||||
.ToListAsync(cancellationToken: cancellationToken);
|
||||
ranks = ranks.Select((rank, i) =>
|
||||
{
|
||||
rank.Rank = i + 1;
|
||||
return rank;
|
||||
}).ToList();
|
||||
|
||||
var dtoList = ranks.Select((rank, i) =>
|
||||
{
|
||||
var dto = rank.ScoreRankToDto();
|
||||
dto.Id = i;
|
||||
dto.Rank2 = dto.Rank;
|
||||
return dto;
|
||||
}).ToList();
|
||||
|
||||
var container = new WTenpoScoreRankContainer
|
||||
{
|
||||
Ranks = dtoList,
|
||||
Status = new RankStatus
|
||||
{
|
||||
TableName = "TenpoScoreRank",
|
||||
StartDate = TimeHelper.DateToString(DateTime.Today),
|
||||
EndDate = TimeHelper.DateToString(DateTime.Today),
|
||||
Rows = dtoList.Count,
|
||||
Status = 1
|
||||
}
|
||||
};
|
||||
|
||||
return new ServiceResult<string>(container.SerializeCardData());
|
||||
}
|
||||
}
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class WTenpoScoreRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "w_t_score_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<ScoreRankDto> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public class RankParam
|
||||
{
|
||||
[XmlElement(ElementName = "card_id")]
|
||||
[DefaultValue("0")]
|
||||
public long CardId { get; set; }
|
||||
|
||||
[XmlElement(ElementName = "tenpo_id")]
|
||||
[DefaultValue("0")]
|
||||
public int TenpoId { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
public class RankStatus
|
||||
{
|
||||
[XmlElement("table_name")]
|
||||
public string TableName { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("start_date")]
|
||||
public string StartDate { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("end_date")]
|
||||
public string EndDate { get; set; } = string.Empty;
|
||||
|
||||
[XmlElement("status")]
|
||||
public int Status { get; set; }
|
||||
|
||||
[XmlElement("rows")]
|
||||
public int Rows { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Application.Game.Rank;
|
||||
|
||||
[XmlRoot("root")]
|
||||
public class TenpoScoreRankContainer
|
||||
{
|
||||
[XmlArray(ElementName = "t_score_rank")]
|
||||
[XmlArrayItem(ElementName = "record")]
|
||||
// ReSharper disable once UnusedAutoPropertyAccessor.Global
|
||||
public List<ScoreRankDto> Ranks { get; init; } = new();
|
||||
|
||||
[XmlElement("ranking_status")]
|
||||
public RankStatus Status { get; set; } = new();
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Domain.Config;
|
||||
using MediatR;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Application.Game.Server;
|
||||
|
||||
public record CertifyCommand(string? Gid, string? Mac, string? Random, string? Md5, string Host) : IRequest<string>;
|
||||
|
||||
public partial class CertifyCommandHandler : IRequestHandler<CertifyCommand, string>
|
||||
{
|
||||
private readonly RelayConfig relayConfig;
|
||||
|
||||
private readonly AuthConfig authConfig;
|
||||
|
||||
public CertifyCommandHandler(IOptions<RelayConfig> relayOptions, IOptions<AuthConfig> authOptions)
|
||||
{
|
||||
relayConfig = relayOptions.Value;
|
||||
authConfig = authOptions.Value;
|
||||
}
|
||||
|
||||
public Task<string> Handle(CertifyCommand request, CancellationToken cancellationToken)
|
||||
{
|
||||
if (request.Gid == null)
|
||||
{
|
||||
return Task.FromResult(QuitWithError(ErrorCode.ErrorNoGid));
|
||||
}
|
||||
|
||||
if (request.Mac == null)
|
||||
{
|
||||
return Task.FromResult(QuitWithError(ErrorCode.ErrorNoMac));
|
||||
}
|
||||
|
||||
if (request.Random == null)
|
||||
{
|
||||
return Task.FromResult(QuitWithError(ErrorCode.ErrorNoRandom));
|
||||
}
|
||||
|
||||
if (request.Md5 == null)
|
||||
{
|
||||
return Task.FromResult(QuitWithError(ErrorCode.ErrorNoHash));
|
||||
}
|
||||
|
||||
if (!MacValid(request.Mac) )
|
||||
{
|
||||
return Task.FromResult(QuitWithError(ErrorCode.ErrorInvalidMac));
|
||||
}
|
||||
|
||||
if (!Md5Valid(request.Md5))
|
||||
{
|
||||
return Task.FromResult(QuitWithError(ErrorCode.ErrorInvalidHash));
|
||||
}
|
||||
var machine = new Machine
|
||||
{
|
||||
TenpoId = "1337",
|
||||
TenpoName = "GCLocalServer",
|
||||
Pref = "nesys",
|
||||
Location = "Local",
|
||||
Mac = request.Mac
|
||||
};
|
||||
if (authConfig.Enabled)
|
||||
{
|
||||
machine = authConfig.Machines.FirstOrDefault(m => m.Mac == request.Mac);
|
||||
if (machine is null)
|
||||
{
|
||||
return Task.FromResult(QuitWithError(ErrorCode.ErrorInvalidMac));
|
||||
}
|
||||
}
|
||||
|
||||
var ticket = string.Join(string.Empty,
|
||||
MD5.HashData(Encoding.UTF8.GetBytes(request.Gid)).Select(b => b.ToString("x2")));
|
||||
|
||||
var response = $"host=card_id=7020392000147361,relay_addr={relayConfig.RelayServer},relay_port={relayConfig.RelayPort}\n" +
|
||||
$"no={machine.TenpoId}\n" +
|
||||
$"name={machine.TenpoName}\n" +
|
||||
$"pref={machine.Pref}\n" +
|
||||
$"addr={machine.Location}\n" +
|
||||
"x-next-time=15\n" +
|
||||
$"x-img=http://{request.Host}/news.png\n" +
|
||||
$"x-ranking=http://{request.Host}/ranking/ranking.php\n" +
|
||||
$"ticket={ticket}";
|
||||
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
|
||||
private static bool MacValid(string mac)
|
||||
{
|
||||
return MacRegex().IsMatch(mac);
|
||||
}
|
||||
|
||||
private static bool Md5Valid(string md5)
|
||||
{
|
||||
return Md5Regex().IsMatch(md5);
|
||||
}
|
||||
|
||||
private static string QuitWithError(ErrorCode errorCode)
|
||||
{
|
||||
return $"error={(int)errorCode}";
|
||||
}
|
||||
|
||||
private enum ErrorCode
|
||||
{
|
||||
ErrorNoGid,
|
||||
ErrorNoMac,
|
||||
ErrorNoRandom,
|
||||
ErrorNoHash,
|
||||
ErrorInvalidMac,
|
||||
ErrorInvalidHash
|
||||
}
|
||||
|
||||
[GeneratedRegex("^[a-fA-F0-9]{12}$")]
|
||||
private static partial Regex MacRegex();
|
||||
[GeneratedRegex("^[a-fA-F0-9]{32}$")]
|
||||
private static partial Regex Md5Regex();
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using System.Text;
|
||||
using MediatR;
|
||||
|
||||
namespace Application.Game.Server;
|
||||
|
||||
public record GetDataQuery(string Host, string Scheme) : IRequest<string>;
|
||||
|
||||
public class GetDataQueryHandler : IRequestHandler<GetDataQuery, string>
|
||||
{
|
||||
private readonly IEventManagerService eventManagerService;
|
||||
|
||||
public GetDataQueryHandler(IEventManagerService eventManagerService)
|
||||
{
|
||||
this.eventManagerService = eventManagerService;
|
||||
}
|
||||
|
||||
public Task<string> Handle(GetDataQuery request, CancellationToken cancellationToken)
|
||||
{
|
||||
var response = "count=0\n" +
|
||||
"nexttime=180";
|
||||
if (!eventManagerService.UseEvents())
|
||||
{
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
|
||||
var urlBase = $"{request.Scheme}://{request.Host}/events/";
|
||||
var dataString = new StringBuilder();
|
||||
var events = eventManagerService.GetEvents();
|
||||
var count = 0;
|
||||
foreach (var pair in events.Select((@event, i) => new {Value = @event, Index = i}))
|
||||
{
|
||||
var value = pair.Value;
|
||||
var index = pair.Index;
|
||||
var fileUrl = $"{urlBase}{value.Name}";
|
||||
var eventString = $"{index},{fileUrl},{value.NotBefore},{value.NotAfter},{value.Md5},{value.Index}";
|
||||
dataString.Append(eventString).Append('\n');
|
||||
count++;
|
||||
}
|
||||
|
||||
response = $"count={count}\n" +
|
||||
"nexttime=1\n" +
|
||||
$"{dataString}";
|
||||
|
||||
return Task.FromResult(response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// Global using directives
|
||||
|
||||
global using Microsoft.EntityFrameworkCore;
|
||||
global using System.Xml.Serialization;
|
||||
global using Application.Common.Base;
|
||||
global using Application.Common.Extensions;
|
||||
global using Shared.Dto.Api;
|
||||
global using Shared.Models;
|
||||
global using Application.Dto.Game;
|
||||
global using Application.Interfaces;
|
||||
global using Application.Mappers;
|
||||
@@ -0,0 +1,30 @@
|
||||
using Domain.Entities;
|
||||
|
||||
namespace Application.Interfaces;
|
||||
|
||||
public interface ICardDbContext
|
||||
{
|
||||
public DbSet<CardBdatum> CardBdata { get; set; }
|
||||
|
||||
public DbSet<CardDetail> CardDetails { get; set; }
|
||||
|
||||
public DbSet<CardMain> CardMains { get; set; }
|
||||
|
||||
public DbSet<CardPlayCount> CardPlayCounts { get; set; }
|
||||
|
||||
public DbSet<PlayNumRank> PlayNumRanks { get; set; }
|
||||
|
||||
public DbSet<GlobalScoreRank> GlobalScoreRanks { get; set; }
|
||||
|
||||
public DbSet<MonthlyScoreRank> MonthlyScoreRanks { get; set; }
|
||||
|
||||
public DbSet<ShopScoreRank> ShopScoreRanks { get; set; }
|
||||
|
||||
public DbSet<OnlineMatch> OnlineMatches { get; set; }
|
||||
|
||||
public DbSet<OnlineMatchEntry> OnlineMatchEntries { get; set; }
|
||||
|
||||
public Task<int> SaveChangesAsync(CancellationToken cancellationToken);
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Domain.Config;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace Application.Interfaces;
|
||||
|
||||
public interface ICardDependencyAggregate
|
||||
{
|
||||
ICardDbContext CardDbContext { get; }
|
||||
IMusicDbContext MusicDbContext { get; }
|
||||
|
||||
IOptions<GameConfig> Options { get; }
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Domain.Models;
|
||||
|
||||
namespace Application.Interfaces;
|
||||
|
||||
public interface IEventManagerService
|
||||
{
|
||||
public void InitializeEvents();
|
||||
|
||||
public bool UseEvents();
|
||||
|
||||
public IEnumerable<Event> GetEvents();
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using Domain.Entities;
|
||||
|
||||
namespace Application.Interfaces;
|
||||
|
||||
public interface IMusicDbContext
|
||||
{
|
||||
public DbSet<MusicAou> MusicAous { get; set; }
|
||||
|
||||
public DbSet<MusicExtra> MusicExtras { get; set; }
|
||||
|
||||
public DbSet<MusicUnlock> MusicUnlocks { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using MediatR;
|
||||
|
||||
namespace Application.Interfaces;
|
||||
|
||||
public interface IRequestWrapper<T> : IRequest<ServiceResult<T>>
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public interface IRequestHandlerWrapper<TIn, TOut> : IRequestHandler<TIn, ServiceResult<TOut>> where TIn : IRequestWrapper<TOut>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Domain.Config;
|
||||
using Domain.Enums;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Quartz;
|
||||
|
||||
namespace Application.Jobs;
|
||||
|
||||
public class MaintainNullValuesJob : IJob
|
||||
{
|
||||
private readonly ILogger<MaintainNullValuesJob> logger;
|
||||
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
private readonly GameConfig config;
|
||||
|
||||
public static readonly JobKey KEY = new("MaintainNullValuesJob");
|
||||
|
||||
public MaintainNullValuesJob(ILogger<MaintainNullValuesJob> logger, ICardDbContext cardDbContext, IOptions<GameConfig> options)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.cardDbContext = cardDbContext;
|
||||
config = options.Value;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records",
|
||||
Justification = "All details might be read")]
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0006: Large number of DB commands")]
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
logger.LogInformation("Starting changing null values in card detail table");
|
||||
|
||||
var details = await cardDbContext.CardDetails.Where(detail => detail.LastPlayTenpoId == null ||
|
||||
detail.LastPlayTenpoId == "GC local server"
|
||||
|| detail.LastPlayTime == null).ToListAsync();
|
||||
details.ForEach(detail =>
|
||||
{
|
||||
detail.LastPlayTenpoId = "1337";
|
||||
detail.LastPlayTime = DateTime.MinValue;
|
||||
});
|
||||
|
||||
cardDbContext.CardDetails.UpdateRange(details);
|
||||
var count = await cardDbContext.SaveChangesAsync(new CancellationToken());
|
||||
|
||||
logger.LogInformation("Updated {Count} entries in card detail table", count);
|
||||
|
||||
logger.LogInformation("Starting closing unfinished matches");
|
||||
var matches = await cardDbContext.OnlineMatches.Where(match => match.IsOpen == true).ToListAsync();
|
||||
matches.ForEach(match => match.IsOpen = false);
|
||||
cardDbContext.OnlineMatches.UpdateRange(matches);
|
||||
count = await cardDbContext.SaveChangesAsync(new CancellationToken());
|
||||
|
||||
logger.LogInformation("Closed {Count} matches", count);
|
||||
|
||||
logger.LogInformation("Starting to remove previously new songs");
|
||||
var unlockables = config.UnlockRewards
|
||||
.Where(c => c.RewardType == RewardType.Music).ToDictionary(rewardConfig => rewardConfig.TargetId);
|
||||
var targets = await cardDbContext.CardDetails.Where(detail => detail.Pcol1 == 10).ToListAsync();
|
||||
foreach (var target in targets)
|
||||
{
|
||||
if (unlockables.ContainsKey((int)target.Pcol2))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
target.ScoreUi2 = 0;
|
||||
target.ScoreUi6 = 0;
|
||||
}
|
||||
cardDbContext.CardDetails.UpdateRange(targets);
|
||||
count = await cardDbContext.SaveChangesAsync(new CancellationToken());
|
||||
|
||||
logger.LogInformation("Fixed {Count} records", count);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Domain.Config;
|
||||
using Domain.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Quartz;
|
||||
|
||||
namespace Application.Jobs;
|
||||
|
||||
public class UpdateGlobalScoreRankJob : IJob
|
||||
{
|
||||
private readonly ILogger<UpdateGlobalScoreRankJob> logger;
|
||||
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
private readonly AuthConfig authConfig;
|
||||
|
||||
public static readonly JobKey KEY = new("UpdateGlobalScoreRankJob");
|
||||
|
||||
public UpdateGlobalScoreRankJob(ILogger<UpdateGlobalScoreRankJob> logger,
|
||||
ICardDbContext cardDbContext,
|
||||
IOptions<AuthConfig> authConfig)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.cardDbContext = cardDbContext;
|
||||
this.authConfig = authConfig.Value;
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records",
|
||||
Justification = "All play record will be read")]
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
logger.LogInformation("Starting update global rank");
|
||||
|
||||
var cardMains = await cardDbContext.CardMains.ToListAsync();
|
||||
|
||||
var totalScoresByCardId = await cardDbContext.CardDetails.Where(detail => detail.Pcol1 == 21)
|
||||
.GroupBy(detail => detail.CardId)
|
||||
.Select(detailGroup => new
|
||||
{
|
||||
CardId = detailGroup.Key,
|
||||
TotalScore = detailGroup.Sum(detail => detail.ScoreUi1)
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var avatarAndTitles = await cardDbContext.CardDetails.Where(detail => detail.Pcol1 == 0 &&
|
||||
detail.Pcol2 == 0 &&
|
||||
detail.Pcol3 == 0).ToListAsync();
|
||||
|
||||
var ranks = new List<GlobalScoreRank>();
|
||||
foreach (var record in totalScoresByCardId)
|
||||
{
|
||||
var cardId = record.CardId;
|
||||
var score = record.TotalScore;
|
||||
var card = cardMains.FirstOrDefault(card => card.CardId == cardId);
|
||||
if (card is null)
|
||||
{
|
||||
logger.LogWarning("Card id {CardId} missing in main card table!", cardId);
|
||||
continue;
|
||||
}
|
||||
|
||||
var detail = avatarAndTitles.First(detail => detail.CardId == cardId);
|
||||
|
||||
var pref = "nesys";
|
||||
var lastPlayTenpoId = 1337;
|
||||
var tenpoName = "GCLocalServer";
|
||||
if (authConfig.Enabled)
|
||||
{
|
||||
var result = int.TryParse(detail.LastPlayTenpoId, out lastPlayTenpoId);
|
||||
if (!result)
|
||||
{
|
||||
lastPlayTenpoId = 1337;
|
||||
}
|
||||
pref = authConfig.Machines.FirstOrDefault(m => m.TenpoId == detail.LastPlayTenpoId)?.Pref ?? "nesys";
|
||||
tenpoName = authConfig.Machines.FirstOrDefault(m => m.TenpoId == detail.LastPlayTenpoId)?.TenpoName ?? "GCLocalServer";
|
||||
}
|
||||
|
||||
var globalRank = new GlobalScoreRank
|
||||
{
|
||||
CardId = cardId,
|
||||
PlayerName = card.PlayerName,
|
||||
Fcol1 = detail.Fcol1,
|
||||
Area = "Local",
|
||||
AreaId = 1,
|
||||
Pref = pref,
|
||||
PrefId = 1337,
|
||||
LastPlayTenpoId = lastPlayTenpoId,
|
||||
TenpoName = tenpoName,
|
||||
AvatarId = (int)detail.ScoreI1,
|
||||
Title = "Title",
|
||||
TitleId = detail.Fcol2,
|
||||
TotalScore = score
|
||||
};
|
||||
|
||||
ranks.Add(globalRank);
|
||||
}
|
||||
|
||||
ranks.AddRange(GetFakeRanks());
|
||||
ranks.Sort((rank, other) => -rank.TotalScore.CompareTo(other.TotalScore));
|
||||
ranks = ranks.Select((rank, i) =>
|
||||
{
|
||||
rank.Rank = i + 1;
|
||||
return rank;
|
||||
}).ToList();
|
||||
|
||||
await cardDbContext.GlobalScoreRanks.UpsertRange(ranks).RunAsync();
|
||||
await cardDbContext.SaveChangesAsync(new CancellationToken());
|
||||
|
||||
logger.LogInformation("Updating global score rank done");
|
||||
}
|
||||
|
||||
private static IEnumerable<GlobalScoreRank> GetFakeRanks()
|
||||
{
|
||||
var fakeList = new List<GlobalScoreRank>();
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var rank = new GlobalScoreRank
|
||||
{
|
||||
CardId = 1020392010281502 + i,
|
||||
PlayerName = $"Fake{i}",
|
||||
Fcol1 = 0,
|
||||
Area = "Local",
|
||||
AreaId = 1,
|
||||
Pref = "nesys",
|
||||
PrefId = 1337,
|
||||
LastPlayTenpoId = 1337,
|
||||
TenpoName = "GCLocalServer",
|
||||
AvatarId = i + 10,
|
||||
Title = "Title",
|
||||
TitleId = i + 100,
|
||||
TotalScore = (i + 1) * 1000000
|
||||
};
|
||||
|
||||
fakeList.Add(rank);
|
||||
}
|
||||
|
||||
return fakeList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
using Domain.Config;
|
||||
using Domain.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Quartz;
|
||||
|
||||
namespace Application.Jobs;
|
||||
|
||||
public class UpdateMonthlyScoreRankJob : IJob
|
||||
{
|
||||
private readonly ILogger<UpdateMonthlyScoreRankJob> logger;
|
||||
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
private readonly AuthConfig authConfig;
|
||||
|
||||
public static readonly JobKey KEY = new JobKey("UpdateMonthlyScoreRankJob");
|
||||
|
||||
public UpdateMonthlyScoreRankJob(ILogger<UpdateMonthlyScoreRankJob> logger,
|
||||
ICardDbContext cardDbContext,
|
||||
IOptions<AuthConfig> authConfig)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.cardDbContext = cardDbContext;
|
||||
this.authConfig = authConfig.Value;
|
||||
}
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
logger.LogInformation("Starting update montly global rank");
|
||||
|
||||
var cardMains = await cardDbContext.CardMains.ToListAsync();
|
||||
|
||||
var totalScoresByCardId = await cardDbContext.CardDetails.Where(detail => detail.Pcol1 == 21 && detail.LastPlayTime >= DateTime.Today.AddDays(-30))
|
||||
.GroupBy(detail => detail.CardId)
|
||||
.Select(detailGroup => new
|
||||
{
|
||||
CardId = detailGroup.Key,
|
||||
TotalScore = detailGroup.Sum(detail => detail.ScoreUi1)
|
||||
})
|
||||
.ToListAsync();
|
||||
|
||||
var avatarAndTitles = await cardDbContext.CardDetails.Where(detail => detail.Pcol1 == 0 &&
|
||||
detail.Pcol2 == 0 &&
|
||||
detail.Pcol3 == 0).ToListAsync();
|
||||
|
||||
var ranks = new List<MonthlyScoreRank>();
|
||||
foreach (var record in totalScoresByCardId)
|
||||
{
|
||||
var cardId = record.CardId;
|
||||
var score = record.TotalScore;
|
||||
var card = cardMains.FirstOrDefault(card => card.CardId == cardId);
|
||||
if (card is null)
|
||||
{
|
||||
logger.LogWarning("Card id {CardId} missing in main card table!", cardId);
|
||||
continue;
|
||||
}
|
||||
|
||||
var detail = avatarAndTitles.First(detail => detail.CardId == cardId);
|
||||
|
||||
var pref = "nesys";
|
||||
var lastPlayTenpoId = 1337;
|
||||
var tenpoName = "GCLocalServer";
|
||||
if (authConfig.Enabled)
|
||||
{
|
||||
var result = int.TryParse(detail.LastPlayTenpoId, out lastPlayTenpoId);
|
||||
if (!result)
|
||||
{
|
||||
lastPlayTenpoId = 1337;
|
||||
}
|
||||
pref = authConfig.Machines.FirstOrDefault(m => m.TenpoId == detail.LastPlayTenpoId)?.Pref ?? "nesys";
|
||||
tenpoName = authConfig.Machines.FirstOrDefault(m => m.TenpoId == detail.LastPlayTenpoId)?.TenpoName ?? "GCLocalServer";
|
||||
}
|
||||
|
||||
var monthlyScoreRank = new MonthlyScoreRank
|
||||
{
|
||||
CardId = cardId,
|
||||
PlayerName = card.PlayerName,
|
||||
Fcol1 = detail.Fcol1,
|
||||
Area = "Local",
|
||||
AreaId = 1,
|
||||
Pref = pref,
|
||||
PrefId = 1337,
|
||||
LastPlayTenpoId = lastPlayTenpoId,
|
||||
TenpoName = tenpoName,
|
||||
AvatarId = (int)detail.ScoreI1,
|
||||
Title = "Title",
|
||||
TitleId = detail.Fcol2,
|
||||
TotalScore = score
|
||||
};
|
||||
|
||||
ranks.Add(monthlyScoreRank);
|
||||
}
|
||||
|
||||
ranks.AddRange(GetFakeRanks());
|
||||
ranks.Sort((rank, other) => -rank.TotalScore.CompareTo(other.TotalScore));
|
||||
ranks = ranks.Select((rank, i) =>
|
||||
{
|
||||
rank.Rank = i + 1;
|
||||
return rank;
|
||||
}).ToList();
|
||||
|
||||
await cardDbContext.MonthlyScoreRanks.UpsertRange(ranks).RunAsync();
|
||||
await cardDbContext.SaveChangesAsync(new CancellationToken());
|
||||
|
||||
logger.LogInformation("Updating monthly score rank done");
|
||||
}
|
||||
|
||||
private static IEnumerable<MonthlyScoreRank> GetFakeRanks()
|
||||
{
|
||||
var fakeList = new List<MonthlyScoreRank>();
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
var rank = new MonthlyScoreRank
|
||||
{
|
||||
CardId = 1020392010281502 + i,
|
||||
PlayerName = $"Fake{i}",
|
||||
Fcol1 = 0,
|
||||
Area = "Local",
|
||||
AreaId = 1,
|
||||
Pref = "nesys",
|
||||
PrefId = 1337,
|
||||
LastPlayTenpoId = 1337,
|
||||
TenpoName = "GCLocalServer",
|
||||
AvatarId = i + 10,
|
||||
Title = "Title",
|
||||
TitleId = i + 100,
|
||||
TotalScore = (i + 1) * 1000000
|
||||
};
|
||||
|
||||
fakeList.Add(rank);
|
||||
}
|
||||
|
||||
return fakeList;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Domain.Entities;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Quartz;
|
||||
|
||||
namespace Application.Jobs;
|
||||
|
||||
public class UpdatePlayNumRankJob : IJob
|
||||
{
|
||||
private readonly ILogger<UpdatePlayNumRankJob> logger;
|
||||
|
||||
private readonly ICardDbContext cardDbContext;
|
||||
|
||||
private readonly IMusicDbContext musicDbContext;
|
||||
|
||||
public static readonly JobKey KEY = new JobKey("UpdatePlayNumRankJob");
|
||||
|
||||
public UpdatePlayNumRankJob(ILogger<UpdatePlayNumRankJob> logger, ICardDbContext cardDbContext,
|
||||
IMusicDbContext musicDbContext)
|
||||
{
|
||||
this.logger = logger;
|
||||
this.cardDbContext = cardDbContext;
|
||||
this.musicDbContext = musicDbContext;
|
||||
}
|
||||
|
||||
public async Task Execute(IJobExecutionContext context)
|
||||
{
|
||||
logger.LogInformation("Start maintaining play num rank");
|
||||
await UpdatePlayNumRank();
|
||||
}
|
||||
|
||||
|
||||
[SuppressMessage("ReSharper.DPA", "DPA0007: Large number of DB records",
|
||||
Justification = "All music will be read")]
|
||||
private async Task UpdatePlayNumRank()
|
||||
{
|
||||
var playRecords = await cardDbContext.CardDetails
|
||||
.Where(detail => detail.Pcol1 == 20).ToListAsync();
|
||||
|
||||
var playNumRanks = new List<PlayNumRank>();
|
||||
var musics = await musicDbContext.MusicUnlocks.ToListAsync();
|
||||
foreach (var music in musics)
|
||||
{
|
||||
var playCount = playRecords
|
||||
.Where(detail => detail.Pcol2 == music.MusicId)
|
||||
.Sum(detail => detail.ScoreUi1);
|
||||
var playNumRank = new PlayNumRank
|
||||
{
|
||||
MusicId = (int)music.MusicId,
|
||||
Artist = music.Artist ?? string.Empty,
|
||||
Title = music.Title,
|
||||
PlayCount = (int)playCount
|
||||
};
|
||||
playNumRanks.Add(playNumRank);
|
||||
}
|
||||
playNumRanks = playNumRanks.OrderByDescending(rank => rank.PlayCount).ToList();
|
||||
var result = playNumRanks.Select((rank, i) =>
|
||||
{
|
||||
rank.Rank = i+1;
|
||||
return rank;
|
||||
}).ToList();
|
||||
await cardDbContext.PlayNumRanks.UpsertRange(result).RunAsync();
|
||||
await cardDbContext.SaveChangesAsync(new CancellationToken());
|
||||
|
||||
logger.LogInformation("Updating play num rank done");
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user