Project_WL/AgentScripts/WL814k_Bake.cs

134 lines
7.8 KiB
C#
Raw Permalink Normal View History

// WL-814k 베이크 드라이버 (에디트 모드 전용 · 게임 코드 아님)
// 에셋 만들기 : unity command run_script --file AgentScripts/WL814k_Bake.cs --entry WL814k_Bake.MakeAssets
// 시범 2종 굽기: unity command run_script --file AgentScripts/WL814k_Bake.cs --entry WL814k_Bake.BakeDemo
// 임의 프리팹 : WL814k_Bake.Targets 를 바꾸거나 에디터 창(WL ▸ 도트 스프라이트 굽기)을 쓴다.
//
// 🔴 이 드라이버에만 「어떤 프리팹을 구울지」가 적혀 있다. 툴(Assets/WL/Look/Sprite/Editor/WLSpriteBaker.cs)
// 에는 캐릭터 이름이 0개다 — PD 가 캐릭터 에셋을 바꿔도 툴은 그대로 쓴다.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEditor;
using UnityEngine;
using WL.Look.SpriteBake;
using WL.Look.SpriteBake.EditorTools;
public static class WL814k_Bake
{
const string kResDir = "Assets/WL/Look/Sprite/Resources/WL";
const string kOutDir = "Assets/WL/Look/Sprite/Baked";
const string kTxt = "AgentScripts/WL814k_BAKE.txt";
// 🔴 1차 시범 = PC 1종 + 잡몹 1종 (전수 전환은 PD 승인 뒤)
// 두 번째 값 = 인게임 실제 루트 스케일(0 이면 프리팹 자체 값).
// PC 는 ClassConfig.f_Scale 0.7 로 스폰된다(814b·발주서 실측) → 그 크기로 구워야
// 스프라이트 1px 이 화면 1px 과 정확히 맞는다. 몹은 프리팹 스케일 그대로(Batty_A = 1.5).
public static readonly string[] Targets = { "Assets/Res_Addr/PC/Ai01.prefab", "Assets/Res_Addr/Mobs/Mob/Batty_A.prefab" };
public static readonly float[] TargetScales = { 0.7f, 0f };
static StringBuilder s_sb;
static void L(string s) { s_sb.AppendLine(s); Debug.Log("[WL814k] " + s); }
// ═════════════════════════════════════════════════════════════════════════
// ① 설정 에셋 2개 만들기
// ═════════════════════════════════════════════════════════════════════════
public static void MakeAssets()
{
s_sb = new StringBuilder();
L("WL-814k 설정 에셋 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
Directory.CreateDirectory(kResDir);
Directory.CreateDirectory(kOutDir);
var bake = AssetDatabase.LoadAssetAtPath<WLSpriteBakeSettings>(kResDir + "/WLSpriteBakeSettings.asset");
if (bake == null)
{
bake = ScriptableObject.CreateInstance<WLSpriteBakeSettings>();
AssetDatabase.CreateAsset(bake, kResDir + "/WLSpriteBakeSettings.asset");
L("만듦 " + kResDir + "/WLSpriteBakeSettings.asset");
}
else L("있음 " + kResDir + "/WLSpriteBakeSettings.asset");
var look = AssetDatabase.LoadAssetAtPath<WLSpriteLookSettings>(kResDir + "/WLSpriteLookSettings.asset");
if (look == null)
{
look = ScriptableObject.CreateInstance<WLSpriteLookSettings>();
AssetDatabase.CreateAsset(look, kResDir + "/WLSpriteLookSettings.asset");
L("만듦 " + kResDir + "/WLSpriteLookSettings.asset");
}
else L("있음 " + kResDir + "/WLSpriteLookSettings.asset");
AssetDatabase.SaveAssetIfDirty(bake);
AssetDatabase.SaveAssetIfDirty(look);
WLSpriteBakeSettings.ClearCache();
WLSpriteLookSettings.ClearCache();
L(string.Format("굽기 기본값 — 내림각 {0:0.000}° · 픽셀 {1:0.00000} m · 방향 {2} · 프레임 {3}(자동 {4}) · 팔레트 {5}단계 · 알파컷 {6}",
bake.PitchDeg, bake.WorldPerPixel, bake.dirCount, bake.frameSize, bake.autoFrameSize, bake.paletteLevels, bake.alphaCutoff));
File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false));
}
// ═════════════════════════════════════════════════════════════════════════
// ② 시범 2종 굽기 + SO 목록 연결
// ═════════════════════════════════════════════════════════════════════════
public static void BakeDemo() { BakeList(Targets, TargetScales); }
public static void BakeList(string[] paths, float[] scales)
{
s_sb = new StringBuilder();
L("WL-814k 굽기 · " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + " · Unity " + Application.unityVersion);
var sets = new List<WLSpriteSet>();
double total = 0;
for (int ti = 0; ti < paths.Length; ti++)
{
var p = paths[ti];
float scale = (scales != null && ti < scales.Length) ? scales[ti] : 0f;
L("");
L("──────── " + p + (scale > 0f ? " (루트 스케일 " + scale + ")" : " (프리팹 스케일 그대로)"));
// 🔴 굽기마다 설정 에셋을 다시 읽는다 — PNG 임포트가 AssetDatabase 를 돌려
// 참조만 들고 있던 SO 가 언로드돼 null 이 되는 것을 실측했다(첫 시도 실패 원인).
var cfg = AssetDatabase.LoadAssetAtPath<WLSpriteBakeSettings>(kResDir + "/WLSpriteBakeSettings.asset");
if (cfg == null) { L("FAIL — 굽기 설정 에셋 없음. MakeAssets 먼저."); break; }
var r = WLSpriteBaker.Bake(p, cfg, kOutDir, null, scale);
total += r.seconds;
L(r.log.ToString().TrimEnd());
foreach (var n in r.notes) L(" · 「미확인/주의」 " + n);
if (!r.ok) { L("FAIL"); continue; }
L(string.Format("OK — 프레임 {0}×{0} px · 방향 {1} · 총 {2}칸 · 시트 {3}×{4} · PNG {5:N0} B ({6:N1} KB) · {7:0.00}초 · 캐릭터 {8:0} px",
r.frameSize, r.dirCount, r.totalFrames, r.sheetW, r.sheetH, r.pngBytes, r.pngBytes / 1024.0, r.seconds, r.charPixelHeight));
L(" PNG = " + r.pngPath);
L(" SO = " + r.setPath);
var set = AssetDatabase.LoadAssetAtPath<WLSpriteSet>(r.setPath);
if (set != null)
{
sets.Add(set);
var sb2 = new StringBuilder();
foreach (var a in set.actions)
sb2.Append(string.Format("{0}(시작 {1}·{2}프레임·{3:0.0}fps·상태 [{4}]·클립 {5}) ",
a.key, a.startIndex, a.frameCount, a.fps, string.Join("/", a.stateNames), a.clipName));
L(" 동작표 = " + sb2.ToString().TrimEnd());
L(string.Format(" 발밑 픽셀 ({0:0.0}, {1:0.0}) · 픽셀 1개 {2:0.00000} m · 베이크 스케일 {3:0.000}",
set.footPixelX, set.footPixelY, set.worldPerPixel, set.bakeScale));
}
}
// 런타임 SO 에 시트 목록 연결
var look = AssetDatabase.LoadAssetAtPath<WLSpriteLookSettings>(kResDir + "/WLSpriteLookSettings.asset");
if (look != null)
{
look.sets = sets.ToArray();
EditorUtility.SetDirty(look);
AssetDatabase.SaveAssetIfDirty(look);
L("");
L("런타임 SO 연결 — sets " + sets.Count + "개 (" + kResDir + "/WLSpriteLookSettings.asset)");
}
L("");
L(string.Format("합계 굽기 시간 = {0:0.00}초 / {1}종 → 1종당 {2:0.00}초", total, paths.Length, total / Math.Max(1, paths.Length)));
Write();
}
static void Write() { File.WriteAllText(kTxt, s_sb.ToString(), new UTF8Encoding(false)); Debug.Log("[WL814k] → " + kTxt); }
}