feat(arena-tk2): SoloDefaultsToScripted config flag for dev convenience

Adds BattleNodeOptions.SoloDefaultsToScripted (default false). When true,
the TK2 do_matching controller treats every solo poll as if ?scripted=1
were passed and returns a Scripted 3004 match immediately — useful for
the live client (which can't append query params) to drive the scripted
bot without needing a second player.

Toggle via "BattleNode:SoloDefaultsToScripted" in appsettings*.json
(Program.cs now binds the BattleNode section over the AddBattleNode
defaults). Turn off to test real PvP with two clients.

Trade-off documented on the option: while on, two simultaneous pollers
each get their own Scripted match instead of pairing, so PvP is
effectively disabled until the flag is flipped.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-01 23:48:14 -04:00
parent 8112b3f81f
commit 0095bdf0cf
5 changed files with 58 additions and 3 deletions

View File

@@ -14,17 +14,20 @@ public class ArenaTwoPickBattleController : SVSimController
private readonly IMatchingBridge _matching;
private readonly IMatchContextBuilder _matchContextBuilder;
private readonly IMatchingPairUpService _pairUp;
private readonly BattleNodeOptions _battleNodeOptions;
public ArenaTwoPickBattleController(
IArenaTwoPickService svc,
IMatchingBridge matching,
IMatchContextBuilder matchContextBuilder,
IMatchingPairUpService pairUp)
IMatchingPairUpService pairUp,
BattleNodeOptions battleNodeOptions)
{
_svc = svc;
_matching = matching;
_matchContextBuilder = matchContextBuilder;
_pairUp = pairUp;
_battleNodeOptions = battleNodeOptions;
}
[HttpPost("do_matching")]
@@ -36,8 +39,12 @@ public class ArenaTwoPickBattleController : SVSimController
if (!TryGetViewerId(out var vid)) return Unauthorized();
// Accept "1" or "true" (case-insensitive) as opt-in for the legacy Scripted path.
// ASP.NET's default bool binder rejects "1", so do a permissive parse here.
var useScripted = scripted is not null
&& (scripted == "1" || string.Equals(scripted, "true", StringComparison.OrdinalIgnoreCase));
// The server-side BattleNodeOptions.SoloDefaultsToScripted flag is the other
// route — it bypasses pair-up for every solo poll, useful when the live client
// (which can't append query params) needs a Scripted match.
var useScripted = (scripted is not null
&& (scripted == "1" || string.Equals(scripted, "true", StringComparison.OrdinalIgnoreCase)))
|| _battleNodeOptions.SoloDefaultsToScripted;
try
{
var ctx = await _matchContextBuilder.BuildForTwoPickAsync(vid);

View File

@@ -124,6 +124,9 @@ public class Program
// Matches the prod do_matching wire format: host:port/socket.io/, no scheme prefix.
// BestHTTP's SocketManager parses this as the Socket.IO v2 endpoint URL.
opt.NodeServerUrl = "localhost:5148/socket.io/";
// Any field in BattleNodeOptions can be overridden via the "BattleNode" section
// in appsettings*.json — see appsettings.Development.json for SoloDefaultsToScripted.
builder.Configuration.GetSection("BattleNode").Bind(opt);
});
// In-process FCFS pair-up for TK2 PvP /do_matching. Singleton: per-mode state is
// process-wide. Proper queue API is a separate spec; this is enough to actually

View File

@@ -4,5 +4,8 @@
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"BattleNode": {
"SoloDefaultsToScripted": false
}
}