197 lines
12 KiB
C#
197 lines
12 KiB
C#
// WL887_Assets.cs — PD 지시 #887 검 + 방패 · 방패 치기 이펙트 교체 — 에셋 확인 도구(에디터 · 읽기 전용)
|
|
// unity command run_script --file AgentScripts/WL887_Assets.cs --entry WL887_Assets.Previews --args '[출력 폴더, "경로1|경로2|..."]'
|
|
using System.Text;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
|
|
public static class WL887_Assets
|
|
{
|
|
/// <summary>에셋 미리보기 PNG 저장(AssetPreview 캐시 — 첫 호출은 생성만 걸릴 수 있어 두 번 부른다).</summary>
|
|
public static object Previews(string outDir, string paths)
|
|
{
|
|
var sb = new StringBuilder();
|
|
System.IO.Directory.CreateDirectory(outDir);
|
|
foreach (var p in paths.Split('|'))
|
|
{
|
|
var o = AssetDatabase.LoadAssetAtPath<Object>(p);
|
|
if (o == null) { sb.Append("없음 ").Append(p).Append('\n'); continue; }
|
|
var tex = AssetPreview.GetAssetPreview(o);
|
|
if (tex == null) { sb.Append(AssetPreview.IsLoadingAssetPreview(o.GetInstanceID()) ? "생성 중 " : "null ").Append(p).Append('\n'); continue; }
|
|
var copy = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
|
|
copy.SetPixels(tex.GetPixels()); copy.Apply();
|
|
var name = System.IO.Path.GetFileNameWithoutExtension(p);
|
|
System.IO.File.WriteAllBytes(System.IO.Path.Combine(outDir, name + ".png"), copy.EncodeToPNG());
|
|
Object.DestroyImmediate(copy);
|
|
sb.Append("저장 ").Append(name).Append(' ').Append(tex.width).Append('x').Append(tex.height).Append('\n');
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
class ShieldSpec { public string outDir; public System.Collections.Generic.List<ShieldModel> models; }
|
|
class ShieldModel { public string name; public string source; public float[] scale; public float[] euler; public float[] offset; public ShieldMat material; }
|
|
class ShieldMat { public string from; public string @out; public float goochDark = -1f; public int receiveShadows = 1; }
|
|
|
|
/// <summary>#891 재질 복사본(원본 무수정) — 어두운 면 색 · 그림자 받기.</summary>
|
|
static Material MakeMat(ShieldMat s, StringBuilder sb)
|
|
{
|
|
if (s == null || string.IsNullOrEmpty(s.from) || string.IsNullOrEmpty(s.@out)) return null;
|
|
var src = AssetDatabase.LoadAssetAtPath<Material>(s.from);
|
|
if (src == null) { sb.Append("재질 원본 없음 ").Append(s.from).Append('\n'); return null; }
|
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(s.@out));
|
|
var m = AssetDatabase.LoadAssetAtPath<Material>(s.@out);
|
|
if (m == null) { m = new Material(src); AssetDatabase.CreateAsset(m, s.@out); } else m.CopyPropertiesFromMaterial(src);
|
|
m.shaderKeywords = src.shaderKeywords;
|
|
if (s.goochDark >= 0f && m.HasProperty("_GoochDarkColor")) m.SetColor("_GoochDarkColor", new Color(s.goochDark, s.goochDark, s.goochDark, 1f));
|
|
if (m.HasProperty("_ReceiveShadows")) m.SetFloat("_ReceiveShadows", s.receiveShadows);
|
|
if (s.receiveShadows == 0) { m.DisableKeyword("_MK_RECEIVE_SHADOWS"); m.DisableKeyword("_RECEIVESHADOWS_ON"); }
|
|
EditorUtility.SetDirty(m);
|
|
sb.Append("재질 ").Append(s.@out).Append(" goochDark=").Append(s.goochDark).Append(" receive=").Append(s.receiveShadows).Append('\n');
|
|
return m;
|
|
}
|
|
|
|
/// <summary>방패 래퍼 프리팹 생성(자식 = 팩 프리팹 인스턴스 · 배율/회전/위치는 자식) + Addressables 등록 (값 = AgentScripts/WL887_Shield.json · 멱등).</summary>
|
|
public static object BuildShield()
|
|
{
|
|
var spec = Newtonsoft.Json.JsonConvert.DeserializeObject<ShieldSpec>(System.IO.File.ReadAllText("AgentScripts/WL887_Shield.json"));
|
|
var sb = new StringBuilder();
|
|
var settings = UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings;
|
|
foreach (var m in spec.models)
|
|
{
|
|
var src = AssetDatabase.LoadAssetAtPath<GameObject>(m.source);
|
|
if (src == null) { sb.Append("원본 없음 ").Append(m.source).Append('\n'); continue; }
|
|
string path = spec.outDir + "/" + m.name + ".prefab";
|
|
var root = new GameObject(m.name);
|
|
try
|
|
{
|
|
var child = (GameObject)PrefabUtility.InstantiatePrefab(src);
|
|
child.transform.SetParent(root.transform, false);
|
|
child.transform.localPosition = new Vector3(m.offset[0], m.offset[1], m.offset[2]);
|
|
child.transform.localRotation = Quaternion.Euler(m.euler[0], m.euler[1], m.euler[2]);
|
|
child.transform.localScale = new Vector3(m.scale[0], m.scale[1], m.scale[2]);
|
|
var mat = MakeMat(m.material, sb);
|
|
foreach (var r in child.GetComponentsInChildren<Renderer>(true))
|
|
{
|
|
if (mat != null) r.sharedMaterial = mat;
|
|
if (m.material != null) r.receiveShadows = m.material.receiveShadows != 0;
|
|
}
|
|
PrefabUtility.SaveAsPrefabAsset(root, path);
|
|
}
|
|
finally { Object.DestroyImmediate(root); }
|
|
if (settings != null)
|
|
{
|
|
var e = settings.CreateOrMoveEntry(AssetDatabase.AssetPathToGUID(path), settings.DefaultGroup, false, false);
|
|
e.address = path;
|
|
}
|
|
sb.Append("프리팹 ").Append(path).Append(" ← ").Append(System.IO.Path.GetFileNameWithoutExtension(m.source)).Append(" scale(").Append(string.Join(",", m.scale)).Append(") euler(").Append(string.Join(",", m.euler)).Append(") · 주소 등록\n");
|
|
}
|
|
if (settings != null) settings.SetDirty(UnityEditor.AddressableAssets.Settings.AddressableAssetSettings.ModificationEvent.EntryMoved, null, true, true);
|
|
AssetDatabase.SaveAssets();
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>VFX 래퍼 프리팹(Resources) — 자식 = 팩 이펙트 프리팹 인스턴스(원본 무수정 · 런타임 Resources.Load 용). pairs = "출력경로=원본경로|…".</summary>
|
|
public static object BuildFx(string pairs)
|
|
{
|
|
var sb = new StringBuilder();
|
|
foreach (var pr in pairs.Split('|'))
|
|
{
|
|
var kv = pr.Split('=');
|
|
if (kv.Length != 2) continue;
|
|
var src = AssetDatabase.LoadAssetAtPath<GameObject>(kv[1]);
|
|
if (src == null) { sb.Append("원본 없음 ").Append(kv[1]).Append('\n'); continue; }
|
|
System.IO.Directory.CreateDirectory(System.IO.Path.GetDirectoryName(kv[0]));
|
|
var root = new GameObject(System.IO.Path.GetFileNameWithoutExtension(kv[0]));
|
|
try
|
|
{
|
|
var child = (GameObject)PrefabUtility.InstantiatePrefab(src);
|
|
child.transform.SetParent(root.transform, false);
|
|
PrefabUtility.SaveAsPrefabAsset(root, kv[0]);
|
|
}
|
|
finally { Object.DestroyImmediate(root); }
|
|
sb.Append("VFX 래퍼 ").Append(kv[0]).Append(" ← ").Append(System.IO.Path.GetFileName(kv[1])).Append('\n');
|
|
}
|
|
AssetDatabase.SaveAssets();
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>프리팹만 미리보기 씬에 세워 +Z · -Z · +X 쪽에서 찍는다(조명 = 카메라 뒤 방향광). 파일 = 접두 + 방향.png</summary>
|
|
public static object ModelShots(string prefabPath, string prefix, int size)
|
|
{
|
|
var p = AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath);
|
|
if (p == null) return "없음 " + prefabPath;
|
|
var scene = UnityEditor.SceneManagement.EditorSceneManager.NewPreviewScene();
|
|
var sb = new StringBuilder();
|
|
try
|
|
{
|
|
var go = (GameObject)PrefabUtility.InstantiatePrefab(p, scene);
|
|
var b = new Bounds(go.transform.position, Vector3.zero); bool has = false;
|
|
foreach (var r in go.GetComponentsInChildren<Renderer>(true)) { if (!has) { b = r.bounds; has = true; } else b.Encapsulate(r.bounds); }
|
|
var camGo = new GameObject("cam"); UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(camGo, scene);
|
|
var cam = camGo.AddComponent<Camera>(); cam.scene = scene; cam.clearFlags = CameraClearFlags.SolidColor; cam.backgroundColor = new Color(0.35f, 0.4f, 0.45f); cam.fieldOfView = 30f; cam.nearClipPlane = 0.01f; cam.farClipPlane = 100f;
|
|
var lightGo = new GameObject("light"); UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(lightGo, scene);
|
|
var lt = lightGo.AddComponent<Light>(); lt.type = LightType.Directional; lt.intensity = 1.2f;
|
|
var rt = new RenderTexture(size, size, 24); cam.targetTexture = rt;
|
|
float dist = b.extents.magnitude * 4f;
|
|
foreach (var dir in new[] { "+Z", "-Z", "+X" })
|
|
{
|
|
Vector3 v = dir == "+Z" ? Vector3.forward : dir == "-Z" ? Vector3.back : Vector3.right;
|
|
cam.transform.position = b.center + v * dist; cam.transform.LookAt(b.center);
|
|
lightGo.transform.rotation = cam.transform.rotation;
|
|
cam.Render();
|
|
var prev = RenderTexture.active; RenderTexture.active = rt;
|
|
var tex = new Texture2D(size, size, TextureFormat.RGB24, false); tex.ReadPixels(new Rect(0, 0, size, size), 0, 0); tex.Apply();
|
|
RenderTexture.active = prev;
|
|
System.IO.File.WriteAllBytes(prefix + dir + ".png", tex.EncodeToPNG()); Object.DestroyImmediate(tex);
|
|
sb.Append("저장 ").Append(dir).Append(' ');
|
|
}
|
|
cam.targetTexture = null; rt.Release(); Object.DestroyImmediate(rt);
|
|
}
|
|
finally { UnityEditor.SceneManagement.EditorSceneManager.ClosePreviewScene(scene); }
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>컨트롤러 0번 레이어 상태 → 클립 이름(원본 파일) · 속도.</summary>
|
|
public static object States(string ctrlPaths)
|
|
{
|
|
var sb = new StringBuilder();
|
|
foreach (var cp in ctrlPaths.Split('|'))
|
|
{
|
|
var c = AssetDatabase.LoadAssetAtPath<UnityEditor.Animations.AnimatorController>(cp);
|
|
if (c == null) { sb.Append("없음 ").Append(cp).Append('\n'); continue; }
|
|
sb.Append("## ").Append(System.IO.Path.GetFileNameWithoutExtension(cp)).Append('\n');
|
|
foreach (var cs in c.layers[0].stateMachine.states)
|
|
{
|
|
var m = cs.state.motion;
|
|
var path = m != null ? AssetDatabase.GetAssetPath(m) : "";
|
|
var dir = System.IO.Path.GetFileName(System.IO.Path.GetDirectoryName(path));
|
|
sb.Append(cs.state.name).Append('=').Append(m != null ? m.name : "-").Append('(').Append(dir).Append('/').Append(System.IO.Path.GetFileName(path)).Append(") ");
|
|
}
|
|
sb.Append('\n');
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
/// <summary>프리팹 구조 · 렌더러 · 재질 · 크기(바운즈) · 루트 회전.</summary>
|
|
public static object Describe(string paths)
|
|
{
|
|
var sb = new StringBuilder();
|
|
foreach (var p in paths.Split('|'))
|
|
{
|
|
var go = AssetDatabase.LoadAssetAtPath<GameObject>(p);
|
|
if (go == null) { sb.Append("없음 ").Append(p).Append('\n'); continue; }
|
|
var b = new Bounds(go.transform.position, Vector3.zero); bool has = false;
|
|
foreach (var r in go.GetComponentsInChildren<Renderer>(true)) { if (!has) { b = r.bounds; has = true; } else b.Encapsulate(r.bounds); }
|
|
sb.Append(System.IO.Path.GetFileNameWithoutExtension(p)).Append(" root rot=").Append(go.transform.localEulerAngles).Append(" scale=").Append(go.transform.localScale)
|
|
.Append(" bounds c=").Append(b.center.ToString("F3")).Append(" size=").Append(b.size.ToString("F3")).Append(" children=").Append(go.transform.childCount);
|
|
foreach (var r in go.GetComponentsInChildren<Renderer>(true))
|
|
sb.Append("\n ").Append(r.name).Append(" lpos=").Append(r.transform.localPosition.ToString("F3")).Append(" lrot=").Append(r.transform.localEulerAngles.ToString("F0")).Append(" lscale=").Append(r.transform.localScale.ToString("F2"))
|
|
.Append(" mat=").Append(r.sharedMaterial != null ? r.sharedMaterial.name + "/" + (r.sharedMaterial.shader != null ? r.sharedMaterial.shader.name : "-") : "null");
|
|
var guid = AssetDatabase.AssetPathToGUID(p);
|
|
var settings = UnityEditor.AddressableAssets.AddressableAssetSettingsDefaultObject.Settings;
|
|
var entry = settings != null ? settings.FindAssetEntry(guid) : null;
|
|
sb.Append("\n addressable=").Append(entry != null ? entry.address + " @" + entry.parentGroup.Name : "아님").Append('\n');
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
}
|