fix(arena-tk2): park returns 3002 RETRY + empty node_server_url
Two client-crash bugs in the do_matching response when no partner is waiting: 1. matching_state was 3001 (RC_BATTLE_MATCHING_ILLEGAL); the client's Matching.OnFinishedDoMatching switch maps that to an error dialog, not a retry. The retry state is 3002 (RC_BATTLE_MATCHING_RETRY). 2. node_server_url was omitted entirely. The client's DoMatchingBase.SettingDoMatchingData reads it via data["node_server_url"].ToString() with no Keys.Contains guard, so absence throws KeyNotFoundException out of NetworkManager.Connect before the matching_state switch is even reached. Prod RETRY captures send "" while waiting and the real URL only on SUCCEEDED; match that. battle_id stays absent; its accessor IS guarded. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -62,10 +62,16 @@ public class ArenaTwoPickBattleController : SVSimController
|
||||
ct);
|
||||
if (paired is null)
|
||||
{
|
||||
// 3002 = RC_BATTLE_MATCHING_RETRY: client polls again. 3001 is ILLEGAL
|
||||
// and shows an error dialog on the client side. node_server_url must be
|
||||
// present (the client's DoMatchingBase.SettingDoMatchingData calls
|
||||
// .ToString() on it without a Keys.Contains guard); prod sends "" while
|
||||
// waiting and the real URL only on SUCCEEDED. battle_id stays absent
|
||||
// (its accessor IS guarded).
|
||||
return Ok(new DoMatchingResponseDto
|
||||
{
|
||||
MatchingState = 3001,
|
||||
// BattleId / NodeServerUrl null — client polls again.
|
||||
MatchingState = 3002,
|
||||
NodeServerUrl = "",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ public class ArenaTwoPickBattleControllerTests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DoMatching_solo_poller_returns_3001_RETRY_with_no_BattleId()
|
||||
public async Task DoMatching_solo_poller_returns_3002_RETRY_with_no_BattleId_but_empty_NodeServerUrl()
|
||||
{
|
||||
using var factory = new SVSimTestFactory();
|
||||
var vid = await factory.SeedViewerAsync();
|
||||
@@ -58,11 +58,17 @@ public class ArenaTwoPickBattleControllerTests
|
||||
using var doc = JsonDocument.Parse(body);
|
||||
var root = doc.RootElement;
|
||||
|
||||
Assert.That(root.GetProperty("matching_state").GetInt32(), Is.EqualTo(3001));
|
||||
// BattleId should be ABSENT from the JSON (WhenWritingNull) — TryGetProperty
|
||||
// returns false when the key isn't present.
|
||||
// 3002 = RC_BATTLE_MATCHING_RETRY (client polls again). 3001 is ILLEGAL and
|
||||
// pops an error dialog on the client.
|
||||
Assert.That(root.GetProperty("matching_state").GetInt32(), Is.EqualTo(3002));
|
||||
// battle_id must be ABSENT from the JSON; the client's accessor IS guarded with
|
||||
// Keys.Contains so absence is the safe shape (matches prod RETRY captures).
|
||||
Assert.That(root.TryGetProperty("battle_id", out _), Is.False,
|
||||
"battle_id must be absent from the wire when matching_state==3001 RETRY.");
|
||||
"battle_id must be absent from the wire when matching_state==3002 RETRY.");
|
||||
// node_server_url MUST be present (empty string while waiting, the real URL on
|
||||
// SUCCEEDED). Client's DoMatchingBase.SettingDoMatchingData calls .ToString() on
|
||||
// it without a Keys.Contains guard, so absence throws KeyNotFoundException.
|
||||
Assert.That(root.GetProperty("node_server_url").GetString(), Is.EqualTo(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -107,8 +113,8 @@ public class ArenaTwoPickBattleControllerTests
|
||||
// A polls first (parks).
|
||||
var respA1 = await clientA.PostAsync("/arena_two_pick_battle/do_matching", JsonContent.Create(req));
|
||||
using var docA1 = JsonDocument.Parse(await respA1.Content.ReadAsStringAsync());
|
||||
Assert.That(docA1.RootElement.GetProperty("matching_state").GetInt32(), Is.EqualTo(3001),
|
||||
"A's first poll parks.");
|
||||
Assert.That(docA1.RootElement.GetProperty("matching_state").GetInt32(), Is.EqualTo(3002),
|
||||
"A's first poll parks (3002 = RETRY).");
|
||||
|
||||
// B polls (pairs).
|
||||
var respB = await clientB.PostAsync("/arena_two_pick_battle/do_matching", JsonContent.Create(req));
|
||||
|
||||
Reference in New Issue
Block a user