// AUTHORED SHIM (not copied). Per-battle ambient context that backs the // AsyncLocal singleton seam for multi-instancing (see docs/superpowers/specs/ // 2026-06-07-engine-multi-instancing-design.md). The engine's per-battle // statics (BattleManagerBase.main/IsForecast/IsRandomDraw, GameMgr.GetIns, // Certification.viewer_id, ToolboxGame.RealTimeNetworkAgent, // Data.BattleRecoveryInfo) resolve through Current when set; process-shared // reference data (CardMaster.Default, Data.Master, etc.) stays static. #nullable enable using System; using System.Threading; namespace SVSim.BattleEngine.Ambient; public sealed class BattleAmbientContext { public BattleManagerBase? Mgr { get; set; } public GameMgr GameMgr { get; init; } = new(); public RealTimeNetworkAgent? NetworkAgent { get; set; } public int ViewerId { get; init; } = 1001; public bool IsForecast { get; set; } = true; public bool IsRandomDraw { get; set; } = true; public Wizard.BattleRecoveryInfo? RecoveryInfo { get; set; } } public static class BattleAmbient { internal static readonly AsyncLocal _current = new(); public static BattleAmbientContext? Current => _current.Value; public static BattleAmbientContext Require() => _current.Value ?? throw new InvalidOperationException( "No ambient battle context. Wrap engine entry points in BattleAmbient.Enter(ctx)."); public static Scope Enter(BattleAmbientContext ctx) { var prior = _current.Value; _current.Value = ctx; return new Scope(prior); } public readonly struct Scope : IDisposable { private readonly BattleAmbientContext? _prior; internal Scope(BattleAmbientContext? prior) { _prior = prior; } public void Dispose() => _current.Value = _prior; } }