Project_WL/AgentScripts/WL842_StatusPrefabs.cs

178 lines
12 KiB
C#

// WL842_StatusPrefabs.cs — #842 상태이상 VFX 준비(에디터 전용 · Play 밖에서)
// ① ConvertLegacy : Master Stylized FX 안에서 아직 내장(Built-in) 셰이더(Particles/Standard Unlit 211 · Surface 210 · Standard 46)를 쓰는 머티리얼을 URP 로 변환.
// 동봉 MSFURP 패키지가 46장을 빠뜨린다(DizzyStar·SleepSymbol·BubbleSymbol·Spike3D 등 = 우리가 쓰는 것들). _Mode(2 Fade·4 Additive) 와 블렌드 값을 그대로 옮긴다.
// ② Build : Prefabs/Buffs·Hit 의 원본 프리팹을 복제해 Resources/WL/Status/<name>.prefab 으로 저장(독은 보라 틴트). 원본 에셋 무수정.
// unity command run_script --file AgentScripts/WL842_StatusPrefabs.cs --entry WL842_StatusPrefabs.ConvertLegacy
// unity command run_script --file AgentScripts/WL842_StatusPrefabs.cs --entry WL842_StatusPrefabs.Build --args '[]'
using System.Collections.Generic;
using System.Text;
using UnityEditor;
using UnityEngine;
public static class WL842_StatusPrefabs
{
const string AssetRoot = "Assets/ResWork/VFX/MasterStylizedFX";
const string OutDir = "Assets/WL/Combat/Status/Resources/WL/Status";
const string BuiltinGuid = "0000000000000000f000000000000000";
// 출력 이름 → (원본 프리팹 경로 · 틴트(없으면 null))
static readonly (string name, string src, Color? tint)[] Map =
{
("WL_Status_Stun", "Prefabs/Buffs/Dizziness.prefab", null),
("WL_Status_Sleep", "Prefabs/Buffs/Sleeping.prefab", null),
("WL_Status_SpeedUp", "Prefabs/Buffs/EnhanceBuff.prefab", null), // 꺽새(^) 상승
("WL_Status_SpeedDown", "Prefabs/Buffs/Debuff.prefab", null), // 꺽새 하락
("WL_Status_StatUp", "Prefabs/Buffs/EnhanceBuff2.prefab", null), // 화살표 상승
("WL_Status_Poison", "Prefabs/Buffs/DrunkBuff.prefab", new Color(0.72f, 0.30f, 1f, 1f)), // 방울+연기 → 보라
("WL_Status_Bleed", "Prefabs/Hit/OrangeSlashHit.prefab", null), // 스크린샷 대조 후 교체 가능(SetBleedSource)
};
public static string ConvertLegacy()
{
if (EditorApplication.isPlaying) return "skipped: playing";
var sb = new StringBuilder();
int n = 0, skipped = 0;
var unlit = Shader.Find("Universal Render Pipeline/Particles/Unlit");
var lit = Shader.Find("Universal Render Pipeline/Lit");
if (unlit == null || lit == null) return "URP shaders not found";
foreach (var guid in AssetDatabase.FindAssets("t:Material", new[] { AssetRoot + "/Materials" }))
{
string path = AssetDatabase.GUIDToAssetPath(guid);
var txt = System.IO.File.ReadAllText(path);
var m = System.Text.RegularExpressions.Regex.Match(txt, @"m_Shader: \{fileID: (\d+), guid: " + BuiltinGuid);
if (!m.Success) { skipped++; continue; }
int fid = int.Parse(m.Groups[1].Value);
var mat = AssetDatabase.LoadAssetAtPath<Material>(path);
if (mat == null) continue;
var mainTex = mat.HasProperty("_MainTex") ? mat.GetTexture("_MainTex") : null;
var scale = mat.HasProperty("_MainTex") ? mat.GetTextureScale("_MainTex") : Vector2.one;
var offset = mat.HasProperty("_MainTex") ? mat.GetTextureOffset("_MainTex") : Vector2.zero;
var color = mat.HasProperty("_Color") ? mat.GetColor("_Color") : Color.white;
if (fid == 46)
{ // Standard → Lit
mat.shader = lit;
mat.SetTexture("_BaseMap", mainTex); mat.SetColor("_BaseColor", color);
sb.AppendLine("lit " + path.Substring(AssetRoot.Length + 1));
EditorUtility.SetDirty(mat); n++; continue;
}
// Particles/Standard Unlit(211)·Surface(210) → Particles/Unlit · 블렌드 값(_Mode·_SrcBlend·_DstBlend·_ZWrite·_Cull·_ColorMode) 승계
int mode = mat.HasProperty("_Mode") ? (int)mat.GetFloat("_Mode") : 2;
float src = mat.HasProperty("_SrcBlend") ? mat.GetFloat("_SrcBlend") : 5f, dst = mat.HasProperty("_DstBlend") ? mat.GetFloat("_DstBlend") : 10f;
float zw = mat.HasProperty("_ZWrite") ? mat.GetFloat("_ZWrite") : 0f, cull = mat.HasProperty("_Cull") ? mat.GetFloat("_Cull") : 2f;
float colorMode = mat.HasProperty("_ColorMode") ? mat.GetFloat("_ColorMode") : 0f;
float soft = mat.HasProperty("_SoftParticlesEnabled") ? mat.GetFloat("_SoftParticlesEnabled") : 0f;
mat.shader = unlit;
mat.SetTexture("_BaseMap", mainTex); mat.SetTextureScale("_BaseMap", scale); mat.SetTextureOffset("_BaseMap", offset);
mat.SetColor("_BaseColor", color);
bool opaque = mode == 0 || mode == 1;
mat.SetFloat("_Surface", opaque ? 0f : 1f);
mat.SetFloat("_Blend", mode == 4 ? 2f : mode == 3 ? 1f : mode == 6 ? 3f : 0f);
mat.SetFloat("_AlphaClip", mode == 1 ? 1f : 0f);
mat.SetFloat("_SrcBlend", src); mat.SetFloat("_DstBlend", dst);
if (mat.HasProperty("_SrcBlendAlpha")) { mat.SetFloat("_SrcBlendAlpha", src); mat.SetFloat("_DstBlendAlpha", dst); }
mat.SetFloat("_ZWrite", zw); mat.SetFloat("_Cull", cull);
mat.SetFloat("_ColorMode", colorMode);
mat.SetFloat("_SoftParticlesEnabled", soft);
if (opaque) { mat.DisableKeyword("_SURFACE_TYPE_TRANSPARENT"); mat.SetOverrideTag("RenderType", mode == 1 ? "TransparentCutout" : "Opaque"); mat.renderQueue = mode == 1 ? 2450 : 2000; }
else { mat.EnableKeyword("_SURFACE_TYPE_TRANSPARENT"); mat.SetOverrideTag("RenderType", "Transparent"); mat.renderQueue = 3000; }
if (mode == 3) mat.EnableKeyword("_ALPHAPREMULTIPLY_ON"); else mat.DisableKeyword("_ALPHAPREMULTIPLY_ON");
if (mode == 6) mat.EnableKeyword("_ALPHAMODULATE_ON"); else mat.DisableKeyword("_ALPHAMODULATE_ON");
if (mode == 1) mat.EnableKeyword("_ALPHATEST_ON"); else mat.DisableKeyword("_ALPHATEST_ON");
if (soft > 0f) mat.EnableKeyword("_SOFTPARTICLES_ON"); else mat.DisableKeyword("_SOFTPARTICLES_ON");
mat.SetShaderPassEnabled("ShadowCaster", false);
EditorUtility.SetDirty(mat); n++;
sb.AppendLine("unlit " + path.Substring(AssetRoot.Length + 1) + " mode=" + mode + " blend=" + src + "/" + dst);
}
AssetDatabase.SaveAssets();
return "converted " + n + " (already URP " + skipped + ")\n" + sb;
}
public static string Build()
{
if (EditorApplication.isPlaying) return "skipped: playing";
if (!AssetDatabase.IsValidFolder(OutDir)) System.IO.Directory.CreateDirectory(OutDir);
AssetDatabase.Refresh();
var sb = new StringBuilder();
foreach (var e in Map)
{
string srcPath = AssetRoot + "/" + e.src;
var src = AssetDatabase.LoadAssetAtPath<GameObject>(srcPath);
if (src == null) { sb.AppendLine("missing " + srcPath); continue; }
var inst = (GameObject)PrefabUtility.InstantiatePrefab(src);
PrefabUtility.UnpackPrefabInstance(inst, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
inst.name = e.name;
inst.transform.position = Vector3.zero; inst.transform.rotation = Quaternion.identity; inst.transform.localScale = Vector3.one;
int ps = 0;
foreach (var p in inst.GetComponentsInChildren<ParticleSystem>(true))
{
ps++;
{ var main = p.main; main.scalingMode = ParticleSystemScalingMode.Hierarchy; } // 트랜스폼 스케일이 파티클 크기에도 먹게(기본 Shape 는 방출 범위만 줄어 별이 원래 크기로 남는다 · 2026-10-11 실측)
if (e.tint.HasValue)
{
var main = p.main; var sc = main.startColor;
sc.mode = ParticleSystemGradientMode.Color; sc.color = e.tint.Value; main.startColor = sc;
var col = p.colorOverLifetime;
if (col.enabled) { var g = col.color; if (g.mode == ParticleSystemGradientMode.Gradient && g.gradient != null) { var grad = g.gradient; var keys = grad.colorKeys; for (int i = 0; i < keys.Length; i++) keys[i].color = e.tint.Value; grad.SetKeys(keys, grad.alphaKeys); g.gradient = grad; col.color = g; } }
}
}
foreach (var l in inst.GetComponentsInChildren<Light>(true)) Object.DestroyImmediate(l); // 포인트 라이트는 치비 씬에서 과함
string outPath = OutDir + "/" + e.name + ".prefab";
PrefabUtility.SaveAsPrefabAsset(inst, outPath);
Object.DestroyImmediate(inst);
sb.AppendLine(e.name + " ← " + e.src + " ps=" + ps + (e.tint.HasValue ? " tint" : ""));
}
AssetDatabase.SaveAssets(); AssetDatabase.Refresh();
return sb.ToString();
}
// ── #843 임팩트 프리팹 사본 (Resources/WL/Impact/) ───────────────────────────
const string ImpactDir = "Assets/WL/Combat/Impact/Resources/WL/Impact";
static readonly (string name, string src)[] ImpactMap =
{
("WL_Impact_Hit_Blue", "Prefabs/Hit/SlashHitBlue.prefab"), // 검 피격 — 파란 별 + 긴 베기 줄 + 불꽃(PD 스크린샷)
("WL_Impact_Hit_Orange", "Prefabs/Hit/OrangeSlashHit.prefab"), // 해머 피격 — 주황 타격 폭발
("WL_Impact_Swing_Orange", "Prefabs/Slash/OrangeSlash.prefab"), // 해머 궤적 — 주황 회전 링(SlashHead·DustRing)
("WL_Impact_Ground", "Prefabs/GroundBlast/ExplosionBlast.prefab"), // 지면 충격파 — 주황 폭발 + 검은 파편 + 불꽃
};
public static string BuildImpact()
{
if (EditorApplication.isPlaying) return "skipped: playing";
if (!AssetDatabase.IsValidFolder(ImpactDir)) System.IO.Directory.CreateDirectory(ImpactDir);
AssetDatabase.Refresh();
var sb = new StringBuilder();
foreach (var e in ImpactMap)
{
var src = AssetDatabase.LoadAssetAtPath<GameObject>(AssetRoot + "/" + e.src);
if (src == null) { sb.AppendLine("missing " + e.src); continue; }
var inst = (GameObject)PrefabUtility.InstantiatePrefab(src);
PrefabUtility.UnpackPrefabInstance(inst, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
inst.name = e.name; inst.transform.position = Vector3.zero; inst.transform.rotation = Quaternion.identity; inst.transform.localScale = Vector3.one;
int ps = 0;
foreach (var p in inst.GetComponentsInChildren<ParticleSystem>(true)) { ps++; var main = p.main; main.scalingMode = ParticleSystemScalingMode.Hierarchy; }
foreach (var l in inst.GetComponentsInChildren<Light>(true)) Object.DestroyImmediate(l);
PrefabUtility.SaveAsPrefabAsset(inst, ImpactDir + "/" + e.name + ".prefab");
Object.DestroyImmediate(inst);
sb.AppendLine(e.name + " ← " + e.src + " ps=" + ps);
}
AssetDatabase.SaveAssets(); AssetDatabase.Refresh();
return sb.ToString();
}
/// <summary>출혈 원본 프리팹 교체(스크린샷 대조 결과 반영). 예: SetBleedSource("Prefabs/Slash/OrangeSlash.prefab")</summary>
public static string SetBleedSource(string relPrefab)
{
if (EditorApplication.isPlaying) return "skipped: playing";
var src = AssetDatabase.LoadAssetAtPath<GameObject>(AssetRoot + "/" + relPrefab);
if (src == null) return "missing " + relPrefab;
var inst = (GameObject)PrefabUtility.InstantiatePrefab(src);
PrefabUtility.UnpackPrefabInstance(inst, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction);
inst.name = "WL_Status_Bleed"; inst.transform.position = Vector3.zero; inst.transform.rotation = Quaternion.identity; inst.transform.localScale = Vector3.one;
foreach (var p in inst.GetComponentsInChildren<ParticleSystem>(true)) { var main = p.main; main.scalingMode = ParticleSystemScalingMode.Hierarchy; }
foreach (var l in inst.GetComponentsInChildren<Light>(true)) Object.DestroyImmediate(l);
PrefabUtility.SaveAsPrefabAsset(inst, OutDir + "/WL_Status_Bleed.prefab");
Object.DestroyImmediate(inst);
AssetDatabase.SaveAssets();
return "bleed ← " + relPrefab;
}
}