feat(replay): wire finish hook for rank-battle family

Finish now consumes the stashed BattleContext, records a
ViewerBattleHistory row (idempotent + retention-capped), and
calls IPlayedTogetherWriter for human PvP (skipped for AI).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-10 08:15:12 -04:00
parent a81289311f
commit 81aac701f4
2 changed files with 100 additions and 2 deletions

View File

@@ -3,6 +3,7 @@ using Microsoft.AspNetCore.Mvc;
using SVSim.BattleNode.Bridge;
using SVSim.BattleNode.Sessions;
using SVSim.Database.Enums;
using SVSim.Database.Services.Friend;
using SVSim.Database.Services.Replay;
using SVSim.EmulatedEntrypoint.Constants;
using SVSim.EmulatedEntrypoint.Extensions;
@@ -30,6 +31,8 @@ public sealed class RankBattleController : ControllerBase
private readonly IMatchContextBuilder _ctxBuilder;
private readonly IBotRoster _botRoster;
private readonly IBattleContextStore _battleContextStore;
private readonly IBattleHistoryWriter _historyWriter;
private readonly IPlayedTogetherWriter _playedTogetherWriter;
private readonly ILogger<RankBattleController> _log;
public RankBattleController(
@@ -38,6 +41,8 @@ public sealed class RankBattleController : ControllerBase
IMatchContextBuilder ctxBuilder,
IBotRoster botRoster,
IBattleContextStore battleContextStore,
IBattleHistoryWriter historyWriter,
IPlayedTogetherWriter playedTogetherWriter,
ILogger<RankBattleController> log)
{
_resolver = resolver;
@@ -45,6 +50,8 @@ public sealed class RankBattleController : ControllerBase
_ctxBuilder = ctxBuilder;
_botRoster = botRoster;
_battleContextStore = battleContextStore;
_historyWriter = historyWriter;
_playedTogetherWriter = playedTogetherWriter;
_log = log;
}
@@ -84,9 +91,29 @@ public sealed class RankBattleController : ControllerBase
[HttpPost("/unlimited_rank_battle/finish")]
[HttpPost("/ai_rotation_rank_battle/finish")]
[HttpPost("/ai_unlimited_rank_battle/finish")]
public IActionResult Finish([FromBody] RankBattleFinishRequestDto req)
public async Task<IActionResult> Finish([FromBody] RankBattleFinishRequestDto req, CancellationToken ct)
{
if (!TryGetViewerId(out var _)) return Unauthorized();
if (!TryGetViewerId(out var vid)) return Unauthorized();
var ctx = _battleContextStore.TakeFor(vid);
bool isWin = req.BattleResult == 1;
await _historyWriter.RecordAsync(vid, ctx, isWin, ct);
// Played-together only fires for human PvP. AI bots have OpponentViewerId=0.
if (ctx is { OpponentViewerId: > 0 })
{
await _playedTogetherWriter.RecordAsync(
vid,
ctx.OpponentViewerId,
new BattleParticipationContext(
PlayedMode: 0,
BattleType: ctx.BattleType,
DeckFormat: ctx.DeckFormat,
TwoPickType: ctx.TwoPickType),
ct);
}
return Ok(new RankBattleFinishResponseDto
{
BattleResult = req.BattleResult,