engine cleanup passes 4-7 + multi-instancing ambient rip

Squashes 146 commits from battle-engine-extraction. Net: 2,045 files changed,
+11,896 / -158,687 lines. Ships engine passes 4-7 (dead-code cull, view-layer
stub, receive-path shrink) plus the Phase-5 AsyncLocal ambient deletion that
turns concurrent battles into a type-system property rather than a scope
contract.

## What landed

**Passes 4-7 (chunks 1-34):** Extended the Phase-4 const-false collapse into a
cascading cull across the skill graph, view layer, and receive-path periphery.
Six mode flags (IsWatchBattle/IsReplayBattle/IsAdmin/IsAdminWatch/IsPuzzleQuest/
IsAINetwork) became `const false`, every guarded block deleted. Field*.cs
subclass ctors + BackGroundBase + ObjectChecker culled to no-ops. Mulligan
family reworked to take a mgr param through IMulliganMgr.InitMulligan.
Emotion/Recovery/Resource clusters null-stubbed. Prediction/OperationSimulator/
skill filters converted from static ambient reads to per-mgr reads via
SkillPrm.ownerCard.SelfBattlePlayer.BattleMgr / ins.BattleMgr / this.BattleMgr.

**Phase-5 ambient rip (chunks 35-47):** Deleted BattleAmbient / BattleAmbient-
Context / TestBattleScope in full. Every per-battle mutable slot now lives on
the mgr instance itself:
  mgr.InstanceIsForecast / InstanceIsRandomDraw / InstanceRecoveryInfo /
  InstanceViewerId / InstanceNetworkAgent / GameMgr
BattleManagerBase.GetIns() returns null unconditionally; the residual static
flags + 3 façades (Certification.ViewerId, Data.BattleRecoveryInfo,
ToolboxGame.RealTimeNetworkAgent) are null-tolerant defaults kept for the
handful of engine-internal readers that still reference their types. Zero
BattleAmbient references anywhere in engine + node + tests.

Added pre-seeded GameMgr ctor overload threaded through the mgr chain
(BattleManagerBase → SingleBattleMgr / NetworkBattleManagerBase → NetworkStandard-
BattleMgr → HeadlessBattleMgr / HeadlessNetworkBattleMgr). Fixtures build a
GameMgr, seed it via HeadlessEngineEnv.SeedCharaIds/SeedNetUser, and pass it
to the mgr's ctor — no ambient reach.

Node side (SVSim.BattleNode/SessionBattleEngine): _ctx replaced with a plain
GameMgr field; 34 `using var _ambient = BattleAmbient.Enter(_ctx)` scope wraps
ripped from every accessor and mutator; EngineGlobalInit.WirePerSessionGameMgr
takes GameMgr as a param and runs from SessionBattleEngine.SetupInternal
BEFORE mgr construction.

Test side: TestBattleScope deleted; 18 fixture [SetUp]s migrated to
`HeadlessEngineEnv.EnsureProcessGlobals()`; MultiInstanceEngineTests rewritten
around per-mgr construction (GetIns() → null is the pinned invariant).

## Regression fixes

- **chunk-48** (MulliganCtrl): chunk-35's `= null` stubs on card lookups broke
  the live receive-driven Deal path (BattlePlayerBase.DrawCard NRE'd downstream
  of NetworkPlayerMulliganCtrl.StartMulliganVfx). Restored the three lookups
  via `_battlePlayer.BattleMgr.GetBattleCardIdx`. Engine tests were satisfied
  by the WireMulliganPhase seam; unit tests exposed the live-path gap.

## Ship state

- SVSim.BattleEngine.Tests: 56/56 pass, 2 skip
- SVSim.UnitTests: 1554/1554 pass (was 1523/31-fail before chunk 48)
- Solution build: 0 source warnings (40 pre-existing NU1902 MessagePack CVEs
  in SVSim.EmulatedEntrypoint, unrelated)
- Sequential PVP smoke: verified live (two back-to-back battles, no regression
  on cleanup/spinup)
- Concurrent PVP smoke: verified live

