Project_WL/AgentScripts/WL_NolantMerchantSetup.cs

91 lines
5.8 KiB
C#

// ─────────────────────────────────────────────────────────────────────────────
// WL_NolantMerchantSetup.cs — 상인 대역 캐릭터(Stylized NPC - Peasant Nolant · 밀짚모자) WL 프리팹 변형 만들기 (2026-10-15 PD)
//
// PD 「Stylized NPC - Peasant Nolant 에셋을 추가했어. "상인 설치" 시 방금 추가한 에셋의 밀집모자를 쓴 캐릭터를 가판대 대신 세우고 싶어.」
// ■ 원본 에셋은 고치지 않는다(재질·프리팹·컨트롤러 0줄) — WL 폴더에 새로 만든다.
// · 재질: 원본이 Built-in `Standard` 라 URP 에서 분홍 → FI 캐릭터와 같은 `URP/Simple Lit`(+ 원본 텍스처) 복사본
// · 애니메이터: 원본 컨트롤러 기본 상태가 `Walk` + Apply Root Motion = 제자리에서 걸어 나간다 → 대기(Idle) 1상태 컨트롤러 · 루트 모션 끔
// · 프리팹: 원본 프리팹의 **변형(Variant)** — 위 두 가지만 덮어쓴다
// · 텍스처: Android 최대 1024(모바일 · 원본 2048) — 임포터 플랫폼 덮어쓰기만
// 실행 = unity command run_script --file AgentScripts/WL_NolantMerchantSetup.cs --entry WL_NolantMerchantSetup.Run --args "[\"Yellow\"]"
// ─────────────────────────────────────────────────────────────────────────────
using System.IO;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
public static class WL_NolantMerchantSetup
{
const string SrcRoot = "Assets/Stylized NPC - Peasant Nolant";
const string OutDir = "Assets/WL/Island/NPC";
public static string Run(string color)
{
if (string.IsNullOrEmpty(color)) color = "Yellow";
string srcPrefab = SrcRoot + "/Prefabs/Peasant Nolant " + color + "(Free Version).prefab";
string srcTex = SrcRoot + "/Textures/Peasant Nolant " + color + ".png";
string fbx = SrcRoot + "/Models/Peasant Nolant(Free Version).fbx";
var prefab = AssetDatabase.LoadAssetAtPath<GameObject>(srcPrefab);
var tex = AssetDatabase.LoadAssetAtPath<Texture2D>(srcTex);
if (prefab == null || tex == null) return "원본 없음 — " + srcPrefab + " / " + srcTex;
if (!AssetDatabase.IsValidFolder(OutDir)) { Directory.CreateDirectory(OutDir); AssetDatabase.Refresh(); }
// ① 텍스처 — Android 최대 1024
var ti = AssetImporter.GetAtPath(srcTex) as TextureImporter;
var ps = ti.GetPlatformTextureSettings("Android");
if (!ps.overridden || ps.maxTextureSize != 1024)
{
ps.overridden = true; ps.maxTextureSize = 1024; ps.format = TextureImporterFormat.ASTC_6x6;
ti.SetPlatformTextureSettings(ps); ti.SaveAndReimport();
}
// ② 재질 — URP Simple Lit + 원본 텍스처(FI 캐릭터 Skin 재질과 같은 셰이더 · 반사광 없음 = 원본 Standard 광택 0 과 같은 무광)
string matPath = OutDir + "/WL_Nolant_" + color + ".mat";
var mat = AssetDatabase.LoadAssetAtPath<Material>(matPath);
if (mat == null) { mat = new Material(Shader.Find("Universal Render Pipeline/Simple Lit")); AssetDatabase.CreateAsset(mat, matPath); }
mat.shader = Shader.Find("Universal Render Pipeline/Simple Lit");
mat.SetTexture("_BaseMap", tex);
mat.SetColor("_BaseColor", Color.white);
mat.SetFloat("_Smoothness", 0f);
mat.SetFloat("_SpecularHighlights", 0f);
mat.DisableKeyword("_SPECULAR_COLOR"); mat.DisableKeyword("_SPECGLOSSMAP");
mat.enableInstancing = true;
EditorUtility.SetDirty(mat);
// ③ 대기 1상태 컨트롤러
string ctrlPath = OutDir + "/WL_Nolant_Idle.controller";
AnimationClip idle = null;
foreach (var o in AssetDatabase.LoadAllAssetsAtPath(fbx)) if (o is AnimationClip c && !c.name.StartsWith("__") && c.name.EndsWith("Idle")) idle = c;
if (idle == null) return "Idle 클립 없음 — " + fbx;
var ctrl = AssetDatabase.LoadAssetAtPath<UnityEditor.Animations.AnimatorController>(ctrlPath);
if (ctrl == null) ctrl = UnityEditor.Animations.AnimatorController.CreateAnimatorControllerAtPath(ctrlPath);
var sm = ctrl.layers[0].stateMachine;
foreach (var st in sm.states) sm.RemoveState(st.state);
var s = sm.AddState("Idle");
s.motion = idle;
sm.defaultState = s;
EditorUtility.SetDirty(ctrl);
// ④ 프리팹 변형 — 재질 · 컨트롤러 · 루트 모션 끔
string varPath = OutDir + "/WL_Merchant_Nolant_" + color + ".prefab";
var inst = (GameObject)PrefabUtility.InstantiatePrefab(prefab);
int mats = 0;
foreach (var r in inst.GetComponentsInChildren<Renderer>(true))
{
var arr = r.sharedMaterials;
for (int i = 0; i < arr.Length; i++) { arr[i] = mat; mats++; }
r.sharedMaterials = arr;
r.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.On;
}
var an = inst.GetComponent<Animator>();
an.runtimeAnimatorController = ctrl;
an.applyRootMotion = false;
an.cullingMode = AnimatorCullingMode.CullUpdateTransforms;
var saved = PrefabUtility.SaveAsPrefabAsset(inst, varPath);
Object.DestroyImmediate(inst);
AssetDatabase.SaveAssets();
return "OK — " + varPath + " (원본 " + srcPrefab + " 변형 · 재질 " + mats + "칸 → " + matPath + " · 컨트롤러 " + ctrlPath + " = " + idle.name + " · 루트 모션 끔 · 텍스처 Android 1024/ASTC6x6) · saved=" + (saved != null) +
" · variant=" + (saved != null && PrefabUtility.GetPrefabAssetType(saved) == PrefabAssetType.Variant);
}
}