using System; using System.Linq; using ShieldField; using UnityEditor; using UnityEditor.Rendering; using UnityEngine; namespace Aetheria.EditorTools { /// /// Batchmode probe for the shield-panel Cut 1 landing (docs/shield-panel-cut.md). /// No NUnit coverage exists for these files (Tests.asmdef cannot see /// Assembly-CSharp — see the map's Q7), so this is the check that stands in /// for a unit test on two Cut 1 rules that a compile pass alone cannot prove: /// /// 1. The shader and compute shader carry zero compile errors on built-in. /// 2. Penrose cell count actually scales with panelRadius (D18) instead of /// being a fixed function of the (now-removed) authored iteration count. /// /// Run via: Unity -batchmode -projectPath <repo> -executeMethod /// Aetheria.EditorTools.ShieldPanelCut1Verify.Run -quit -logFile <path> /// Exits with a non-zero code if either rule is violated, so the log alone is /// not the only signal — a CI runner can gate on the exit code too. /// public static class ShieldPanelCut1Verify { public static void Run() { bool ok = true; ok &= CheckShaderMessages(); ok &= CheckComputeMessages(); ok &= CheckPenroseScalesWithRadius(); Debug.Log(ok ? "[ShieldPanelCut1Verify] PASS" : "[ShieldPanelCut1Verify] FAIL — see errors above"); EditorApplication.Exit(ok ? 0 : 1); } static bool CheckShaderMessages() { var shader = AssetDatabase.LoadAssetAtPath( "Assets/Shaders/Compute/ShieldField/ShieldPanel.shader"); if (shader == null) { Debug.LogError("[ShieldPanelCut1Verify] ShieldPanel.shader not found."); return false; } bool ok = true; // The first query can observe the shader mid-compile and return a stale/empty // message set; warm it up before trusting the result. _ = ShaderUtil.GetShaderMessageCount(shader); _ = ShaderUtil.ShaderHasError(shader); var shaderMsgs = ShaderUtil.GetShaderMessages(shader); foreach (var m in shaderMsgs) { if (m.severity == ShaderCompilerMessageSeverity.Error) { Debug.LogError($"[ShieldPanelCut1Verify] Shader error: {m.message} ({m.file}:{m.line})"); ok = false; } else { Debug.Log($"[ShieldPanelCut1Verify] Shader warning: {m.message} ({m.file}:{m.line})"); } } if (ShaderUtil.ShaderHasError(shader)) { Debug.LogError("[ShieldPanelCut1Verify] ShieldPanel.shader has compile errors (ShaderHasError)."); ok = false; } Debug.Log($"[ShieldPanelCut1Verify] shader supported={!ShaderUtil.ShaderHasError(shader)} messages={shaderMsgs.Length}"); return ok; } static bool CheckComputeMessages() { var cs = AssetDatabase.LoadAssetAtPath( "Assets/Shaders/Compute/ShieldField/ShieldSim.compute"); if (cs == null) { Debug.LogError("[ShieldPanelCut1Verify] ShieldSim.compute not found."); return false; } bool ok = true; var msgs = ShaderUtil.GetComputeShaderMessages(cs); foreach (var m in msgs) { if (m.severity == ShaderCompilerMessageSeverity.Error) { Debug.LogError($"[ShieldPanelCut1Verify] Compute shader error: {m.message} ({m.file}:{m.line})"); ok = false; } } Debug.Log($"[ShieldPanelCut1Verify] compute messages={msgs.Length}, errors={msgs.Count(m => m.severity == ShaderCompilerMessageSeverity.Error)}"); return ok; } static bool CheckPenroseScalesWithRadius() { const float cellSize = 0.35f; float[] radii = { 1.5f, 10f }; int[] penroseCounts = new int[radii.Length]; int[] hexCounts = new int[radii.Length]; for (int i = 0; i < radii.Length; i++) { var pSoup = Tilings.Generate(TilingKind.PenroseP3, radii[i], cellSize, 1337); var pMerged = TilingBuilder.MergeRhombs(pSoup); var pData = TilingBuilder.Build(pMerged, weldEps: Mathf.Max(cellSize * 0.02f, 1e-4f), clipRadius: radii[i], seed: 1337); penroseCounts[i] = pData.CellCount; var hSoup = Tilings.Generate(TilingKind.Hex, radii[i], cellSize, 1337); var hData = TilingBuilder.Build(hSoup, weldEps: Mathf.Max(cellSize * 0.02f, 1e-4f), clipRadius: radii[i], seed: 1337); hexCounts[i] = hData.CellCount; Debug.Log($"[ShieldPanelCut1Verify] radius={radii[i]} cellSize={cellSize} " + $"PenroseP3(merged) cells={penroseCounts[i]} Hex cells={hexCounts[i]}"); } bool ok = penroseCounts[0] != penroseCounts[1]; if (!ok) Debug.LogError($"[ShieldPanelCut1Verify] D18 not fixed: Penrose cell count identical " + $"({penroseCounts[0]}) at radius {radii[0]} and {radii[1]}."); else if (penroseCounts[1] < penroseCounts[0]) Debug.LogError($"[ShieldPanelCut1Verify] D18 regression: Penrose cell count DECREASED " + $"from {penroseCounts[0]} (r={radii[0]}) to {penroseCounts[1]} (r={radii[1]})."); else Debug.Log("[ShieldPanelCut1Verify] D18 fixed: Penrose cell count increases with panelRadius."); return ok && penroseCounts[1] > penroseCounts[0]; } } }