109 lines
5.9 KiB
C#
109 lines
5.9 KiB
C#
// ─────────────────────────────────────────────────────────────────────────────
|
|
// WLNullMaterialSettings.cs — 빈 머티리얼 슬롯 가드(D-40 마젠타) 값의 단일 출처(SOT · C45)
|
|
//
|
|
// PD 지시 #813 · 발주서 WL-813m3 §1-4 · 근거 = Q9 `qa/W2-9_재채점_v7.md` §6
|
|
// 실측: 런타임 렌더러 스캔 3회 전부 `errorShader=0 · nullShader=0` · **`nullMaterial` 4 → 8 → 52**
|
|
// (이펙트가 많이 재생될수록 는다) · 경로 5종 전부 `InGameInfo/Effects/**` 아래 · 전부 `slot=0` 이 null.
|
|
// 머티리얼 없는 렌더러를 Unity 는 **마젠타로 그린다** → 화면 1/4 크기 마젠타 사각형 · 결과창 위 마젠타 다각형.
|
|
//
|
|
// 에셋 경로(고정): Assets/WL/Combat/Settings/Resources/WL/WLNullMaterialSettings.asset
|
|
// C8 롤백: 에셋이 없거나 enabled = false → 스윕 0 · 오브젝트 0 · 코드 무수정 100 % 원본.
|
|
//
|
|
// 🔴 원본 프리팹은 고치지 않는다(발주서 금지). 이 가드는 **런타임에서 그 렌더러만 끈다** = 임시 봉합이고,
|
|
// 근본 수리는 아트/이펙트 발주(완료보고 「아트 수정 목록」)다.
|
|
// 🔴 어셈블리 주의: Assets/WL/Combat/ 에 .asmdef 를 만들지 말 것.
|
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
using UnityEngine;
|
|
|
|
namespace WL.Combat.Reaction
|
|
{
|
|
/// <summary>빈 머티리얼 슬롯을 만났을 때 무엇을 끄나.</summary>
|
|
public enum NullMaterialAction
|
|
{
|
|
/// <summary>Renderer.enabled = false (최소 침습 · 기본).</summary>
|
|
DisableRenderer = 0,
|
|
/// <summary>렌더러가 붙은 GameObject 를 비활성(자식까지 사라진다).</summary>
|
|
DeactivateObject = 1,
|
|
/// <summary>아무것도 하지 않는다(계측만 · A/B 비교용).</summary>
|
|
MeasureOnly = 2
|
|
}
|
|
|
|
[CreateAssetMenu(fileName = "WLNullMaterialSettings", menuName = "WL/Null Material Guard Settings", order = 326)]
|
|
public sealed class WLNullMaterialSettings : ScriptableObject
|
|
{
|
|
public const string ResourcesPath = "WL/WLNullMaterialSettings";
|
|
|
|
static WLNullMaterialSettings s_cached;
|
|
static bool s_lookupDone;
|
|
|
|
/// <summary>설정 에셋(1회 로드 후 캐시). 없으면 null.</summary>
|
|
public static WLNullMaterialSettings Instance
|
|
{
|
|
get
|
|
{
|
|
if (!s_lookupDone) { s_cached = Resources.Load<WLNullMaterialSettings>(ResourcesPath); s_lookupDone = true; }
|
|
return s_cached;
|
|
}
|
|
}
|
|
|
|
/// <summary>QA·A/B 전용 런타임 스위치. 0 = 에셋의 enabled · 1 = 강제 on · -1 = 강제 off.</summary>
|
|
public static int RuntimeOverride;
|
|
|
|
/// <summary>가드가 살아 있는가. false 면 스윕도 러너도 없다(C8).</summary>
|
|
public static bool Enabled
|
|
{
|
|
get
|
|
{
|
|
var i = Instance;
|
|
if (i == null || RuntimeOverride < 0) return false;
|
|
return RuntimeOverride > 0 || i.enabled;
|
|
}
|
|
}
|
|
|
|
/// <summary>테스트용: 캐시를 비운다.</summary>
|
|
public static void ClearCache() { s_cached = null; s_lookupDone = false; }
|
|
|
|
[Header("전체 스위치")]
|
|
[Tooltip("끄면 스윕도 러너도 만들지 않는다 = 원본 100 %(마젠타 그대로). C8 롤백 1순위.")]
|
|
public bool enabled = true;
|
|
|
|
[Tooltip("검사·조치 결정을 Console 에 남긴다(오브젝트당 1줄 · 기본 off).")]
|
|
public bool verboseLog = false;
|
|
|
|
[Header("조치")]
|
|
[Tooltip("빈 머티리얼 슬롯을 가진 렌더러에 무엇을 하나. DisableRenderer = Renderer.enabled 만 내린다(기본).")]
|
|
public NullMaterialAction action = NullMaterialAction.DisableRenderer;
|
|
|
|
[Tooltip("머티리얼 슬롯이 0개인 렌더러도 결함으로 본다(Q9 실측은 slot=0 이 null 인 경우다 · 기본 off).")]
|
|
public bool treatEmptyArrayAsNull = false;
|
|
|
|
[Header("스윕")]
|
|
[Tooltip("루트를 훑는 주기(초 · unscaled). 새로 생긴 자식만 본다(인스턴스 ID 캐시). 0 이면 매 프레임.")]
|
|
public float sweepIntervalSeconds = 0.5f;
|
|
|
|
[Tooltip("한 번의 스윕에서 새로 검사할 오브젝트 상한(프레임 스파이크 방지 · 남으면 다음 스윕).")]
|
|
public int maxInspectPerSweep = 24;
|
|
|
|
[Tooltip("검사 완료 인스턴스 ID 캐시 상한. 넘으면 비운다(풀 재사용 때 재검사 = 안전 · 비용 미미).")]
|
|
public int inspectCacheMax = 4096;
|
|
|
|
[Header("스윕 루트 (Q9 §6 실측 = 5종 전부 InGameInfo/Effects 아래)")]
|
|
[Tooltip("원본 이펙트 풀 `InGameInfo.tf_Effects` 를 훑는다 — 🔴 D-40 의 5종이 전부 여기다. 끄면 D-40 은 안 잡힌다.")]
|
|
public bool sweepIngameEffects = true;
|
|
|
|
[Tooltip("원본 오브젝트 풀 `InGameInfo.tf_Objs` 도 훑는다(드랍·813f 등급 빔이 드랍에 붙는다).")]
|
|
public bool sweepIngameObjs = true;
|
|
|
|
[Tooltip("811i SkillSpectacle 의 Live/Pool 루트를 훑는다(러너가 이미 있을 때만 · 새로 만들지 않는다).")]
|
|
public bool sweepSkillSpectacle = true;
|
|
|
|
[Tooltip("메인 PC 하위를 훑는다(813k 레벨업 폭발이 PC 에 붙고 · 811gh 잔상도 PC 근처에 생긴다).")]
|
|
public bool sweepMainPc = true;
|
|
|
|
[Header("증거 수집")]
|
|
[Tooltip("결함 경로를 문자열로 몇 개까지 보관하나(프로브·보고서용 · 넘으면 카운터만 는다).")]
|
|
public int pathSampleMax = 16;
|
|
}
|
|
}
|