Project_WL/AgentScripts/WL816b_Verify.cs

138 lines
7.6 KiB
C#
Raw Permalink 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-816b — 최종 검증 (🔴 인게임 Play · 포스트 포함 · 게임 크기) · entry WL816bVerify.Run
// 실제 런타임 경로(`WLWeaponPalette.Apply`)로만 갈아끼운다 — 하니스 전용 경로를 쓰지 않는다.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using UnityEngine;
using WL.Look.Character;
public static class WL816bVerify
{
public static void Run()
{
WL816b.Reset(); WL816b.PubSetup();
var cfg = WLCharacterPaletteSettings.Instance;
WL816b.Log("");
WL816b.Log("SO: enabled_=" + cfg.enabled_ + " weaponEnabled_=" + cfg.weaponEnabled_
+ " 무기행 " + (cfg.weaponNames == null ? 0 : cfg.weaponNames.Length)
+ " 캐릭터행 " + (cfg.rendererNames == null ? 0 : cfg.rendererNames.Length));
WL816b.Log("=== 최종 검증 (인게임 Play · 포스트 포함 · 1080x1920 · ortho 10 · 덩어리 " + WL816bBake.FINAL_CHUNKS + " · 팔레트 " + WL816bBake.FINAL_PALETTE + "칸) ===");
var cA = WL816b.MeasureChar("v_char_A.png", null);
WL816b.Log(string.Format("캐릭터 (무기 없음 · 시작) : {0} px · 고유색 {1} · 비율 {2:F2} % · 단계 {3}", cA.px, cA.uniq, cA.ratio, cA.steps));
WL816b.Log("");
WL816b.Log("| 무기 | 화면 px | 고유색 전→후 | 서로다른색 % 전→후 | 칸당단계 평균/최대 | 배수 | 메시/렌더러 교체 |");
WL816b.Log("|---|---|---|---|---|---|---|");
int okMesh = 0, okRend = 0;
foreach (var w in WL816b.WEAPONS)
{
WL816b.Clear();
float rb, mult;
var go = WL816b.Spawn(w[0], int.Parse(w[1]), out rb, out mult);
if (go == null) continue;
WL816b.ReLook();
var mA = WL816b.MeasureNow(go, "v_" + w[0] + "_maskA.png", "v_" + w[0] + "_A.png");
// 원본 메시·머티리얼 기록(되돌리기 동일성 확인용)
var mf0 = go.GetComponentsInChildren<MeshFilter>(true).Select(f => f.sharedMesh).ToArray();
var rm0 = go.GetComponentsInChildren<Renderer>(true).Where(r => !(r is ParticleSystemRenderer)).Select(r => r.sharedMaterial).ToArray();
WLWeaponPalette.ResetCounters();
WL816b.UnLook(); // 🔴 장식을 먼저 벗긴다
bool applied = WLWeaponPalette.Apply(go.transform); // 🔴 실제 런타임 경로
WL816b.ReLook();
var mB = WL816b.MeasureNow(go, "v_" + w[0] + "_maskB.png", "v_" + w[0] + "_B.png");
string steps = "—"; int mx = 0; float av = 0;
if (applied)
{
var mat = go.GetComponentsInChildren<Renderer>(true).First(r => !(r is ParticleSystemRenderer)).sharedMaterial;
var tex = mat.HasProperty("_BaseMap") ? mat.GetTexture("_BaseMap") as Texture2D : null;
if (tex != null)
{
// 팔레트 텍스처에서 칸 색을 되읽어 칸별 단계를 잰다
var pal = new List<Vector3>();
int G = tex.width / 8;
for (int j = 0; j < G * G; j++)
{
var c = tex.GetPixel((j % G) * 8 + 4, (j / G) * 8 + 4);
if (c.r > 0.98f && c.g < 0.02f && c.b > 0.98f) continue; // 미사용 칸(마젠타)
pal.Add(new Vector3(c.r, c.g, c.b));
}
string det = WL816b.CellSteps(go, pal.ToArray(), out mx, out av);
steps = av.ToString("F2") + "/" + mx;
WL816b.Log(" " + w[0] + " " + det);
}
okMesh += WLWeaponPalette.AppliedMeshes; okRend += WLWeaponPalette.AppliedRenderers;
}
WL816b.Log(string.Format("| {0} | {1} | {2}→{3} | {4:F2}→{5:F2} | {6} | ×{7:F4} | {8} |",
w[0], mB.px, mA.uniq, mB.uniq, mA.ratio, mB.ratio, steps, mult,
applied ? (WLWeaponPalette.AppliedMeshes + "/" + WLWeaponPalette.AppliedRenderers) : "표에 없음(Orb)"));
// 되돌리기 동일성 — 원본으로 되돌리면 글자 하나까지 같은가
if (applied)
{
WL816b.UnLook();
var fs = go.GetComponentsInChildren<MeshFilter>(true);
for (int i = 0; i < fs.Length; i++) fs[i].sharedMesh = mf0[i];
var rs = go.GetComponentsInChildren<Renderer>(true).Where(r => !(r is ParticleSystemRenderer)).ToArray();
for (int i = 0; i < rs.Length; i++) { var ms = rs[i].sharedMaterials; for (int k = 0; k < ms.Length; k++) ms[k] = rm0[i]; rs[i].sharedMaterials = ms; }
WL816b.ReLook();
var mR = WL816b.MeasureNow(go, null, "v_" + w[0] + "_R.png");
WL816b.Log(string.Format(" 되돌림 확인 {0} : px {1}(전 {2}) · 고유색 {3}(전 {4}) · {5}",
w[0], mR.px, mA.px, mR.uniq, mA.uniq, (mR.px == mA.px && mR.uniq == mA.uniq) ? "동일 ✅" : "차이 ⚠"));
}
}
WL816b.Clear();
var cB = WL816b.MeasureChar("v_char_B.png", null);
WL816b.Log("");
WL816b.Log(string.Format("캐릭터 (무기 없음 · 끝) : {0} px · 고유색 {1} · 비율 {2:F2} % · 단계 {3} → 악화 {4}",
cB.px, cB.uniq, cB.ratio, cB.steps, (cB.uniq <= cA.uniq && cB.ratio <= cA.ratio + 0.05f) ? "없음 ✅" : "고유색 " + (cB.uniq - cA.uniq) + " · 비율 " + (cB.ratio - cA.ratio).ToString("F2") + "%p"));
WL816b.Log("합계 교체: 메시 " + okMesh + " · 렌더러 " + okRend);
// ⓐⓑ 전신 캡처 — 기본 클래스(10501) 메이스+방패를 동시에 든 전신
WL816b.Clear();
float r1, m1, r2, m2;
var g1 = WL816b.Spawn("PP_Theme_10_Mace_003", 1, out r1, out m1);
var g2 = WL816b.Spawn("PP_Theme_10_Shield_003", 0, out r2, out m2);
WL816b.ReLook(); WL816b.ShootGame("a_full_before.png");
WL816b.UnLook();
WLWeaponPalette.Apply(g1.transform); WLWeaponPalette.Apply(g2.transform);
WL816b.ReLook(); WL816b.ShootGame("b_full_after.png");
// 한손검 전신도 한 장씩
WL816b.Clear();
var g3 = WL816b.Spawn("Elven_Sword_01", 2, out r1, out m1);
WL816b.ReLook(); WL816b.ShootGame("a_sword_before.png");
WL816b.UnLook();
WLWeaponPalette.Apply(g3.transform);
WL816b.ReLook(); WL816b.ShootGame("b_sword_after.png");
WL816b.Clear(); WL816b.FreeTmp(); WL816b.PubTeardown();
WL816b.Flush("WL816b_VERIFY.txt");
Debug.Log("[WL816b] verify done");
}
/// <summary>🔴 대조군 — 무기를 하나도 붙이지 않고 같은 횟수만큼 측정·ReLook 을 반복한다.
/// 캐릭터 수치가 여기서도 같은 만큼 흔들리면 그 흔들림은 **하니스 탓**이지 무기 탓이 아니다.</summary>
public static void Control()
{
WL816b.Reset(); WL816b.PubSetup();
WL816b.Log("=== 대조군: 무기 0 · ReLook/측정만 12회 반복 ===");
var c0 = WL816b.MeasureChar(null, null);
WL816b.Log(string.Format("0회 : {0} px · 고유색 {1} · 비율 {2:F2} %", c0.px, c0.uniq, c0.ratio));
for (int i = 1; i <= 12; i++)
{
WL816b.UnLook(); WL816b.ReLook();
var c = WL816b.MeasureChar(null, null);
if (i % 4 == 0 || i == 12) WL816b.Log(string.Format("{0}회 : {1} px · 고유색 {2} · 비율 {3:F2} %", i, c.px, c.uniq, c.ratio));
}
WL816b.PubTeardown();
WL816b.Flush("WL816b_CONTROL.txt");
Debug.Log("[WL816b] control done");
}
}