fix(tk2): per-viewer is_join in arena_info + stub /arena/get_challenge_info
Bug 1 ("pay to enter again after restart"):
arena_info[0].is_join shipped from the static ArenaSeasonConfig seed,
so /load/index and /mypage/index always emitted false regardless of
viewer state. The client uses is_join to choose between the "Pay to
enter" and "Resume run" dialogs (Wizard/ChallengeEntry.cs:165 + the
ArenaEntryBase._isJoinFunc pivot). Without a per-viewer override every
cold start after a partial run looked like "no run" and the player got
charged again.
LoadController + MyPageController now compute is_join from
ViewerArenaTwoPickRuns presence. MyPageController grew an
IArenaTwoPickRunRepository dep (LoadController already had _db).
Bug 2: /arena/get_challenge_info 404. Stubbed via a new
ArenaController + DTO pair. Returns the season seed's begin/end_time
+ name where available; placeholder zeros for win history. All 6 keys
required by ChallangeHistoryInfoTask.Parse are present (unconditional
JsonData lookups).
Routing smoke added for /arena/get_challenge_info.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
59
SVSim.EmulatedEntrypoint/Controllers/ArenaController.cs
Normal file
59
SVSim.EmulatedEntrypoint/Controllers/ArenaController.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using SVSim.Database.Repositories.Globals;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Requests.Arena;
|
||||
using SVSim.EmulatedEntrypoint.Models.Dtos.Responses.Arena;
|
||||
|
||||
namespace SVSim.EmulatedEntrypoint.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Generic /arena/* family — primarily challenge-history info read by the TK2 entry screen's
|
||||
/// detail button. TODO: lifetime TK2 stats tracking; today we emit a stub.
|
||||
/// </summary>
|
||||
[Route("arena")]
|
||||
public class ArenaController : SVSimController
|
||||
{
|
||||
private readonly IGlobalsRepository _globalsRepository;
|
||||
|
||||
public ArenaController(IGlobalsRepository globalsRepository)
|
||||
{
|
||||
_globalsRepository = globalsRepository;
|
||||
}
|
||||
|
||||
[HttpPost("get_challenge_info")]
|
||||
public async Task<IActionResult> GetChallengeInfo([FromBody] GetChallengeInfoRequest req)
|
||||
{
|
||||
if (!TryGetViewerId(out _)) return Unauthorized();
|
||||
|
||||
var season = await _globalsRepository.GetCurrentArenaSeason();
|
||||
// Best-effort: pull begin/end_time + name from the season seed when present; otherwise
|
||||
// emit deterministic stub values. All 6 ChallangeHistoryInfoTask.Parse fields must be
|
||||
// present — the parser accesses them unconditionally.
|
||||
var beginTime = "2026-05-01 02:00:00";
|
||||
var endTime = "2026-06-01 01:59:59";
|
||||
var name = "Take Two";
|
||||
if (season is not null && !string.IsNullOrEmpty(season.FormatInfo) && season.FormatInfo != "{}")
|
||||
{
|
||||
try
|
||||
{
|
||||
using var doc = System.Text.Json.JsonDocument.Parse(season.FormatInfo);
|
||||
if (doc.RootElement.TryGetProperty("start_time", out var st)) beginTime = st.GetString() ?? beginTime;
|
||||
if (doc.RootElement.TryGetProperty("end_time", out var et)) endTime = et.GetString() ?? endTime;
|
||||
if (doc.RootElement.TryGetProperty("card_pool_name", out var cp)) name = cp.GetString() ?? name;
|
||||
}
|
||||
catch { /* fall back to defaults */ }
|
||||
}
|
||||
|
||||
return Ok(new GetChallengeInfoResponseDto
|
||||
{
|
||||
ChallengeName = name,
|
||||
BeginTime = beginTime,
|
||||
EndTime = endTime,
|
||||
TwoPickAllWinCount = 0,
|
||||
RewardStepInfo = new RewardStepInfoDto
|
||||
{
|
||||
MaxRewardStep = 0,
|
||||
RewardStepList = new List<int>(),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user