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:
@@ -1,5 +1,6 @@
|
||||
using System.Text.Json;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using SVSim.Database;
|
||||
using SVSim.Database.Enums;
|
||||
using SVSim.Database.Models;
|
||||
@@ -244,7 +245,7 @@ public class LoadController : SVSimController
|
||||
UseChallengePickTwoPremiumCard = challenge.UseTwoPickPremiumCard ? 1 : 0,
|
||||
ChallengePickTwoCardSleeve = (int)challenge.TwoPickSleeveId,
|
||||
},
|
||||
ArenaInfos = await BuildArenaInfosAsync(),
|
||||
ArenaInfos = await BuildArenaInfosAsync(viewer.Id),
|
||||
RotationSets = rotationSets,
|
||||
UserConfig = new UserConfig(),
|
||||
OpenBattlefieldIds = (await _globalsRepository.GetBattlefields(true))
|
||||
@@ -263,7 +264,7 @@ public class LoadController : SVSimController
|
||||
/// field is omitted on the wire, which the client's <c>Keys.Contains("arena_info")</c> guard
|
||||
/// (LoadDetail.cs:261) handles cleanly.
|
||||
/// </summary>
|
||||
private async Task<List<ArenaInfo>?> BuildArenaInfosAsync()
|
||||
private async Task<List<ArenaInfo>?> BuildArenaInfosAsync(long viewerId)
|
||||
{
|
||||
var season = await _globalsRepository.GetCurrentArenaSeason();
|
||||
if (season is null) return null;
|
||||
@@ -274,6 +275,15 @@ public class LoadController : SVSimController
|
||||
format = JsonSerializer.Deserialize<ArenaFormatInfo>(season.FormatInfo, JsonbReadOptions.Instance);
|
||||
}
|
||||
|
||||
// is_join must reflect the viewer's actual TK2 state — true if they have an
|
||||
// active ViewerArenaTwoPickRun row. The client uses this to decide between the
|
||||
// "Pay to enter" and "Resume run" dialogs (Wizard/ChallengeEntry.cs:165 + ArenaEntryBase).
|
||||
// Without a per-viewer override here, every cold start after a partial run shows
|
||||
// "Pay to enter" — losing the in-progress draft from the player's perspective.
|
||||
bool hasActiveRun = await _db.ViewerArenaTwoPickRuns
|
||||
.AsNoTracking()
|
||||
.AnyAsync(r => r.ViewerId == viewerId);
|
||||
|
||||
return new List<ArenaInfo>
|
||||
{
|
||||
new ArenaInfo
|
||||
@@ -283,7 +293,7 @@ public class LoadController : SVSimController
|
||||
Cost = season.Cost,
|
||||
RupeeCost = season.RupyCost,
|
||||
TicketCost = season.TicketCost,
|
||||
IsJoin = season.IsJoin,
|
||||
IsJoin = hasActiveRun,
|
||||
FormatInfo = format,
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user