Project_WL/AgentScripts/WL816j_Final.cs

213 lines
12 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// WL-816j — ⑥ 채택 상태 최종 확인: PD 경로(구조 재현) · 기능 무영향 · 성능 전/후 · 되돌리기 · 최종 캡처
// 🔴 자기 완결 파일 · Play 중 에셋 수정 0(렌더러의 sharedMaterial 만 교체).
using System.Collections;
using System.Text;
using UnityEngine;
using UnityEngine.Rendering.Universal;
using UnityEngine.SceneManagement;
using FIIsland = CryingSnow.FarmingIsland.Island;
public static class WL816j_Final
{
public const string D = "Screenshots_WL/WL816j/";
public static void Open()
{
UnityEditor.SceneManagement.EditorSceneManager.OpenScene(
"Assets/Scenes/InGame.unity", UnityEditor.SceneManagement.OpenSceneMode.Single);
Debug.Log("[816j] InGame 열림");
}
public static void Start()
{
var go = GameObject.Find("~WL816jFinal");
if (go != null) Object.DestroyImmediate(go);
go = new GameObject("~WL816jFinal");
go.AddComponent<WL816j_FinalRunner>();
Debug.Log("[816j] final 러너 시작");
}
public static Camera Look(string n, Vector3 pos, Vector3 at, float fov)
{
var go = GameObject.Find(n);
if (go == null) { go = new GameObject(n); go.hideFlags = HideFlags.DontSave; }
var c = go.GetComponent<Camera>(); if (c == null) c = go.AddComponent<Camera>();
c.orthographic = false; c.fieldOfView = fov; c.nearClipPlane = 0.1f; c.farClipPlane = 2000f;
c.clearFlags = CameraClearFlags.Skybox; c.cullingMask = ~0; c.depth = -100f;
go.transform.position = pos; go.transform.LookAt(at);
var a = go.GetComponent<UniversalAdditionalCameraData>();
if (a == null) a = go.AddComponent<UniversalAdditionalCameraData>();
a.renderPostProcessing = true;
return c;
}
public static string Shot(Camera cam, string path, int w, int h)
{
if (cam == null) return "카메라 없음";
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(path));
var rt = new RenderTexture(w, h, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; var pA = RenderTexture.active;
cam.targetTexture = rt; cam.Render(); RenderTexture.active = rt;
var t = new Texture2D(w, h, TextureFormat.RGB24, false);
t.ReadPixels(new Rect(0, 0, w, h), 0, 0); t.Apply();
RenderTexture.active = pA; cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt);
System.IO.File.WriteAllBytes(path, t.EncodeToPNG());
var px = t.GetPixels32(); long r = 0, g = 0, b = 0; int n = 0;
for (int i = 0; i < px.Length; i += 7) { r += px[i].r; g += px[i].g; b += px[i].b; n++; }
Object.DestroyImmediate(t);
return "평균 #" + ((int)(r / n)).ToString("X2") + ((int)(g / n)).ToString("X2") + ((int)(b / n)).ToString("X2") + " → " + path;
}
public static float Ms(Camera cam, int frames)
{
var rt = new RenderTexture(1080, 1920, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB);
rt.antiAliasing = 1; rt.Create();
var pT = cam.targetTexture; cam.targetTexture = rt;
for (int i = 0; i < 10; i++) cam.Render();
var sw = System.Diagnostics.Stopwatch.StartNew();
for (int i = 0; i < frames; i++) cam.Render();
sw.Stop();
cam.targetTexture = pT; rt.Release(); Object.DestroyImmediate(rt);
return (float)sw.Elapsed.TotalMilliseconds / frames;
}
public static void Strip(string[] paths, string outPath)
{
var ts = new Texture2D[paths.Length]; int w = 0, h = 0;
for (int i = 0; i < paths.Length; i++)
{
if (!System.IO.File.Exists(paths[i])) return;
ts[i] = new Texture2D(2, 2, TextureFormat.RGB24, false);
ts[i].LoadImage(System.IO.File.ReadAllBytes(paths[i]));
w += ts[i].width; h = Mathf.Max(h, ts[i].height);
}
var o = new Texture2D(w, h, TextureFormat.RGB24, false);
var f = new Color32[w * h];
for (int i = 0; i < f.Length; i++) f[i] = new Color32(24, 24, 28, 255);
o.SetPixels32(f);
int x = 0;
for (int i = 0; i < ts.Length; i++) { o.SetPixels32(x, 0, ts[i].width, ts[i].height, ts[i].GetPixels32()); x += ts[i].width; }
o.Apply();
System.IO.File.WriteAllBytes(outPath, o.EncodeToPNG());
Object.DestroyImmediate(o);
for (int i = 0; i < ts.Length; i++) Object.DestroyImmediate(ts[i]);
}
}
public class WL816j_FinalRunner : MonoBehaviour
{
static StringBuilder sb;
static void L(string s) { sb.AppendLine(s); }
const string D = WL816j_Final.D;
const string MatDir = "Assets/WL/Look/Farm/Materials/";
void Start() { StartCoroutine(Co()); }
IEnumerator Co()
{
sb = new StringBuilder();
L("=== WL-816j ⑥ 최종 확인 ===");
bool viaGame = false;
try { if (InGameInfo.Ins != null) { InGameInfo.Ins.Load_Map(900); viaGame = true; } }
catch (System.Exception) { }
L("Load_Map(900) = " + (viaGame ? "성공" : "🔴 로그인 없이는 못 탄다 → LoadSceneAsync(Level01, Additive)"));
if (!viaGame)
{
var op = SceneManager.LoadSceneAsync("Level01", LoadSceneMode.Additive);
while (op != null && !op.isDone) yield return null;
}
for (int i = 0; i < 7; i++) yield return new WaitForSeconds(1f);
Renderer water = null;
foreach (var r in Object.FindObjectsByType<Renderer>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
if (r != null && r.gameObject.scene.name == "Level01" && r.name == "Water") water = r;
Camera live = null;
foreach (var c in Object.FindObjectsByType<Camera>(FindObjectsInactive.Exclude, FindObjectsSortMode.None))
{
if (!c.gameObject.activeInHierarchy || !c.enabled || c.targetTexture != null) continue;
if (c.name.StartsWith("~WL816j")) continue;
if (live == null || c.depth > live.depth) live = c;
}
if (water == null || live == null) { L("🔴 물/카메라 없음"); Done(); yield break; }
var adopted = water.sharedMaterial;
L("");
L("1) 물 = " + adopted.name + " · 셰이더 " + adopted.shader.name + " · 물 교체 " + WL.Look.Farm.WLIslandLook.WaterSwapped
+ " · 렌더러 " + WL.Look.Farm.WLIslandLook.SwappedRenderers);
var mc = water.GetComponent<MeshCollider>(); var mf = water.GetComponent<MeshFilter>();
L(" 물 오브젝트 그대로인가 : MeshCollider=" + (mc ? "있음 enabled=" + mc.enabled + " mesh=" + (mc.sharedMesh ? mc.sharedMesh.name : "-") : "없음")
+ " · MeshFilter=" + (mf && mf.sharedMesh ? mf.sharedMesh.name : "-")
+ " · layer=" + water.gameObject.layer + " · pos=" + water.transform.position.ToString("F1")
+ " · scale=" + water.transform.localScale.ToString("F0"));
// ── 2) 걷기 ────────────────────────────────────────────────
var cc = Object.FindFirstObjectByType<CharacterController>(FindObjectsInactive.Exclude);
if (cc != null)
{
var p0 = cc.transform.position; var dir = new Vector3(1f, 0f, 1f).normalized; float moved = 0f;
for (int i = 0; i < 120 && moved < 6f; i++) { cc.Move(dir * 0.05f + Vector3.down * 0.05f); moved += 0.05f; yield return null; }
var p1 = cc.transform.position;
L("2) 걷기: " + p0.ToString("F2") + " → " + p1.ToString("F2") + " · 이동 "
+ Vector3.Distance(new Vector3(p0.x, 0, p0.z), new Vector3(p1.x, 0, p1.z)).ToString("F2") + " m · grounded=" + cc.isGrounded);
}
else L("2) 걷기: CharacterController 없음");
// ── 3) 섬 확장 ─────────────────────────────────────────────
var islands = Object.FindObjectsByType<FIIsland>(FindObjectsInactive.Exclude, FindObjectsSortMode.None);
L("3) 섬 타일 " + islands.Length + " · 풀 " + WL.Look.Farm.WLIslandGrass.LastLog);
FIIsland target = null;
foreach (var isl in islands) if (isl != null && isl.IsUnlocked && isl.gameObject.activeInHierarchy) target = isl;
if (target != null)
{
target.gameObject.SetActive(false); yield return new WaitForSeconds(2f);
L(" 1칸 잠금 → " + WL.Look.Farm.WLIslandGrass.LastLog + " · 물 = " + water.sharedMaterial.name);
target.gameObject.SetActive(true); yield return new WaitForSeconds(3f);
L(" 다시 열기 → " + WL.Look.Farm.WLIslandGrass.LastLog + " · 물 = " + water.sharedMaterial.name
+ " · 물 교체 누적 " + WL.Look.Farm.WLIslandLook.WaterSwapped + " (평면 1장이라 새 가장자리도 같은 물)");
}
// ── 4) 성능 전(816h C)/후(816j D) 교대 2회 ──────────────────
var C = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(MatDir + "Farm_Water_WL_C.mat");
var FI = UnityEditor.AssetDatabase.LoadAssetAtPath<Material>(MatDir + "Farm_SimpleWater_Demo.mat");
L("");
L("4) 성능 (같은 카메라 1080×1920 · 60프레임 오프스크린 · 순서 교대 2회)");
for (int round = 0; round < 2; round++)
foreach (var pr in new[] { new object[] { "전(816h C)", C }, new object[] { "후(816j D)", adopted }, new object[] { "참고(FI SimpleWater)", FI } })
{
var m = pr[1] as Material; if (m == null) continue;
water.sharedMaterial = m; yield return null; yield return null;
L(" " + round + "회차 " + (string)pr[0] + " = " + WL816j_Final.Ms(live, 60).ToString("F3") + " ms/frame");
}
// ── 5) 되돌리기 (화면으로) ──────────────────────────────────
L("");
L("5) 되돌리기 — waterTo 를 C 로 되돌리면 816h 그대로 · waterMode 0 이면 FI 물");
water.sharedMaterial = C; yield return null; yield return new WaitForSeconds(0.3f);
L(" waterTo=C " + WL816j_Final.Shot(live, D + "z_rollback_to_C.png", 1080, 1920));
water.sharedMaterial = FI; yield return null; yield return new WaitForSeconds(0.3f);
L(" waterMode=0 " + WL816j_Final.Shot(live, D + "z_rollback_to_FI.png", 1080, 1920));
// ── 6) 최종 캡처 ───────────────────────────────────────────
water.sharedMaterial = C; yield return null; yield return new WaitForSeconds(0.3f);
float zc = -3.78f, shoreX = 0f;
for (float x = 4f; x < 90f; x += 0.25f)
{ RaycastHit h; if (Physics.Raycast(new Vector3(x, 60f, zc), Vector3.down, out h, 200f) && h.point.y > -0.9f) shoreX = x; }
var shore = WL816j_Final.Look("~WL816jFS", new Vector3(shoreX + 5.5f, 2.2f, zc + 5.5f), new Vector3(shoreX - 0.5f, -1f, zc - 0.5f), 32f);
var horizon = WL816j_Final.Look("~WL816jFH", new Vector3(-14f, 8f, -14f), new Vector3(6f, 0f, 6f), 55f);
L("");
L("6) 최종 캡처");
L(" [전 816h C] 게임 " + WL816j_Final.Shot(live, D + "n_before_game.png", 1080, 1920));
L(" [전 816h C] 가장자리 " + WL816j_Final.Shot(shore, D + "n_before_shore.png", 720, 1280));
L(" [전 816h C] 수평선 " + WL816j_Final.Shot(horizon, D + "n_before_horizon.png", 1080, 1920));
water.sharedMaterial = adopted; yield return null; yield return new WaitForSeconds(0.3f);
L(" [후 816j D] 게임 " + WL816j_Final.Shot(live, D + "n_after_game.png", 1080, 1920));
L(" [후 816j D] 가장자리 " + WL816j_Final.Shot(shore, D + "n_after_shore.png", 720, 1280));
L(" [후 816j D] 수평선 " + WL816j_Final.Shot(horizon, D + "n_after_horizon.png", 1080, 1920));
WL816j_Final.Strip(new[] { D + "n_before_game.png", D + "n_after_game.png" }, D + "z_final_side_by_side.png");
WL816j_Final.Strip(new[] { D + "n_before_shore.png", D + "n_after_shore.png" }, D + "z_final_shore_before_after.png");
L(" 좌우 = z_final_side_by_side.png(좌 지금/우 채택) · z_final_shore_before_after.png(가장자리 확대 전/후)");
Done();
}
void Done()
{
System.IO.File.WriteAllText("AgentScripts/WL816j_FINAL.txt", sb.ToString());
Debug.Log("[816j final]\n" + sb);
}
}