Adds tools/engine-port/ClosureAnalyzer/ — the Roslyn transitive-type-closure
analyzer needed to make future cascade cleanup safe (per feedback memory
"Engine cleanup needs closure tool" from the 2026-06-28 pass-3 failure).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-07-03 19:18:54 -04:00
parent 5c1db83967
commit 2d9a6eea4b
2045 changed files with 11704 additions and 158495 deletions

View File

@@ -11,7 +11,6 @@ public class UILabel : UIWidget
public enum Effect
{
None,
Shadow,
Outline,
Outline8
}
@@ -26,12 +25,7 @@ public class UILabel : UIWidget
public enum Crispness
{
Never,
OnDesktop,
Always
}
public Crispness keepCrispWhenShrunk = Crispness.OnDesktop;
}
private static bool OnFontChangedFlg = false;
@@ -210,8 +204,6 @@ public class UILabel : UIWidget
private string _originalText;
public Action OnWindowResize;
private static BetterList<UILabel> mList = new BetterList<UILabel>();
private static Dictionary<UnityEngine.Font, int> mFontUsage = new Dictionary<UnityEngine.Font, int>();
@@ -234,18 +226,6 @@ public class UILabel : UIWidget
public float DotMargin => m_WizardDotMargin;
public int finalFontSize
{
get
{
if ((bool)trueTypeFont)
{
return Mathf.RoundToInt(mScale * (float)mFinalFontSize);
}
return Mathf.RoundToInt((float)mFinalFontSize * mScale);
}
}
private bool shouldBeProcessed
{
get
@@ -319,19 +299,6 @@ public class UILabel : UIWidget
}
}
[Obsolete("Use UILabel.bitmapFont instead")]
public UIFont font
{
get
{
return bitmapFont;
}
set
{
bitmapFont = value;
}
}
public UIFont bitmapFont
{
get
@@ -471,23 +438,6 @@ public class UILabel : UIWidget
}
}
public FontStyle fontStyle
{
get
{
return mFontStyle;
}
set
{
if (mFontStyle != value)
{
mFontStyle = value;
shouldBeProcessed = true;
ProcessAndRequest();
}
}
}
public NGUIText.Alignment alignment
{
get
@@ -570,22 +520,6 @@ public class UILabel : UIWidget
}
}
public int spacingX
{
get
{
return mSpacingX;
}
set
{
if (mSpacingX != value)
{
mSpacingX = value;
MarkAsChanged();
}
}
}
public int spacingY
{
get
@@ -602,54 +536,6 @@ public class UILabel : UIWidget
}
}
public bool useFloatSpacing
{
get
{
return mUseFloatSpacing;
}
set
{
if (mUseFloatSpacing != value)
{
mUseFloatSpacing = value;
shouldBeProcessed = true;
}
}
}
public float floatSpacingX
{
get
{
return mFloatSpacingX;
}
set
{
if (!Mathf.Approximately(mFloatSpacingX, value))
{
mFloatSpacingX = value;
MarkAsChanged();
}
}
}
public float floatSpacingY
{
get
{
return mFloatSpacingY;
}
set
{
if (!Mathf.Approximately(mFloatSpacingY, value))
{
mFloatSpacingY = value;
MarkAsChanged();
}
}
}
public float effectiveSpacingY
{
get
@@ -708,22 +594,6 @@ public class UILabel : UIWidget
}
}
public NGUIText.SymbolStyle symbolStyle
{
get
{
return mSymbols;
}
set
{
if (mSymbols != value)
{
mSymbols = value;
shouldBeProcessed = true;
}
}
}
public Overflow overflowMethod
{
get
@@ -740,32 +610,6 @@ public class UILabel : UIWidget
}
}
[Obsolete("Use 'width' instead")]
public int lineWidth
{
get
{
return base.width;
}
set
{
base.width = value;
}
}
[Obsolete("Use 'height' instead")]
public int lineHeight
{
get
{
return base.height;
}
set
{
base.height = value;
}
}
public bool multiLine
{
get
@@ -889,22 +733,6 @@ public class UILabel : UIWidget
}
}
[Obsolete("Use 'overflowMethod == UILabel.Overflow.ShrinkContent' instead")]
public bool shrinkToFit
{
get
{
return mOverflow == Overflow.ShrinkContent;
}
set
{
if (value)
{
overflowMethod = Overflow.ShrinkContent;
}
}
}
public string processedText
{
get
@@ -965,18 +793,6 @@ public class UILabel : UIWidget
text = Global.GetConvertWrapText(this, s);
}
public void WrapOnResize()
{
if (_originalText != null)
{
text = Global.GetConvertWrapText(this, _originalText);
}
if (OnWindowResize != null)
{
OnWindowResize();
}
}
protected override void OnInit()
{
base.OnInit();
@@ -1131,17 +947,6 @@ public class UILabel : UIWidget
}
}
public void RefreshCustom()
{
SetActiveFont(null);
mList.Remove(this);
RemoveFromPanel();
if (base.isActiveAndEnabled)
{
base.OnEnable();
}
}
protected override void OnStart()
{
base.OnStart();
@@ -1310,12 +1115,6 @@ public class UILabel : UIWidget
}
}
private IEnumerator FontRefreshCoroutine()
{
yield return null;
Invalidate(includeChildren: false);
}
private static void FontReflash(UnityEngine.Font font)
{
OnFontChangedFlg = false;
@@ -1420,46 +1219,6 @@ public class UILabel : UIWidget
}
}
[Obsolete("Use UILabel.GetCharacterAtPosition instead")]
public int GetCharacterIndex(Vector3 worldPos)
{
return GetCharacterIndexAtPosition(worldPos, precise: false);
}
[Obsolete("Use UILabel.GetCharacterAtPosition instead")]
public int GetCharacterIndex(Vector2 localPos)
{
return GetCharacterIndexAtPosition(localPos, precise: false);
}
public int GetCharacterIndexAtPositionRangeSpecification(Vector3 worldPos, List<int[]> rangeList)
{
if (isValid)
{
Vector2 pos = base.cachedTransform.InverseTransformPoint(worldPos);
string value = processedText;
if (string.IsNullOrEmpty(value))
{
return 0;
}
UpdateNGUIText();
NGUIText.PrintApproximateCharacterPositions(value, mTempVerts, mTempIndices);
if (mTempVerts.size > 0)
{
ApplyOffset(mTempVerts, 0);
int nearCharacterIndex = NGUIText.GetNearCharacterIndex(mTempVerts, mTempIndices, pos, rangeList);
mTempVerts.Clear();
mTempIndices.Clear();
NGUIText.bitmapFont = null;
NGUIText.dynamicFont = null;
return nearCharacterIndex;
}
NGUIText.bitmapFont = null;
NGUIText.dynamicFont = null;
}
return 0;
}
public int GetCharacterIndexAtPosition(Vector3 worldPos, bool precise)
{
Vector2 localPos = base.cachedTransform.InverseTransformPoint(worldPos);
@@ -1500,137 +1259,6 @@ public class UILabel : UIWidget
return 0;
}
public string GetWordAtPosition(Vector3 worldPos)
{
int characterIndexAtPosition = GetCharacterIndexAtPosition(worldPos, precise: true);
return GetWordAtCharacterIndex(characterIndexAtPosition);
}
public string GetWordAtPosition(Vector2 localPos)
{
int characterIndexAtPosition = GetCharacterIndexAtPosition(localPos, precise: true);
return GetWordAtCharacterIndex(characterIndexAtPosition);
}
public string GetWordAtCharacterIndex(int characterIndex)
{
if (characterIndex != -1 && characterIndex < mText.Length)
{
int num = mText.LastIndexOfAny(new char[2] { ' ', '\n' }, characterIndex) + 1;
int num2 = mText.IndexOfAny(new char[4] { ' ', '\n', ',', '.' }, characterIndex);
if (num2 == -1)
{
num2 = mText.Length;
}
if (num != num2)
{
int num3 = num2 - num;
if (num3 > 0)
{
return NGUIText.StripSymbols(mText.Substring(num, num3));
}
}
}
return null;
}
public string GetUrlAtPosition(Vector3 worldPos)
{
return GetUrlAtCharacterIndex(GetCharacterIndexAtPosition(worldPos, precise: true));
}
public string GetUrlAtPosition(Vector2 localPos)
{
return GetUrlAtCharacterIndex(GetCharacterIndexAtPosition(localPos, precise: true));
}
public string GetUrlAtCharacterIndex(int characterIndex)
{
if (characterIndex != -1 && characterIndex < mText.Length - 6)
{
int num = ((mText[characterIndex] != '[' || mText[characterIndex + 1] != 'u' || mText[characterIndex + 2] != 'r' || mText[characterIndex + 3] != 'l' || mText[characterIndex + 4] != '=') ? mText.LastIndexOf("[url=", characterIndex) : characterIndex);
if (num == -1)
{
return null;
}
num += 5;
int num2 = mText.IndexOf("]", num);
if (num2 == -1)
{
return null;
}
int num3 = mText.IndexOf("[/url]", num2);
if (num3 == -1 || characterIndex <= num3)
{
return mText.Substring(num, num2 - num);
}
}
return null;
}
public int GetCharacterIndex(int currentIndex, KeyCode key)
{
if (isValid)
{
string text = processedText;
if (string.IsNullOrEmpty(text))
{
return 0;
}
int num = defaultFontSize;
UpdateNGUIText();
NGUIText.PrintApproximateCharacterPositions(text, mTempVerts, mTempIndices);
if (mTempVerts.size > 0)
{
ApplyOffset(mTempVerts, 0);
for (int i = 0; i < mTempIndices.size; i++)
{
if (mTempIndices[i] == currentIndex)
{
Vector2 pos = mTempVerts[i];
switch (key)
{
case KeyCode.UpArrow:
pos.y += (float)num + effectiveSpacingY;
break;
case KeyCode.DownArrow:
pos.y -= (float)num + effectiveSpacingY;
break;
case KeyCode.Home:
pos.x -= 1000f;
break;
case KeyCode.End:
pos.x += 1000f;
break;
}
int approximateCharacterIndex = NGUIText.GetApproximateCharacterIndex(mTempVerts, mTempIndices, pos);
if (approximateCharacterIndex == currentIndex)
{
break;
}
mTempVerts.Clear();
mTempIndices.Clear();
return approximateCharacterIndex;
}
}
mTempVerts.Clear();
mTempIndices.Clear();
}
NGUIText.bitmapFont = null;
NGUIText.dynamicFont = null;
switch (key)
{
case KeyCode.UpArrow:
case KeyCode.Home:
return 0;
case KeyCode.DownArrow:
case KeyCode.End:
return text.Length;
}
}
return currentIndex;
}
public void PrintOverlay(int start, int end, UIGeometry caret, UIGeometry highlight, Color caretColor, Color highlightColor)
{
caret?.Clear();
@@ -1798,30 +1426,6 @@ public class UILabel : UIWidget
return result;
}
public void SetCurrentProgress()
{
if (UIProgressBar.current != null)
{
text = UIProgressBar.current.value.ToString("F");
}
}
public void SetCurrentPercent()
{
if (UIProgressBar.current != null)
{
text = Mathf.RoundToInt(UIProgressBar.current.value * 100f) + "%";
}
}
public void SetCurrentSelection()
{
if (UIPopupList.current != null)
{
text = (UIPopupList.current.isLocalized ? Localization.Get(UIPopupList.current.value) : UIPopupList.current.value);
}
}
public bool Wrap(string text, out string final)
{
return Wrap(text, out final, 1000000);
@@ -1930,12 +1534,4 @@ public class UILabel : UIWidget
}
NGUIText.Update(base.rawPivot);
}
private void OnApplicationPause(bool paused)
{
if (!paused && mTrueTypeFont != null)
{
Invalidate(includeChildren: false);
}
}
}