Add initial ai battle saving
This commit is contained in:
parent
1d89ce2009
commit
2de8d8ab86
14
SharedProject/Utils/ValueHelpers.cs
Normal file
14
SharedProject/Utils/ValueHelpers.cs
Normal file
@ -0,0 +1,14 @@
|
||||
namespace SharedProject.Utils;
|
||||
|
||||
public static class ValueHelpers
|
||||
{
|
||||
public static T Min<T>(T a, T b) where T : IComparable
|
||||
{
|
||||
return Comparer<T>.Default.Compare(a, b) <= 0 ? a : b;
|
||||
}
|
||||
|
||||
public static T Max<T>(T a, T b) where T : IComparable
|
||||
{
|
||||
return Comparer<T>.Default.Compare(a, b) >= 0 ? a : b;
|
||||
}
|
||||
}
|
@ -16,13 +16,16 @@ public class BaidController : BaseController<BaidController>
|
||||
|
||||
private readonly IDanScoreDatumService danScoreDatumService;
|
||||
|
||||
private readonly IAiDatumService aiDatumService;
|
||||
|
||||
public BaidController(IUserDatumService userDatumService, ICardService cardService,
|
||||
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService)
|
||||
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService)
|
||||
{
|
||||
this.userDatumService = userDatumService;
|
||||
this.cardService = cardService;
|
||||
this.songBestDatumService = songBestDatumService;
|
||||
this.danScoreDatumService = danScoreDatumService;
|
||||
this.aiDatumService = aiDatumService;
|
||||
}
|
||||
|
||||
|
||||
@ -112,6 +115,9 @@ public class BaidController : BaseController<BaidController>
|
||||
var genericInfoFlgLength = genericInfoFlg.Any()? genericInfoFlg.Max() + 1 : 0;
|
||||
var genericInfoFlgArray = FlagCalculator.GetBitArrayFromIds(genericInfoFlg, (int)genericInfoFlgLength, Logger);
|
||||
|
||||
var aiScores = await aiDatumService.GetAllAiScoreById(baid);
|
||||
var totalWin = aiScores.Count(datum => datum.IsWin);
|
||||
|
||||
response = new BAIDResponse
|
||||
{
|
||||
Result = 1,
|
||||
@ -159,7 +165,7 @@ public class BaidController : BaseController<BaidController>
|
||||
LastPlayMode = userData.LastPlayMode,
|
||||
IsDispSouuchiOn = true,
|
||||
AiRank = 0,
|
||||
AiTotalWin = 0,
|
||||
AiTotalWin = (uint)totalWin,
|
||||
Accesstoken = "123456",
|
||||
ContentInfo = GZipBytesUtil.GetGZipBytes(new byte[10])
|
||||
};
|
||||
|
@ -1,19 +1,30 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
using TaikoLocalServer.Services.Interfaces;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r03/chassis/getaidata.php")]
|
||||
[ApiController]
|
||||
public class GetAiDataController : BaseController<GetAiDataController>
|
||||
{
|
||||
private readonly IAiDatumService aiDatumService;
|
||||
|
||||
public GetAiDataController(IAiDatumService aiDatumService)
|
||||
{
|
||||
this.aiDatumService = aiDatumService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetAiData([FromBody] GetAiDataRequest request)
|
||||
public async Task<IActionResult> GetAiData([FromBody] GetAiDataRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetAiData request : {Request}", request.Stringify());
|
||||
|
||||
var aiScoreData = await aiDatumService.GetAllAiScoreById(request.Baid);
|
||||
var totalWin = aiScoreData.Count(datum => datum.IsWin);
|
||||
var response = new GetAiDataResponse
|
||||
{
|
||||
Result = 1,
|
||||
TotalWinnings = 0
|
||||
TotalWinnings = (uint)totalWin
|
||||
};
|
||||
|
||||
return Ok(response);
|
||||
|
@ -1,12 +1,22 @@
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
using TaikoLocalServer.Services.Interfaces;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Controllers.Game;
|
||||
|
||||
[Route("/v12r03/chassis/getaiscore.php")]
|
||||
[ApiController]
|
||||
public class GetAiScoreController : BaseController<GetAiScoreController>
|
||||
{
|
||||
private readonly IAiDatumService aiDatumService;
|
||||
|
||||
public GetAiScoreController(IAiDatumService aiDatumService)
|
||||
{
|
||||
this.aiDatumService = aiDatumService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[Produces("application/protobuf")]
|
||||
public IActionResult GetAiScore([FromBody] GetAiScoreRequest request)
|
||||
public async Task<IActionResult> GetAiScore([FromBody] GetAiScoreRequest request)
|
||||
{
|
||||
Logger.LogInformation("GetAiScore request : {Request}", request.Stringify());
|
||||
|
||||
@ -15,6 +25,30 @@ public class GetAiScoreController : BaseController<GetAiScoreController>
|
||||
Result = 1
|
||||
};
|
||||
|
||||
var difficulty = (Difficulty)request.Level;
|
||||
difficulty.Throw().IfOutOfRange();
|
||||
|
||||
var aiData = await aiDatumService.GetSongAiScore(request.Baid, request.SongNo, difficulty);
|
||||
if (aiData is null)
|
||||
{
|
||||
return Ok(response);
|
||||
}
|
||||
|
||||
for (var index = 0; index < aiData.AiSectionScoreData.Count; index++)
|
||||
{
|
||||
var sectionScoreDatum = aiData.AiSectionScoreData[index];
|
||||
response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData
|
||||
{
|
||||
Crown = (uint)sectionScoreDatum.Crown,
|
||||
GoodCnt = sectionScoreDatum.GoodCount,
|
||||
OkCnt = sectionScoreDatum.OkCount,
|
||||
NgCnt = sectionScoreDatum.MissCount,
|
||||
PoundCnt = sectionScoreDatum.DrumrollCount,
|
||||
Score = sectionScoreDatum.Score,
|
||||
SectionNo = (uint)index
|
||||
});
|
||||
}
|
||||
|
||||
// There's either 3 or 5 total sections
|
||||
// SectionNo doesn't seem to actually affect which section is being assigned to, only the List order matters
|
||||
/*response.AryBestSectionDatas.Add(new GetAiScoreResponse.AiBestSectionData()
|
||||
|
@ -20,13 +20,16 @@ public class PlayResultController : BaseController<PlayResultController>
|
||||
|
||||
private readonly IDanScoreDatumService danScoreDatumService;
|
||||
|
||||
private readonly IAiDatumService aiDatumService;
|
||||
|
||||
public PlayResultController(IUserDatumService userDatumService, ISongPlayDatumService songPlayDatumService,
|
||||
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService)
|
||||
ISongBestDatumService songBestDatumService, IDanScoreDatumService danScoreDatumService, IAiDatumService aiDatumService)
|
||||
{
|
||||
this.userDatumService = userDatumService;
|
||||
this.songPlayDatumService = songPlayDatumService;
|
||||
this.songBestDatumService = songBestDatumService;
|
||||
this.danScoreDatumService = danScoreDatumService;
|
||||
this.aiDatumService = aiDatumService;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
@ -77,9 +80,7 @@ public class PlayResultController : BaseController<PlayResultController>
|
||||
|
||||
if (playMode == PlayMode.AiBattle)
|
||||
{
|
||||
// await UpdateAiBattleData(request, stageData);
|
||||
// Update AI win count here somewhere, or in UpdatePlayData?
|
||||
// I have no clue how to update input median or variance
|
||||
await UpdateAiBattleData(request, stageData);
|
||||
}
|
||||
|
||||
await UpdateBestData(request, stageData, bestData);
|
||||
@ -163,7 +164,7 @@ public class PlayResultController : BaseController<PlayResultController>
|
||||
ComboCount = stageData.ComboCnt,
|
||||
HitCount = stageData.HitCnt,
|
||||
DrumrollCount = stageData.PoundCnt,
|
||||
Crown = PlayResultToCrown(stageData),
|
||||
Crown = PlayResultToCrown(stageData.PlayResult, stageData.OkCnt),
|
||||
Score = stageData.PlayScore,
|
||||
ScoreRate = stageData.ScoreRate,
|
||||
ScoreRank = (ScoreRank)stageData.ScoreRank,
|
||||
@ -294,7 +295,7 @@ public class PlayResultController : BaseController<PlayResultController>
|
||||
});
|
||||
|
||||
// Determine whether it is dondaful crown as this is not reflected by play result
|
||||
var crown = PlayResultToCrown(stageData);
|
||||
var crown = PlayResultToCrown(stageData.PlayResult, stageData.OkCnt);
|
||||
|
||||
bestDatum.UpdateBestData(crown, stageData.ScoreRank, stageData.PlayScore, stageData.ScoreRate);
|
||||
|
||||
@ -302,23 +303,67 @@ public class PlayResultController : BaseController<PlayResultController>
|
||||
}
|
||||
|
||||
// TODO: AI battle
|
||||
/*private async Task UpdateAiBattleData(PlayResultRequest request, StageData stageData)
|
||||
private async Task UpdateAiBattleData(PlayResultRequest request, StageData stageData)
|
||||
{
|
||||
for (int i = 0; i < stageData.ArySectionDatas.Count; i++)
|
||||
var difficulty = (Difficulty)stageData.Level;
|
||||
difficulty.Throw().IfOutOfRange();
|
||||
var existing = await aiDatumService.GetSongAiScore(request.BaidConf,
|
||||
stageData.SongNo, difficulty);
|
||||
|
||||
if (existing is null)
|
||||
{
|
||||
// Only update crown if it's a higher crown than the previous best crown
|
||||
var aiScoreDatum = new AiScoreDatum
|
||||
{
|
||||
Baid = request.BaidConf,
|
||||
SongId = stageData.SongNo,
|
||||
Difficulty = difficulty,
|
||||
IsWin = stageData.IsWin
|
||||
};
|
||||
for (var index = 0; index < stageData.ArySectionDatas.Count; index++)
|
||||
{
|
||||
AddNewAiSectionScore(request, stageData, index, difficulty, aiScoreDatum);
|
||||
}
|
||||
|
||||
// Maybe have a "SectionNo" variable for which section number it is on the DB
|
||||
// compare DB.SectionNo == i
|
||||
// if any aspect of the section is higher than the previous best, update it
|
||||
// Similar to Dan best play updates
|
||||
await aiDatumService.InsertSongAiScore(aiScoreDatum);
|
||||
return;
|
||||
}
|
||||
}*/
|
||||
|
||||
private static CrownType PlayResultToCrown(StageData stageData)
|
||||
for (var index = 0; index < stageData.ArySectionDatas.Count; index++)
|
||||
{
|
||||
var sectionData = stageData.ArySectionDatas[index];
|
||||
if (index < existing.AiSectionScoreData.Count)
|
||||
{
|
||||
existing.AiSectionScoreData[index].UpdateBest(sectionData);
|
||||
}
|
||||
else
|
||||
{
|
||||
AddNewAiSectionScore(request,stageData,index,difficulty,existing);
|
||||
}
|
||||
}
|
||||
|
||||
await aiDatumService.UpdateSongAiScore(existing);
|
||||
}
|
||||
|
||||
private static void AddNewAiSectionScore(PlayResultRequest request, StageData stageData, int index, Difficulty difficulty,
|
||||
AiScoreDatum aiScoreDatum)
|
||||
{
|
||||
var crown = (CrownType)stageData.PlayResult;
|
||||
if (crown == CrownType.Gold && stageData.OkCnt == 0)
|
||||
var sectionData = stageData.ArySectionDatas[index];
|
||||
var aiSectionScoreDatum = new AiSectionScoreDatum
|
||||
{
|
||||
Baid = request.BaidConf,
|
||||
SongId = stageData.SongNo,
|
||||
Difficulty = difficulty,
|
||||
SectionIndex = index
|
||||
};
|
||||
aiSectionScoreDatum.UpdateBest(sectionData);
|
||||
aiScoreDatum.AiSectionScoreData.Add(aiSectionScoreDatum);
|
||||
}
|
||||
|
||||
|
||||
private static CrownType PlayResultToCrown(uint playResult, uint okCount)
|
||||
{
|
||||
var crown = (CrownType)playResult;
|
||||
if (crown == CrownType.Gold && okCount == 0)
|
||||
{
|
||||
crown = CrownType.Dondaful;
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
namespace TaikoLocalServer.Entities;
|
||||
using SharedProject.Utils;
|
||||
|
||||
namespace TaikoLocalServer.Entities;
|
||||
|
||||
public class AiSectionScoreDatum
|
||||
{
|
||||
@ -25,4 +27,21 @@ public class AiSectionScoreDatum
|
||||
public uint DrumrollCount { get; set; }
|
||||
|
||||
public AiScoreDatum Parent { get; set; } = null!;
|
||||
|
||||
public void UpdateBest(PlayResultDataRequest.StageData.AiStageSectionData sectionData)
|
||||
{
|
||||
var crown = (CrownType)sectionData.Crown;
|
||||
if (crown == CrownType.Gold && sectionData.OkCnt == 0)
|
||||
{
|
||||
crown = CrownType.Dondaful;
|
||||
}
|
||||
|
||||
IsWin = sectionData.IsWin ? sectionData.IsWin : IsWin;
|
||||
Crown = ValueHelpers.Max(crown, Crown);
|
||||
Score = ValueHelpers.Max(sectionData.Score, Score);
|
||||
GoodCount = ValueHelpers.Max(sectionData.GoodCnt, GoodCount);
|
||||
OkCount = ValueHelpers.Min(sectionData.OkCnt, OkCount);
|
||||
MissCount = ValueHelpers.Min(sectionData.NgCnt, MissCount);
|
||||
DrumrollCount = ValueHelpers.Max(sectionData.PoundCnt, DrumrollCount);
|
||||
}
|
||||
}
|
50
TaikoLocalServer/Services/AiDatumService.cs
Normal file
50
TaikoLocalServer/Services/AiDatumService.cs
Normal file
@ -0,0 +1,50 @@
|
||||
using TaikoLocalServer.Services.Interfaces;
|
||||
using Throw;
|
||||
|
||||
namespace TaikoLocalServer.Services;
|
||||
|
||||
public class AiDatumService : IAiDatumService
|
||||
{
|
||||
private readonly TaikoDbContext context;
|
||||
|
||||
public AiDatumService(TaikoDbContext context)
|
||||
{
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
public async Task<List<AiScoreDatum>> GetAllAiScoreById(uint baid)
|
||||
{
|
||||
return await context.AiScoreData.Where(datum => datum.Baid == baid)
|
||||
.Include(datum => datum.AiSectionScoreData)
|
||||
.ToListAsync();
|
||||
}
|
||||
|
||||
public async Task<AiScoreDatum?> GetSongAiScore(uint baid, uint songId, Difficulty difficulty)
|
||||
{
|
||||
return await context.AiScoreData.Where(datum => datum.Baid == baid &&
|
||||
datum.SongId == songId &&
|
||||
datum.Difficulty == difficulty)
|
||||
.Include(datum => datum.AiSectionScoreData)
|
||||
.FirstOrDefaultAsync();
|
||||
}
|
||||
|
||||
public async Task UpdateSongAiScore(AiScoreDatum datum)
|
||||
{
|
||||
var existing = await context.AiScoreData.FindAsync(datum.Baid, datum.SongId, datum.Difficulty);
|
||||
existing.ThrowIfNull("Cannot update a non-existing ai score!");
|
||||
|
||||
context.AiScoreData.Update(datum);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task InsertSongAiScore(AiScoreDatum datum)
|
||||
{
|
||||
var existing = await context.AiScoreData.FindAsync(datum.Baid, datum.SongId, datum.Difficulty);
|
||||
if (existing is not null)
|
||||
{
|
||||
throw new ArgumentException("Ai score already exists!", nameof(datum));
|
||||
}
|
||||
context.AiScoreData.Add(datum);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
@ -30,7 +30,7 @@ public class DanScoreDatumService : IDanScoreDatumService
|
||||
var existing = await context.DanScoreData.FindAsync(datum.Baid, datum.DanId);
|
||||
if (existing is null)
|
||||
{
|
||||
await context.DanScoreData.AddAsync(datum);
|
||||
context.DanScoreData.Add(datum);
|
||||
await context.SaveChangesAsync();
|
||||
return;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ public static class ServiceExtensions
|
||||
services.AddScoped<ISongPlayDatumService, SongPlayDatumService>();
|
||||
services.AddScoped<ISongBestDatumService, SongBestDatumService>();
|
||||
services.AddScoped<IDanScoreDatumService, DanScoreDatumService>();
|
||||
services.AddScoped<IAiDatumService, AiDatumService>();
|
||||
|
||||
return services;
|
||||
}
|
||||
|
12
TaikoLocalServer/Services/Interfaces/IAiDatumService.cs
Normal file
12
TaikoLocalServer/Services/Interfaces/IAiDatumService.cs
Normal file
@ -0,0 +1,12 @@
|
||||
namespace TaikoLocalServer.Services.Interfaces;
|
||||
|
||||
public interface IAiDatumService
|
||||
{
|
||||
public Task<List<AiScoreDatum>> GetAllAiScoreById(uint baid);
|
||||
|
||||
public Task<AiScoreDatum?> GetSongAiScore(uint baid, uint songId, Difficulty difficulty);
|
||||
|
||||
public Task UpdateSongAiScore(AiScoreDatum datum);
|
||||
|
||||
public Task InsertSongAiScore(AiScoreDatum datum);
|
||||
}
|
@ -32,7 +32,7 @@ public class SongBestDatumService : ISongBestDatumService
|
||||
return;
|
||||
}
|
||||
|
||||
await context.SongBestData.AddAsync(datum);
|
||||
context.SongBestData.Add(datum);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ class SongPlayDatumService : ISongPlayDatumService
|
||||
|
||||
public async Task AddSongPlayDatum(SongPlayDatum datum)
|
||||
{
|
||||
await context.SongPlayData.AddAsync(datum);
|
||||
context.SongPlayData.Add(datum);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user