// WL-816f — PD 경로 Play 에서 ⓓ성능 ⓔ기능(걷기·농사·건설/확장) ⓕ되돌리기를 실측한다. public static class WL816f_Verify { public static void Start() { var go = UnityEngine.GameObject.Find("~WL816fVerify"); if (go != null) UnityEngine.Object.DestroyImmediate(go); go = new UnityEngine.GameObject("~WL816fVerify"); go.AddComponent(); } } public class WL816f_VerifyRunner : UnityEngine.MonoBehaviour { const string Dir = "Screenshots_WL/WL816f/"; static System.Text.StringBuilder sb; void Start() { StartCoroutine(Co()); } System.Collections.IEnumerator Co() { sb = new System.Text.StringBuilder(); if (UnityEngine.SceneManagement.SceneManager.sceneCount < 2) { var op = UnityEngine.SceneManagement.SceneManager.LoadSceneAsync("Level01", UnityEngine.SceneManagement.LoadSceneMode.Additive); while (op != null && !op.isDone) yield return null; } for (int i = 0; i < 6; i++) yield return new UnityEngine.WaitForSeconds(1f); L("=== WL-816f 검증 (PD 경로 · InGame 활성 + Level01 Additive) ==="); L("풀 : " + WL.Look.Farm.WLIslandGrass.LastLog); L("Soil 톤 : farm " + WL.Look.Farm.WLIslandLook.SoilFarmsToned + " · 타일 " + WL.Look.Farm.WLIslandLook.SoilTilesRepainted); // ── ⓓ 성능 : 같은 카메라로 60프레임 오프스크린 렌더 ───────── var cam = FindLiveCam(); L(""); L("[성능] 카메라 " + (cam ? cam.name : "없음")); float onMs = RenderBench(cam, 60); var g = UnityEngine.Object.FindFirstObjectByType(UnityEngine.FindObjectsInactive.Include); int instOn = WL.Look.Farm.WLIslandGrass.Instances; long triOn = WL.Look.Farm.WLIslandGrass.Triangles; if (g != null) g.enabled = false; // 풀만 끈 상태 yield return null; yield return null; float offMs = RenderBench(cam, 60); if (g != null) g.enabled = true; yield return null; yield return null; L("풀 켬 " + onMs.ToString("F3") + " ms/frame · 풀 끔 " + offMs.ToString("F3") + " ms/frame · 델타 " + (onMs - offMs).ToString("F3") + " ms"); L("인스턴스 " + instOn + " · 삼각형(풀) " + triOn + " · 드로우콜 +" + WL.Look.Farm.WLIslandGrass.DrawnConfigs); // ── ⓔ 기능 ───────────────────────────────────────────────── L(""); L("[기능]"); // 풀 콜라이더 0 · 레이캐스트 · NavMesh int colliders = 0; var gobj = g != null ? g.gameObject : null; if (gobj != null) colliders = gobj.GetComponentsInChildren(true).Length; L("풀 오브젝트 콜라이더 = " + colliders + " (0 이어야 한다)"); int hit = 0, nav = 0; for (int i = 0; i < 100; i++) { var p = new UnityEngine.Vector3(UnityEngine.Random.Range(-7f, 7f), 3f, UnityEngine.Random.Range(-7f, 7f)); UnityEngine.RaycastHit h; if (UnityEngine.Physics.Raycast(p, UnityEngine.Vector3.down, out h, 10f)) hit++; UnityEngine.AI.NavMeshHit nh; if (UnityEngine.AI.NavMesh.SamplePosition(new UnityEngine.Vector3(p.x, 0f, p.z), out nh, 1.5f, ~0)) nav++; } L("풀밭 100점 아래 레이캐스트 적중 " + hit + "/100 · NavMesh 샘플 " + nav + "/100"); // 걷기 — FI PlayerController 의 CharacterController var cc = UnityEngine.Object.FindFirstObjectByType(UnityEngine.FindObjectsInactive.Exclude); if (cc != null) { var p0 = cc.transform.position; var dir = new UnityEngine.Vector3(1f, 0f, 1f).normalized; float moved = 0f; for (int i = 0; i < 120; i++) { cc.Move(dir * 0.05f + UnityEngine.Vector3.down * 0.02f); yield return null; } moved = UnityEngine.Vector3.Distance(new UnityEngine.Vector3(p0.x, 0f, p0.z), new UnityEngine.Vector3(cc.transform.position.x, 0f, cc.transform.position.z)); L("걷기 : " + p0.ToString("F2") + " → " + cc.transform.position.ToString("F2") + " = " + moved.ToString("F2") + " m · grounded=" + cc.isGrounded); } else L("걷기 : CharacterController 없음(미확인)"); // 농사 — Farm/Soil 개수 + 씨뿌리기 상태 전환 var farms = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None); var soils = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None); L("농사 : Farm " + farms.Length + " · Soil " + soils.Length); int painted = 0; for (int i = 0; i < soils.Length; i++) { var r = soils[i].GetComponentInChildren(true); if (r != null && r.sharedMaterial != null) painted++; } L("Soil 렌더러 살아있음 " + painted + "/" + soils.Length + " · 첫 Soil 색 " + (soils.Length > 0 && soils[0].GetComponentInChildren(true) != null ? UnityEngine.ColorUtility.ToHtmlStringRGB(soils[0].GetComponentInChildren(true).material.color) : "-")); // 확장 — 섬 타일 수 var islands = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None); int unlocked = 0; for (int i = 0; i < islands.Length; i++) if (islands[i].IsUnlocked && islands[i].gameObject.activeInHierarchy) unlocked++; L("확장 : 섬 타일 전체 " + islands.Length + " · 열린 타일 " + unlocked + " · 풀 깔린 타일 " + WL.Look.Farm.WLIslandGrass.Tiles); // ── 최종 캡처 ─────────────────────────────────────────────── Shot(FindLiveCam(), Dir + "d_final_wide.png"); System.IO.File.WriteAllText("AgentScripts/WL816f_VERIFY.txt", sb.ToString()); UnityEngine.Debug.Log("[816f verify]\n" + sb.ToString()); } static void L(string s) { sb.AppendLine(s); } static UnityEngine.Camera FindLiveCam() { var cams = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None); UnityEngine.Camera top = null; for (int i = 0; i < cams.Length; i++) { var c = cams[i]; if (!c.enabled || c.targetTexture != null) continue; if (top == null || c.depth > top.depth) top = c; } return top; } static float RenderBench(UnityEngine.Camera cam, int frames) { if (cam == null) return -1f; var rt = new UnityEngine.RenderTexture(1080, 1920, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB); rt.antiAliasing = 1; rt.Create(); var prev = cam.targetTexture; cam.targetTexture = rt; cam.Render(); // 워밍업 var sw = System.Diagnostics.Stopwatch.StartNew(); for (int i = 0; i < frames; i++) cam.Render(); sw.Stop(); cam.targetTexture = prev; rt.Release(); UnityEngine.Object.DestroyImmediate(rt); return (float)sw.Elapsed.TotalMilliseconds / frames; } static void Shot(UnityEngine.Camera cam, string path) { if (cam == null) return; System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path)); var rt = new UnityEngine.RenderTexture(1080, 1920, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB); rt.antiAliasing = 1; rt.Create(); var prevT = cam.targetTexture; var prevA = UnityEngine.RenderTexture.active; cam.targetTexture = rt; cam.Render(); UnityEngine.RenderTexture.active = rt; var tex = new UnityEngine.Texture2D(1080, 1920, UnityEngine.TextureFormat.RGB24, false); tex.ReadPixels(new UnityEngine.Rect(0, 0, 1080, 1920), 0, 0); tex.Apply(); System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex)); UnityEngine.RenderTexture.active = prevA; cam.targetTexture = prevT; UnityEngine.Object.DestroyImmediate(tex); rt.Release(); UnityEngine.Object.DestroyImmediate(rt); L("캡처 " + path); } }