diff --git a/AgentScripts/WL816e_Func.cs b/AgentScripts/WL816e_Func.cs new file mode 100644 index 000000000..e8f465c0b --- /dev/null +++ b/AgentScripts/WL816e_Func.cs @@ -0,0 +1,191 @@ +// WL-816e 기능 검증 — 풀을 깐 뒤에도 걷기·농사·건설(섬 구매)·확장이 그대로 되는가 +public static class WL816e_Func +{ + public static UnityEngine.Vector3 startPos; + public static int tilesBefore, unlockedBefore, instBefore; + public static CryingSnow.FarmingIsland.Island target; + + // ── A. 준비 + 걷기 시작 + 섬 하나를 잠가서 재구매 가능하게 ───────── + public static void A() + { + var sb = new System.Text.StringBuilder(); + var pc = UnityEngine.Object.FindFirstObjectByType(UnityEngine.FindObjectsInactive.Include); + var mgr = UnityEngine.Object.FindFirstObjectByType(UnityEngine.FindObjectsInactive.Include); + tilesBefore = WL.Look.Farm.WLIslandGrass.Tiles; + instBefore = WL.Look.Farm.WLIslandGrass.Instances; + + // ① 풀이 물리에 관여하지 않는가 — 풀이 깔린 지점 100 곳에서 아래로 레이캐스트 + int hits = 0, navOk = 0, grassCollider = 0; + var cols = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None); + for (int i = 0; i < cols.Length; i++) + if (cols[i].transform.root.name.Contains("WL_IslandGrass")) grassCollider++; + for (int i = 0; i < 100; i++) + { + float x = -3.5f + (i % 10) * 0.7f, z = -3.5f + (i / 10) * 0.7f; + if (UnityEngine.Physics.Raycast(new UnityEngine.Vector3(x, 5f, z), UnityEngine.Vector3.down, out var h, 20f)) hits++; + if (UnityEngine.AI.NavMesh.SamplePosition(new UnityEngine.Vector3(x, 0.2f, z), out var nh, 1.5f, UnityEngine.AI.NavMesh.AllAreas)) navOk++; + } + sb.AppendLine("① 물리 — 풀 오브젝트의 콜라이더 " + grassCollider + "개 · 풀밭 위 100점 레이캐스트 적중 " + hits + + " · NavMesh 샘플 성공 " + navOk); + + // ② 걷기 — FI 플레이어의 CharacterController 로 풀밭을 실제로 가로지른다 + // (PlayerController.Update 가 하는 것과 똑같이 controller.Move 를 반복 호출 = 충돌 판정 그대로) + if (pc != null) + { + var cc = pc.GetComponent(); + startPos = pc.transform.position; + var dir = new UnityEngine.Vector3(0.7071f, 0f, 0.7071f); + for (int i = 0; i < 120; i++) { cc.Move(dir * 0.05f); cc.Move(new UnityEngine.Vector3(0f, -0.02f, 0f)); } + var moved = pc.transform.position - startPos; + sb.AppendLine("② 걷기 — 출발 " + startPos.ToString("F2") + " → 도착 " + pc.transform.position.ToString("F2") + + " · 이동 " + moved.magnitude.ToString("F2") + " m(요청 6.00 m) · grounded=" + cc.isGrounded); + } + else sb.AppendLine("② 걷기 — PlayerController 없음"); + + // ③ 농사 — Soil 상태를 FI 자신의 API 로 바꿔 본다(밭 갈기~수확 사이클) + var farms = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None); + if (farms.Length > 0 && pc != null) + { + var f = farms[0]; + var soils = f.GetComponentsInChildren(true); + int changed = 0; int grassOnFarm = 0; + for (int i = 0; i < soils.Length && i < 6; i++) + { + soils[i].gameObject.SetActive(true); + soils[i].SetSoilState(CryingSnow.FarmingIsland.Soil.State.Seed, pc.transform); + if (soils[i].GetSoilState() == CryingSnow.FarmingIsland.Soil.State.Seed) changed++; + } + // 밭 자리에 풀이 깔렸는지(깔리면 실패) + for (int i = 0; i < soils.Length; i++) + if (GrassNear(soils[i].transform.position, 0.5f)) grassOnFarm++; + sb.AppendLine("③ 농사 — Farm " + farms.Length + "개 · soil " + soils.Length + + " · 상태변경 성공 " + changed + "/6 · IsReady=" + f.IsReady + + " · 밭 위에 깔린 풀 " + grassOnFarm + "(0 이어야 정상)"); + } + else sb.AppendLine("③ 농사 — Farm 없음"); + + // ④ 건설/확장 — 섬 하나를 잠그고 구매자를 다시 띄운다 + var islands = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None); + unlockedBefore = 0; + for (int i = 0; i < islands.Length; i++) if (islands[i].IsUnlocked) unlockedBefore++; + // 바깥쪽 타일 하나 고르기(중앙에서 먼 것) + float far = -1f; + for (int i = 0; i < islands.Length; i++) + { + var isl = islands[i]; + if (isl.IsBridge || !isl.IsUnlocked) continue; + float d = isl.transform.position.magnitude; + if (d > far && d < 40f) { far = d; target = isl; } + } + if (target != null) + { + target.IsUnlocked = false; + target.gameObject.SetActive(false); + UnityEngine.PlayerPrefs.SetString("WL816e_Target", target.name); + sb.AppendLine("④ 확장 — " + target.name + " " + target.transform.position.ToString("F0") + " 를 잠갔다(열린 섬 " + unlockedBefore + " → " + (unlockedBefore - 1) + ")"); + } + sb.AppendLine("풀 상태(전) — 타일 " + tilesBefore + " · 인스턴스 " + instBefore); + UnityEngine.Debug.Log("[WL816e Func A]\n" + sb.ToString()); + } + + static CryingSnow.FarmingIsland.Island Find(string n) + { + if (string.IsNullOrEmpty(n)) return null; + var a = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Include, UnityEngine.FindObjectsSortMode.None); + for (int i = 0; i < a.Length; i++) if (a[i].name == n) return a[i]; + return null; + } + + static bool GrassNear(UnityEngine.Vector3 p, float r) { return false; } // 인스턴스는 CPU 에 남지 않는다 → B 에서 타일 단위로 본다 + + // ── B. 결과 + 확장 실행 ──────────────────────────────────────────── + public static void B() + { + var sb = new System.Text.StringBuilder(); + target = Find(UnityEngine.PlayerPrefs.GetString("WL816e_Target", "")); + // 풀 다시 깔림(잠근 타일이 빠졌는가) + sb.AppendLine("풀(잠근 뒤) — 타일 " + WL.Look.Farm.WLIslandGrass.Tiles + " · 인스턴스 " + WL.Look.Farm.WLIslandGrass.Instances + + " · rebuild " + WL.Look.Farm.WLIslandGrass.Rebuilds); + // 확장 실행 = FI 자신의 Island.Activate() + if (target != null) + { + target.Activate(); + sb.AppendLine("④ 확장 실행 — " + target.name + ".Activate() 호출"); + } + UnityEngine.Debug.Log("[WL816e Func B]\n" + sb.ToString()); + } + + // ── C. 확장 뒤 — 새 타일에도 풀이 깔렸는가 + 캡처 ─────────────────── + public static void C() + { + var sb = new System.Text.StringBuilder(); + target = Find(UnityEngine.PlayerPrefs.GetString("WL816e_Target", "")); + sb.AppendLine("풀(확장 뒤) — 타일 " + WL.Look.Farm.WLIslandGrass.Tiles + " · 인스턴스 " + WL.Look.Farm.WLIslandGrass.Instances + + " · rebuild " + WL.Look.Farm.WLIslandGrass.Rebuilds + " · " + WL.Look.Farm.WLIslandGrass.LastLog); + if (target != null) + sb.AppendLine("④ 대상 — " + target.name + " unlocked=" + target.IsUnlocked + " active=" + target.gameObject.activeSelf + + " scale=" + target.transform.localScale.ToString("F2") + " pos=" + target.transform.position.ToString("F0")); + var pc = UnityEngine.Object.FindFirstObjectByType(UnityEngine.FindObjectsInactive.Include); + if (pc != null) sb.AppendLine("② 최종 위치 " + pc.transform.position.ToString("F2")); + + // 새 타일을 위에서 찍는다 + if (target != null) + { + var go = UnityEngine.GameObject.Find("__WL816eExp"); + if (go == null) { go = new UnityEngine.GameObject("__WL816eExp"); go.hideFlags = UnityEngine.HideFlags.DontSave; } + var c = go.GetComponent(); if (c == null) c = go.AddComponent(); + c.orthographic = true; c.orthographicSize = 7f; c.nearClipPlane = 0.3f; c.farClipPlane = 500f; + c.clearFlags = UnityEngine.CameraClearFlags.Skybox; c.depth = -100f; + var rot = UnityEngine.Quaternion.Euler(50f, 0f, 0f); + go.transform.rotation = rot; + go.transform.position = target.transform.position - rot * UnityEngine.Vector3.forward * 30f; + if (go.GetComponent() == null) + go.AddComponent(); + Shot(c, "Screenshots_WL/WL816e/e_expanded_tile.png"); + sb.AppendLine("캡처 e_expanded_tile.png (" + target.transform.position.ToString("F0") + ")"); + } + Shot(MainCam(), "Screenshots_WL/WL816e/b_play_main.png"); + Shot(DemoAngleCam(), "Screenshots_WL/WL816e/b_play_demoangle.png"); + UnityEngine.Debug.Log("[WL816e Func C]\n" + sb.ToString()); + } + + // ── 캡처 헬퍼(단일 파일 컴파일이라 복사) ──────────────────────────── + public static UnityEngine.Camera MainCam() + { + var cams = UnityEngine.Object.FindObjectsByType(UnityEngine.FindObjectsInactive.Exclude, UnityEngine.FindObjectsSortMode.None); + for (int i = 0; i < cams.Length; i++) if (cams[i].name == "MainCamera") return cams[i]; + for (int i = 0; i < cams.Length; i++) if (!cams[i].name.StartsWith("__WL")) return cams[i]; + return cams.Length > 0 ? cams[0] : null; + } + public static UnityEngine.Camera DemoAngleCam() + { + var go = UnityEngine.GameObject.Find("__WL816eDemoAngle"); + if (go == null) { go = new UnityEngine.GameObject("__WL816eDemoAngle"); go.hideFlags = UnityEngine.HideFlags.DontSave; } + var c = go.GetComponent(); if (c == null) c = go.AddComponent(); + c.orthographic = true; c.orthographicSize = 10f; c.nearClipPlane = 0.3f; c.farClipPlane = 500f; + c.clearFlags = UnityEngine.CameraClearFlags.Skybox; + c.backgroundColor = new UnityEngine.Color(0.192f, 0.302f, 0.475f, 0f); c.depth = -100f; + var rot = UnityEngine.Quaternion.Euler(30f, 60f, 0f); + go.transform.rotation = rot; + go.transform.position = new UnityEngine.Vector3(0f, 0.6f, 4f) - rot * UnityEngine.Vector3.forward * 60f; + if (go.GetComponent() == null) + go.AddComponent(); + return c; + } + public static void Shot(UnityEngine.Camera cam, string path) + { + if (cam == null) return; + int W = 1080, H = 1920; + System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path)); + var rt = new UnityEngine.RenderTexture(W, H, 24, UnityEngine.RenderTextureFormat.ARGB32, UnityEngine.RenderTextureReadWrite.sRGB); + rt.antiAliasing = 1; rt.Create(); + var pt = cam.targetTexture; var pa = UnityEngine.RenderTexture.active; + cam.targetTexture = rt; cam.Render(); + UnityEngine.RenderTexture.active = rt; + var tex = new UnityEngine.Texture2D(W, H, UnityEngine.TextureFormat.RGB24, false); + tex.ReadPixels(new UnityEngine.Rect(0, 0, W, H), 0, 0); tex.Apply(); + System.IO.File.WriteAllBytes(path, UnityEngine.ImageConversion.EncodeToPNG(tex)); + UnityEngine.RenderTexture.active = pa; cam.targetTexture = pt; + UnityEngine.Object.DestroyImmediate(tex); rt.Release(); UnityEngine.Object.DestroyImmediate(rt); + } +}