107 lines
4.6 KiB
C#
107 lines
4.6 KiB
C#
// ─────────────────────────────────────────────────────────────────────────────
|
|
// WLCharacterLook.cs — 캐릭터 머티리얼을 모드에 맞게 갈아끼운다 (WL-814s)
|
|
//
|
|
// PD 지시 #814 · 발주서 WL-814s §1-5
|
|
//
|
|
// ■ 무엇을 하나
|
|
// 프리팹(LH_M05)은 기본 모드의 머티리얼을 들고 있다. 이 컴포넌트가 Awake 에서
|
|
// SO(WLCharacterLookSettings) 를 읽어 「지금 모드」의 머티리얼로 맞춘다.
|
|
// enabled_ = 0 · mode = 0 이면 **원본 머티리얼로 되돌린다**(되돌리기 스위치).
|
|
//
|
|
// ■ 어떻게 맞추나 (프리팹이 무엇을 들고 있든 결과가 같다 = 멱등)
|
|
// SO 의 4개 배열(originals · mode1 · mode2 · mode3)은 같은 길이·같은 순서다.
|
|
// 렌더러가 들고 있는 머티리얼이 어느 배열의 i번이든, 목표 배열의 i번으로 바꾼다.
|
|
// 표에 없는 머티리얼(무기 등)은 건드리지 않는다.
|
|
//
|
|
// ■ 성능 / GC
|
|
// Awake 1회. 렌더러 수만큼만 돈다(LH_M05 = 7). 바뀔 것이 없으면 배열 대입도 하지 않는다.
|
|
//
|
|
// 🔴 Debug.LogError / Debug.LogException 을 쓰지 않는다(813z 규칙).
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
namespace WL.Look.Character
|
|
{
|
|
[DisallowMultipleComponent]
|
|
public class WLCharacterLook : MonoBehaviour
|
|
{
|
|
// 진단(프로브가 읽는다)
|
|
public static int AppliedRenderers, AppliedSlots, LastMode = -1;
|
|
public static string LastLog = "";
|
|
|
|
static readonly List<Renderer> s_buf = new List<Renderer>(16);
|
|
|
|
void Awake() { Apply(gameObject); }
|
|
|
|
/// <summary>SO 가 지시하는 모드로 맞춘다.</summary>
|
|
public static void Apply(GameObject root)
|
|
{
|
|
var cfg = WLCharacterLookSettings.Instance;
|
|
if (cfg == null || root == null) return;
|
|
ApplyMode(root, WLCharacterLookSettings.ActiveMode, cfg);
|
|
}
|
|
|
|
/// <summary>모드를 직접 지정해 맞춘다(캡처·프로브·A/B 용).</summary>
|
|
public static void ApplyMode(GameObject root, int mode, WLCharacterLookSettings cfg)
|
|
{
|
|
if (root == null) return;
|
|
if (cfg == null) cfg = WLCharacterLookSettings.Instance;
|
|
if (cfg == null || cfg.originals == null || cfg.originals.Length == 0) return;
|
|
|
|
Material[] target = cfg.SetForMode(mode);
|
|
if (target == null) return;
|
|
|
|
int n = cfg.originals.Length;
|
|
int renderers = 0, slots = 0;
|
|
|
|
s_buf.Clear();
|
|
root.GetComponentsInChildren<Renderer>(true, s_buf);
|
|
for (int ri = 0; ri < s_buf.Count; ri++)
|
|
{
|
|
var r = s_buf[ri];
|
|
if (r == null) continue;
|
|
var mats = r.sharedMaterials;
|
|
if (mats == null || mats.Length == 0) continue;
|
|
|
|
bool changed = false;
|
|
for (int si = 0; si < mats.Length; si++)
|
|
{
|
|
int idx = IndexOf(cfg, mats[si], n);
|
|
if (idx < 0) continue;
|
|
var want = target[idx];
|
|
if (want == null || mats[si] == want) continue;
|
|
mats[si] = want;
|
|
changed = true;
|
|
slots++;
|
|
}
|
|
if (changed) { r.sharedMaterials = mats; renderers++; }
|
|
}
|
|
|
|
AppliedRenderers = renderers; AppliedSlots = slots; LastMode = mode;
|
|
LastLog = "mode " + mode + " · 렌더러 " + renderers + " · 슬롯 " + slots;
|
|
if (cfg.verboseLog != 0) Debug.Log("[WL814s CharacterLook] " + LastLog);
|
|
}
|
|
|
|
/// <summary>머티리얼이 4개 배열 중 어디의 몇 번인지(없으면 -1).</summary>
|
|
static int IndexOf(WLCharacterLookSettings c, Material m, int n)
|
|
{
|
|
if (m == null) return -1;
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
if (Same(c.originals, i, m)) return i;
|
|
if (Same(c.mode1, i, m)) return i;
|
|
if (Same(c.mode2, i, m)) return i;
|
|
if (Same(c.mode3, i, m)) return i;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static bool Same(Material[] a, int i, Material m)
|
|
{
|
|
return a != null && i < a.Length && a[i] != null && a[i] == m;
|
|
}
|
|
}
|
|
}
|