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:
@@ -10,21 +10,6 @@ public static class NGUIMath
|
||||
return from * (1f - factor) + to * factor;
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static int ClampIndex(int val, int max)
|
||||
{
|
||||
if (val >= 0)
|
||||
{
|
||||
if (val >= max)
|
||||
{
|
||||
return max - 1;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static int RepeatIndex(int val, int max)
|
||||
@@ -44,28 +29,6 @@ public static class NGUIMath
|
||||
return val;
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static float WrapAngle(float angle)
|
||||
{
|
||||
while (angle > 180f)
|
||||
{
|
||||
angle -= 360f;
|
||||
}
|
||||
while (angle < -180f)
|
||||
{
|
||||
angle += 360f;
|
||||
}
|
||||
return angle;
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static float Wrap01(float val)
|
||||
{
|
||||
return val - (float)Mathf.FloorToInt(val);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static int HexToDecimal(char ch)
|
||||
@@ -115,29 +78,6 @@ public static class NGUIMath
|
||||
}
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static char DecimalToHexChar(int num)
|
||||
{
|
||||
if (num > 15)
|
||||
{
|
||||
return 'F';
|
||||
}
|
||||
if (num < 10)
|
||||
{
|
||||
return (char)(48 + num);
|
||||
}
|
||||
return (char)(65 + num - 10);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static string DecimalToHex8(int num)
|
||||
{
|
||||
num &= 0xFF;
|
||||
return num.ToString("X2");
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static string DecimalToHex24(int num)
|
||||
@@ -160,43 +100,6 @@ public static class NGUIMath
|
||||
return 0 | (Mathf.RoundToInt(c.r * 255f) << 24) | (Mathf.RoundToInt(c.g * 255f) << 16) | (Mathf.RoundToInt(c.b * 255f) << 8) | Mathf.RoundToInt(c.a * 255f);
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static Color IntToColor(int val)
|
||||
{
|
||||
float num = 0.003921569f;
|
||||
Color black = Color.black;
|
||||
black.r = num * (float)((val >> 24) & 0xFF);
|
||||
black.g = num * (float)((val >> 16) & 0xFF);
|
||||
black.b = num * (float)((val >> 8) & 0xFF);
|
||||
black.a = num * (float)(val & 0xFF);
|
||||
return black;
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static string IntToBinary(int val, int bits)
|
||||
{
|
||||
string text = "";
|
||||
int num = bits;
|
||||
while (num > 0)
|
||||
{
|
||||
if (num == 8 || num == 16 || num == 24)
|
||||
{
|
||||
text += " ";
|
||||
}
|
||||
text += (((val & (1 << --num)) != 0) ? '1' : '0');
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static Color HexToColor(uint val)
|
||||
{
|
||||
return IntToColor((int)val);
|
||||
}
|
||||
|
||||
public static Rect ConvertToTexCoords(Rect rect, int width, int height)
|
||||
{
|
||||
Rect result = rect;
|
||||
@@ -230,25 +133,6 @@ public static class NGUIMath
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Rect MakePixelPerfect(Rect rect)
|
||||
{
|
||||
rect.xMin = Mathf.RoundToInt(rect.xMin);
|
||||
rect.yMin = Mathf.RoundToInt(rect.yMin);
|
||||
rect.xMax = Mathf.RoundToInt(rect.xMax);
|
||||
rect.yMax = Mathf.RoundToInt(rect.yMax);
|
||||
return rect;
|
||||
}
|
||||
|
||||
public static Rect MakePixelPerfect(Rect rect, int width, int height)
|
||||
{
|
||||
rect = ConvertToPixels(rect, width, height, round: true);
|
||||
rect.xMin = Mathf.RoundToInt(rect.xMin);
|
||||
rect.yMin = Mathf.RoundToInt(rect.yMin);
|
||||
rect.xMax = Mathf.RoundToInt(rect.xMax);
|
||||
rect.yMax = Mathf.RoundToInt(rect.yMax);
|
||||
return ConvertToTexCoords(rect, width, height);
|
||||
}
|
||||
|
||||
public static Vector2 ConstrainRect(Vector2 minRect, Vector2 maxRect, Vector2 minArea, Vector2 maxArea)
|
||||
{
|
||||
Vector2 zero = Vector2.zero;
|
||||
@@ -483,138 +367,6 @@ public static class NGUIMath
|
||||
return vector * 0.06f;
|
||||
}
|
||||
|
||||
public static Vector2 SpringDampen(ref Vector2 velocity, float strength, float deltaTime)
|
||||
{
|
||||
if (deltaTime > 1f)
|
||||
{
|
||||
deltaTime = 1f;
|
||||
}
|
||||
float f = 1f - strength * 0.001f;
|
||||
int num = Mathf.RoundToInt(deltaTime * 1000f);
|
||||
float num2 = Mathf.Pow(f, num);
|
||||
Vector2 vector = velocity * ((num2 - 1f) / Mathf.Log(f));
|
||||
velocity *= num2;
|
||||
return vector * 0.06f;
|
||||
}
|
||||
|
||||
public static float SpringLerp(float strength, float deltaTime)
|
||||
{
|
||||
if (deltaTime > 1f)
|
||||
{
|
||||
deltaTime = 1f;
|
||||
}
|
||||
int num = Mathf.RoundToInt(deltaTime * 1000f);
|
||||
deltaTime = 0.001f * strength;
|
||||
float num2 = 0f;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
num2 = Mathf.Lerp(num2, 1f, deltaTime);
|
||||
}
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static float SpringLerp(float from, float to, float strength, float deltaTime)
|
||||
{
|
||||
if (deltaTime > 1f)
|
||||
{
|
||||
deltaTime = 1f;
|
||||
}
|
||||
int num = Mathf.RoundToInt(deltaTime * 1000f);
|
||||
deltaTime = 0.001f * strength;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
from = Mathf.Lerp(from, to, deltaTime);
|
||||
}
|
||||
return from;
|
||||
}
|
||||
|
||||
public static Vector2 SpringLerp(Vector2 from, Vector2 to, float strength, float deltaTime)
|
||||
{
|
||||
return Vector2.Lerp(from, to, SpringLerp(strength, deltaTime));
|
||||
}
|
||||
|
||||
public static Vector3 SpringLerp(Vector3 from, Vector3 to, float strength, float deltaTime)
|
||||
{
|
||||
return Vector3.Lerp(from, to, SpringLerp(strength, deltaTime));
|
||||
}
|
||||
|
||||
public static Quaternion SpringLerp(Quaternion from, Quaternion to, float strength, float deltaTime)
|
||||
{
|
||||
return Quaternion.Slerp(from, to, SpringLerp(strength, deltaTime));
|
||||
}
|
||||
|
||||
public static float RotateTowards(float from, float to, float maxAngle)
|
||||
{
|
||||
float num = WrapAngle(to - from);
|
||||
if (Mathf.Abs(num) > maxAngle)
|
||||
{
|
||||
num = maxAngle * Mathf.Sign(num);
|
||||
}
|
||||
return from + num;
|
||||
}
|
||||
|
||||
private static float DistancePointToLineSegment(Vector2 point, Vector2 a, Vector2 b)
|
||||
{
|
||||
float sqrMagnitude = (b - a).sqrMagnitude;
|
||||
if (sqrMagnitude == 0f)
|
||||
{
|
||||
return (point - a).magnitude;
|
||||
}
|
||||
float num = Vector2.Dot(point - a, b - a) / sqrMagnitude;
|
||||
if (num < 0f)
|
||||
{
|
||||
return (point - a).magnitude;
|
||||
}
|
||||
if (num > 1f)
|
||||
{
|
||||
return (point - b).magnitude;
|
||||
}
|
||||
Vector2 vector = a + num * (b - a);
|
||||
return (point - vector).magnitude;
|
||||
}
|
||||
|
||||
public static float DistanceToRectangle(Vector2[] screenPoints, Vector2 mousePos)
|
||||
{
|
||||
bool flag = false;
|
||||
int val = 4;
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
Vector3 vector = screenPoints[RepeatIndex(i, 4)];
|
||||
Vector3 vector2 = screenPoints[RepeatIndex(val, 4)];
|
||||
if (vector.y > mousePos.y != vector2.y > mousePos.y && mousePos.x < (vector2.x - vector.x) * (mousePos.y - vector.y) / (vector2.y - vector.y) + vector.x)
|
||||
{
|
||||
flag = !flag;
|
||||
}
|
||||
val = i;
|
||||
}
|
||||
if (!flag)
|
||||
{
|
||||
float num = -1f;
|
||||
for (int j = 0; j < 4; j++)
|
||||
{
|
||||
Vector3 vector3 = screenPoints[j];
|
||||
Vector3 vector4 = screenPoints[RepeatIndex(j + 1, 4)];
|
||||
float num2 = DistancePointToLineSegment(mousePos, vector3, vector4);
|
||||
if (num2 < num || num < 0f)
|
||||
{
|
||||
num = num2;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
return 0f;
|
||||
}
|
||||
|
||||
public static float DistanceToRectangle(Vector3[] worldPoints, Vector2 mousePos, Camera cam)
|
||||
{
|
||||
Vector2[] array = new Vector2[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
array[i] = cam.WorldToScreenPoint(worldPoints[i]);
|
||||
}
|
||||
return DistanceToRectangle(array, mousePos);
|
||||
}
|
||||
|
||||
public static Vector2 GetPivotOffset(UIWidget.Pivot pv)
|
||||
{
|
||||
Vector2 zero = Vector2.zero;
|
||||
@@ -690,11 +442,6 @@ public static class NGUIMath
|
||||
return UIWidget.Pivot.Center;
|
||||
}
|
||||
|
||||
public static void MoveWidget(UIRect w, float x, float y)
|
||||
{
|
||||
MoveRect(w, x, y);
|
||||
}
|
||||
|
||||
public static void MoveRect(UIRect rect, float x, float y)
|
||||
{
|
||||
int num = Mathf.FloorToInt(x + 0.5f);
|
||||
@@ -727,70 +474,11 @@ public static class NGUIMath
|
||||
}
|
||||
}
|
||||
|
||||
public static void ResizeWidget(UIWidget w, UIWidget.Pivot pivot, float x, float y, int minWidth, int minHeight)
|
||||
{
|
||||
ResizeWidget(w, pivot, x, y, 2, 2, 100000, 100000);
|
||||
}
|
||||
|
||||
public static void ResizeWidget(UIWidget w, UIWidget.Pivot pivot, float x, float y, int minWidth, int minHeight, int maxWidth, int maxHeight)
|
||||
{
|
||||
if (pivot == UIWidget.Pivot.Center)
|
||||
{
|
||||
int num = Mathf.RoundToInt(x - (float)w.width);
|
||||
int num2 = Mathf.RoundToInt(y - (float)w.height);
|
||||
num -= num & 1;
|
||||
num2 -= num2 & 1;
|
||||
if ((num | num2) != 0)
|
||||
{
|
||||
num >>= 1;
|
||||
num2 >>= 1;
|
||||
AdjustWidget(w, -num, -num2, num, num2, minWidth, minHeight);
|
||||
}
|
||||
return;
|
||||
}
|
||||
Vector3 vector = new Vector3(x, y);
|
||||
vector = Quaternion.Inverse(w.cachedTransform.localRotation) * vector;
|
||||
switch (pivot)
|
||||
{
|
||||
case UIWidget.Pivot.BottomLeft:
|
||||
AdjustWidget(w, vector.x, vector.y, 0f, 0f, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.Left:
|
||||
AdjustWidget(w, vector.x, 0f, 0f, 0f, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.TopLeft:
|
||||
AdjustWidget(w, vector.x, 0f, 0f, vector.y, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.Top:
|
||||
AdjustWidget(w, 0f, 0f, 0f, vector.y, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.TopRight:
|
||||
AdjustWidget(w, 0f, 0f, vector.x, vector.y, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.Right:
|
||||
AdjustWidget(w, 0f, 0f, vector.x, 0f, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.BottomRight:
|
||||
AdjustWidget(w, 0f, vector.y, vector.x, 0f, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.Bottom:
|
||||
AdjustWidget(w, 0f, vector.y, 0f, 0f, minWidth, minHeight, maxWidth, maxHeight);
|
||||
break;
|
||||
case UIWidget.Pivot.Center:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public static void AdjustWidget(UIWidget w, float left, float bottom, float right, float top)
|
||||
{
|
||||
AdjustWidget(w, left, bottom, right, top, 2, 2, 100000, 100000);
|
||||
}
|
||||
|
||||
public static void AdjustWidget(UIWidget w, float left, float bottom, float right, float top, int minWidth, int minHeight)
|
||||
{
|
||||
AdjustWidget(w, left, bottom, right, top, minWidth, minHeight, 100000, 100000);
|
||||
}
|
||||
|
||||
public static void AdjustWidget(UIWidget w, float left, float bottom, float right, float top, int minWidth, int minHeight, int maxWidth, int maxHeight)
|
||||
{
|
||||
Vector2 pivotOffset = w.pivotOffset;
|
||||
@@ -960,74 +648,4 @@ public static class NGUIMath
|
||||
}
|
||||
return num2;
|
||||
}
|
||||
|
||||
public static Vector2 ScreenToPixels(Vector2 pos, Transform relativeTo)
|
||||
{
|
||||
Camera camera = NGUITools.FindCameraForLayer(relativeTo.gameObject.layer);
|
||||
if (camera == null)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
Vector3 position = camera.ScreenToWorldPoint(pos);
|
||||
return relativeTo.InverseTransformPoint(position);
|
||||
}
|
||||
|
||||
public static Vector2 ScreenToParentPixels(Vector2 pos, Transform relativeTo)
|
||||
{
|
||||
int layer = relativeTo.gameObject.layer;
|
||||
if (relativeTo.parent != null)
|
||||
{
|
||||
relativeTo = relativeTo.parent;
|
||||
}
|
||||
Camera camera = NGUITools.FindCameraForLayer(layer);
|
||||
if (camera == null)
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
Vector3 vector = camera.ScreenToWorldPoint(pos);
|
||||
return (relativeTo != null) ? relativeTo.InverseTransformPoint(vector) : vector;
|
||||
}
|
||||
|
||||
public static Vector3 WorldToLocalPoint(Vector3 worldPos, Camera worldCam, Camera uiCam, Transform relativeTo)
|
||||
{
|
||||
worldPos = worldCam.WorldToViewportPoint(worldPos);
|
||||
worldPos = uiCam.ViewportToWorldPoint(worldPos);
|
||||
if (relativeTo == null)
|
||||
{
|
||||
return worldPos;
|
||||
}
|
||||
relativeTo = relativeTo.parent;
|
||||
if (relativeTo == null)
|
||||
{
|
||||
return worldPos;
|
||||
}
|
||||
return relativeTo.InverseTransformPoint(worldPos);
|
||||
}
|
||||
|
||||
public static void OverlayPosition(this Transform trans, Vector3 worldPos, Camera worldCam, Camera myCam)
|
||||
{
|
||||
worldPos = worldCam.WorldToViewportPoint(worldPos);
|
||||
worldPos = myCam.ViewportToWorldPoint(worldPos);
|
||||
Transform parent = trans.parent;
|
||||
trans.localPosition = ((parent != null) ? parent.InverseTransformPoint(worldPos) : worldPos);
|
||||
}
|
||||
|
||||
public static void OverlayPosition(this Transform trans, Vector3 worldPos, Camera worldCam)
|
||||
{
|
||||
Camera camera = NGUITools.FindCameraForLayer(trans.gameObject.layer);
|
||||
if (camera != null)
|
||||
{
|
||||
trans.OverlayPosition(worldPos, worldCam, camera);
|
||||
}
|
||||
}
|
||||
|
||||
public static void OverlayPosition(this Transform trans, Transform target)
|
||||
{
|
||||
Camera camera = NGUITools.FindCameraForLayer(trans.gameObject.layer);
|
||||
Camera camera2 = NGUITools.FindCameraForLayer(target.gameObject.layer);
|
||||
if (camera != null && camera2 != null)
|
||||
{
|
||||
trans.OverlayPosition(target.position, camera2, camera);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user