Adds IMissionProgressService to RankBattle, FreeBattle, ArenaTwoPickBattle, and ArenaTwoPick controllers. Each finish handler emits the appropriate MissionEventKeys builder result: - RankBattle.Finish (win) → Ranked.WinAll(classId) Includes AI-rank routes; on a private server AI wins count the same. - FreeBattle.Finish (win) → Free.WinAll() (aggregates only) - ArenaTwoPickBattle.Finish → Challenge.MatchPlayAll or MatchWinAll Always fires challenge_play; wins additionally fire challenge_win and the ranked/arena/daily aggregates. - ArenaTwoPick.Finish (5-win full clear) → Challenge.FullClearAll Gated on RunFinishOutcome.WasFullClear from the previous commit. This closes six of the eight remaining catalog wire-up gaps; class_level_up and rank_achieved follow in Tier 2 (need pre-state detection). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
77 lines
2.6 KiB
C#
77 lines
2.6 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using SVSim.Database.Services;
|
|
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.ArenaTwoPick;
|
|
using SVSim.EmulatedEntrypoint.Services;
|
|
|
|
namespace SVSim.EmulatedEntrypoint.Controllers;
|
|
|
|
[Route("arena_two_pick")]
|
|
public class ArenaTwoPickController : SVSimController
|
|
{
|
|
private readonly IArenaTwoPickService _svc;
|
|
private readonly IMissionProgressService _missionProgress;
|
|
|
|
public ArenaTwoPickController(IArenaTwoPickService svc, IMissionProgressService missionProgress)
|
|
{
|
|
_svc = svc;
|
|
_missionProgress = missionProgress;
|
|
}
|
|
|
|
[HttpPost("top")]
|
|
public async Task<IActionResult> Top([FromBody] TopRequest _)
|
|
{
|
|
if (!TryGetViewerId(out var vid)) return Unauthorized();
|
|
return Ok(await _svc.GetTopAsync(vid));
|
|
}
|
|
|
|
[HttpPost("entry")]
|
|
public async Task<IActionResult> Entry([FromBody] EntryRequest req)
|
|
{
|
|
if (!TryGetViewerId(out var vid)) return Unauthorized();
|
|
return await GuardAsync(() => _svc.EntryAsync(vid, req.ConsumeItemType));
|
|
}
|
|
|
|
[HttpPost("class_choose")]
|
|
public async Task<IActionResult> ClassChoose([FromBody] ClassChooseRequest req)
|
|
{
|
|
if (!TryGetViewerId(out var vid)) return Unauthorized();
|
|
return await GuardAsync(() => _svc.ChooseClassAsync(vid, req.ClassId));
|
|
}
|
|
|
|
[HttpPost("card_choose")]
|
|
public async Task<IActionResult> CardChoose([FromBody] CardChooseRequest req)
|
|
{
|
|
if (!TryGetViewerId(out var vid)) return Unauthorized();
|
|
return await GuardAsync(() => _svc.ChooseCardAsync(vid, req.SelectedId));
|
|
}
|
|
|
|
[HttpPost("retire")]
|
|
public async Task<IActionResult> Retire([FromBody] RetireRequest _)
|
|
{
|
|
if (!TryGetViewerId(out var vid)) return Unauthorized();
|
|
return await GuardAsync(() => _svc.RetireAsync(vid));
|
|
}
|
|
|
|
[HttpPost("finish")]
|
|
public async Task<IActionResult> Finish([FromBody] FinishRequest _, CancellationToken ct = default)
|
|
{
|
|
if (!TryGetViewerId(out var vid)) return Unauthorized();
|
|
return await GuardAsync(async () =>
|
|
{
|
|
var outcome = await _svc.FinishAsync(vid);
|
|
if (outcome.WasFullClear)
|
|
{
|
|
await _missionProgress.RecordEventAsync(
|
|
vid, MissionEventKeys.Challenge.FullClearAll(), ct: ct);
|
|
}
|
|
return outcome.Response;
|
|
});
|
|
}
|
|
|
|
private async Task<IActionResult> GuardAsync<T>(Func<Task<T>> action)
|
|
{
|
|
try { return Ok(await action()); }
|
|
catch (ArenaTwoPickException ex) { return BadRequest(new { error_code = ex.ErrorCode }); }
|
|
}
|
|
}
|