Files
SVSimServer/SVSim.EmulatedEntrypoint/Controllers/ArenaTwoPickController.cs
gamer147 94622a526d refactor(arena-tk2): FinishAsync returns RunFinishOutcome with WasFullClear signal
Introduces RunFinishOutcome — a semantic record that wraps the wire
FinishResponseDto with the controller-side WasFullClear signal used to fire
the challenge_full_clear mission event. The wire response isn't affected
(controller unwraps the .Response field before returning to the client);
RetireAsync stays returning FinishResponseDto because retire cannot full-clear.

Full-clear detection compares run.WinCount against ResolveMaxBattleCountAsync
rather than hard-coding 5, so a future TK2 rules-config change tracks
automatically. New test covers the full-clear signal explicitly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-07-04 13:17:23 -04:00

65 lines
2.2 KiB
C#

using Microsoft.AspNetCore.Mvc;
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;
public ArenaTwoPickController(IArenaTwoPickService svc) => _svc = svc;
[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 _)
{
if (!TryGetViewerId(out var vid)) return Unauthorized();
return await GuardAsync(async () =>
{
var outcome = await _svc.FinishAsync(vid);
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 }); }
}
}