[WL-813s] 엘리트 몹: 존별 배치 · 마커 · 드랍 (#813)

MonsterAppear.json 에 엘리트 스포너 새 행 4개(813021~813024) 추가 — 기존 52행 바이트 무변경
(813u 가 같은 파일의 존 행을 고치므로 「기존 행 값 수정 0」 · 단일 라인 JSON 이라 rebase 에서
전체 충돌 1회 → main(813u) 값을 기준으로 새 행만 재부착). 존1~4 에 Elite 1종씩 ·
동시 1마리 · 리젠 25 s.

🔴 HP 는 발주서 제안값(120~180 · Q3 보스 단일표적 DPS 15/s 기준)이 아니라 **470/540/610/680**
이다. 발주 시점 뒤에 813u 가 존 잡몹 HP 를 300/450/600/800 → 190/270/350/430 으로 내려서,
120~180 이면 엘리트가 같은 존 잡몹보다 약해진다. 813u 실측 존 총 DPS 171.8 HP/s 를
기준서 §E 3-2 규격(1발 명중 ≥3마리)으로 나눈 단일 표적 57.3 HP/s 기준 → 8.2/9.4/10.6/11.9 s
= 기준서 「엘리트 8~12 s」. 잡몹 대비 2.47/2.00/1.74/1.58배. ATK 는 813u 존 값과 동률
(6/8/10/12 · Q4-a D-1 사망 이슈 · ATK 밸런스는 813u 소유).

WL_Nature.prefab: maplv/e1~e4 스포너 노드 4기 신규(존 스포너와 같은 좌표 · MobGenRange 6 ·
Lv 라벨 렌더러 끔) — 기존 노드·좌표 무변경(+924 / −0).

EliteMarker.cs(신규 · 정적 · 러너 0 · GC 0): Spawned(isElite) → localScale = 테이블 기본
스케일 × 1.3(멱등 · NavMesh 반경 무변경) + 상시 색 등록, Killed(Elite) → 색 해제 + 처치
시간(TTK) 로그. 아웃라인은 QuickOutline 이 프로젝트에 없고 MK Toon 의 _RimColor 가
_MK_RIM_* shader_feature 게이팅이라 MPB 로 못 켠다 → 발주서 대체안대로 MPB 상시 색
(_EmissionColor 주 · _AlbedoColor 보조 · 새 셰이더/머티리얼 0). MobHitFlash 가 렌더러 MPB 의
단일 소유자라 합성 지점(SetEliteTint/ClearEliteTint)만 그 파일에 더했다(우선순위 = 점멸 > 상시).

킬캠(811d)·임팩트 티어(811gh)는 이미 Elite 분기가 열려 있어 코드 0(killCamOnElite=1 ·
bossKillIncludesElite=1 실측). 드랍은 WLLootSettings.asset 값만 eliteBurst 1~2 → 2~3.

검증: 게이트 PASS(oneshot · error CS 0줄) · 프로브 AgentScripts/WL813s_Probe.cs
(새 행 4/4 · 스포너 노드 4/4 · 크기 2.30→2.99 멱등 · 상시 색 O · 일반 몹 미적용 ·
킬캠 Elite 1 / 일반 0 · 드랍 버스트 2~3 · 0건 0회 · GC 0 B · C8 PASS · 원본 문자열 0).
Play 실측(인게임 화면)은 미확인 — 로그인 금지라 병합 후 QA. xlsm 동기화 안 함(백로그).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
깃 관리자 2026-09-09 09:25:41 +09:00
parent 3adc1bcca8
commit e8c32880cd
11 changed files with 1931 additions and 5 deletions

View File

@ -0,0 +1,521 @@
// PD 지시 #813 · 발주서 WL-813s — 엘리트 몹(존별 배치 · 크기 1.3× · 상시 색 · HP 8~12 s · 킬캠 · 드랍) 검증 프로브
// (에디트 모드 전용 · Play 0 · 로그인 0 · 에셋 무수정)
//
// 실행 (CLAUDE.md §1: using 금지 · 네임스페이스 풀어 쓰기)
// unity command run_script --file AgentScripts/WL813s_Probe.cs --entry WL813s_Probe.Edit --timeout 900
//
// 무엇을 재는가
// A. 데이터 — MonsterAppear.json 새 행 813021~813024 인식 · 몹 ID 가 MonsterList 의 Elite 인지 ·
// 실 HP(f_BaseHPRate × n_MonsterHP) → Q3 실측 DPS 15/s 기준 처치 시간 · 몹/투사체 프리팹 실존 ·
// WL_Nature.prefab 의 스포너 전수(존 5 + 엘리트 4 + 레거시 14) 연결 · text_lv null 0
// B. 마커 — 진짜 엘리트 프리팹으로 가짜 Spawned(Elite) → 스케일 1.3× · MPB 색 부착 · **멱등**(2회) ·
// 가짜 Killed(Elite) → 색 뗌 · 처치 시간(TTK) 측정 · RestoreAll 로 원본 스케일 복귀
// C. 연계 — 킬캠(811d): CombatCameraDirector 를 리플렉션으로 구독시키고 진짜 Killed 를 올려 Elite/일반 대조 ·
// 드랍(813f): LootBurst.BurstCount(SO, Elite) 실행 · 임팩트 티어(811gh): bossKillIncludesElite 실값
// D. GC — Spawned/Killed 각 100회의 GC.GetAllocatedBytesForCurrentThread() 증가분(0 B 목표)
// E. C8 — WLEliteSettings.RuntimeDisabled = true(= 에셋 enabled 0 과 같은 Enabled 게이트)
// → 크기 원본 · 색 0 · MPB 잔류 0
// F. 원본 — Assets/Script/** · Core · UI 에 813s 문자열 0 · MobHitFlash 합성 배선 확인
//
// 에디트 모드 주의
// · [RuntimeInitializeOnLoadMethod] 는 Play 에서만 돈다 → EliteMarker.Probe* 헬퍼로 핸들러를 직접 부른다.
// · Time.unscaledTime 은 한 호출 안에서 멈춰 있다 → TTK 는 ImpactRunner.ForceTick 으로 시뮬 시계를 민다(811gh 방식).
// · 프로브가 만드는 오브젝트는 전부 HideAndDontSave + DestroyImmediate. 어떤 에셋도 쓰지 않는다.
public static class WL813s_Probe
{
const string kOut = "AgentScripts/staging/WL813s/EDIT_PROBE.txt";
const string kAppear = "Assets/ResWork/Table/Export/MonsterAppear.json";
const string kList = "Assets/ResWork/Table/Export/MonsterList.json";
const string kMap = "Assets/Res_Addr/Map/WL_Nature.prefab";
const string kFlash = "Assets/WL/Combat/Reaction/MobHitFlash.cs";
const float kDps = 15f; // Q3 실측(보스 9000 → 6247 / 3분) · 813u 발주서 근거
static readonly int[] kEliteSpawners = new int[] { 813021, 813022, 813023, 813024 };
static readonly int[] kZoneSpawners = new int[] { 813001, 813002, 813003, 813004 };
static System.Collections.Generic.List<string> s_log = new System.Collections.Generic.List<string>();
static bool s_hooked;
static void OnLog(string cond, string stack, UnityEngine.LogType t)
{
if (t == UnityEngine.LogType.Error || t == UnityEngine.LogType.Exception || t == UnityEngine.LogType.Assert)
s_log.Add(t + " | " + cond);
}
static void Hook() { if (!s_hooked) { UnityEngine.Application.logMessageReceived += OnLog; s_hooked = true; } }
static void Unhook() { if (s_hooked) { UnityEngine.Application.logMessageReceived -= OnLog; s_hooked = false; } }
static UnityEngine.GameObject s_root, s_eliteGo, s_normalGo;
static MobActor s_elite, s_normal;
static float s_eliteBaseScale = -1f;
public static string Edit()
{
var sb = new System.Text.StringBuilder();
sb.Append("# WL-813s 프로브 (에디트 모드 · Play 0 · 로그인 0)\n");
sb.Append("unity=").Append(UnityEngine.Application.unityVersion)
.Append(" isPlaying=").Append(UnityEngine.Application.isPlaying)
.Append(" utc=").Append(System.DateTime.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")).Append("\n\n");
Hook(); s_log.Clear();
try
{
Section0(sb);
SectionA(sb);
BuildFakes(sb);
SectionB(sb);
SectionC(sb);
SectionD(sb);
SectionE(sb);
SectionF(sb);
}
catch (System.Exception ex) { sb.Append("\n🔴 예외: ").Append(ex.ToString()).Append("\n"); }
finally { Cleanup(sb); Unhook(); }
sb.Append("\n## 프로브 중 Error/Exception: ").Append(s_log.Count).Append("\n");
for (int i = 0; i < s_log.Count && i < 30; i++) sb.Append(" ").Append(s_log[i]).Append("\n");
var dir = System.IO.Path.GetDirectoryName(kOut);
if (!System.IO.Directory.Exists(dir)) System.IO.Directory.CreateDirectory(dir);
System.IO.File.WriteAllText(kOut, sb.ToString(), new System.Text.UTF8Encoding(false));
return sb.ToString();
}
// ═══════════════════════════════════════════════ 0. 환경 · SO 실값
static void Section0(System.Text.StringBuilder sb)
{
sb.Append("## 0. SO 실값 (전부 에셋에서 읽은 값 · 코드 상수 0)\n");
var el = WL.Combat.Reaction.WLEliteSettings.Instance;
sb.Append("WLEliteSettings: ").Append(el == null ? "🔴 에셋 없음" : "로드 O").Append("\n");
if (el != null)
sb.Append(" enabled=").Append(el.enabled)
.Append(" scaleEnabled=").Append(el.scaleEnabled)
.Append(" scaleMultiplier=").Append(el.scaleMultiplier.ToString("F2"))
.Append(" scaleMaxAbsolute=").Append(el.scaleMaxAbsolute.ToString("F1"))
.Append(" tintEnabled=").Append(el.tintEnabled)
.Append("\n tintAlbedo=").Append(el.tintAlbedo.ToString("F2"))
.Append(" tintEmission=").Append(el.tintEmission.ToString("F2"))
.Append(" 목표 처치 ").Append(el.killTimeTargetMin.ToString("F0")).Append("~").Append(el.killTimeTargetMax.ToString("F0")).Append(" s\n");
var loot = WL.Combat.Loot.WLLootSettings.Instance;
sb.Append("WLLootSettings: ").Append(loot == null ? "🔴 없음" : "burstEnabled=" + loot.burstEnabled
+ " elite=" + loot.eliteBurstMin + "~" + loot.eliteBurstMax
+ " normal=" + loot.normalBurstCount + " boss=" + loot.bossBurstMin + "~" + loot.bossBurstMax
+ " burstRollsBag=" + loot.burstRollsBag + " burstGoldShare=" + loot.burstGoldShare.ToString("F2")).Append("\n");
var cam = WL.CombatCamera.WLCombatCameraSettings.Instance;
sb.Append("WLCombatCameraSettings: ").Append(cam == null ? "🔴 없음" : "killCamEnabled=" + cam.killCamEnabled
+ " onElite=" + cam.killCamOnElite + " onBoss=" + cam.killCamOnBoss + " onNormal=" + cam.killCamOnNormal
+ " directHitOnly=" + cam.killCamDirectHitOnly + " maxPerRun=" + cam.killCamMaxPerRun).Append("\n");
var tier = WL.Combat.Reaction.WLImpactTierSettings.Instance;
sb.Append("WLImpactTierSettings: ").Append(tier == null ? "🔴 없음" : "tierEnabled=" + tier.tierEnabled
+ " bossKillIncludesElite=" + tier.bossKillIncludesElite).Append("\n");
var blink = WL.Combat.Reaction.WLHitBlinkSettings.Instance;
sb.Append("WLHitBlinkSettings: ").Append(blink == null ? "🔴 없음"
: "colorProperties=[" + string.Join(",", blink.colorProperties) + "] emissionProperties=["
+ string.Join(",", blink.emissionProperties) + "] dissolveElite hdr=" + blink.dissolveEdgeHdrElite).Append("\n");
sb.Append("코어 CombatEvents.Enabled=").Append(WL.Combat.Core.CombatEvents.Enabled).Append("\n\n");
}
// ═══════════════════════════════════════════════ A. 데이터
static void SectionA(System.Text.StringBuilder sb)
{
sb.Append("## A. 데이터 — MonsterAppear 새 행 · MonsterList 대조 · 자산 실존 · 스포너 연결\n");
string appear = System.IO.File.ReadAllText(kAppear);
string list = System.IO.File.ReadAllText(kList);
sb.Append("| 스포너 | Lv | ATK | HP(행) | 몹ID | e_MonsterType | f_BaseHPRate | 실 HP | DPS15 처치 s | f_DefaultScale | ×1.3 | 리젠 s | 동시 | 몹 프리팹 | 투사체 |\n");
sb.Append("|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|\n");
int ok = 0;
var el = WL.Combat.Reaction.WLEliteSettings.Instance;
float mul = el != null ? el.scaleMultiplier : 1.3f;
for (int i = 0; i < kEliteSpawners.Length; i++)
{
string row = Row(appear, "n_SpawnerID", kEliteSpawners[i].ToString());
if (row == null) { sb.Append("| ").Append(kEliteSpawners[i]).Append(" | 🔴 행 없음 |\n"); continue; }
string mobId = F(row, "s_AppearMonster");
string hp = F(row, "n_MonsterHP");
string mrow = Row(list, "n_MonsterID", mobId);
string type = mrow != null ? F(mrow, "e_MonsterType") : "?";
float hpRate = mrow != null ? Num(F(mrow, "f_BaseHPRate")) : 0f;
float scale = mrow != null ? Num(F(mrow, "f_DefaultScale")) : 0f;
string prefab = mrow != null ? F(mrow, "s_MonsterPrefab") : "";
string proj = mrow != null ? F(mrow, "s_Porjectile1") : "";
float realHp = hpRate * Num(hp);
bool mobOk = Exists("Assets/Res_Addr/Mobs/" + prefab + ".prefab");
bool projOk = Exists("Assets/Res_Addr/Projectile/" + proj + ".prefab");
if (type == "Elite" && mobOk && projOk) ok++;
sb.Append("| ").Append(kEliteSpawners[i]).Append(" | ").Append(F(row, "n_AppearMonsterLv"))
.Append(" | ").Append(F(row, "n_MonsterATK")).Append(" | ").Append(hp)
.Append(" | ").Append(mobId).Append(" | ").Append(type)
.Append(" | ").Append(hpRate.ToString("F0")).Append(" | ").Append(realHp.ToString("F0"))
.Append(" | ").Append((realHp / kDps).ToString("F1"))
.Append(" | ").Append(scale.ToString("F1")).Append(" | ").Append((scale * mul).ToString("F2"))
.Append(" | ").Append(F(row, "f_SpawnerDelay")).Append(" | ").Append(F(row, "n_MaxMonsterCount"))
.Append(" | ").Append(prefab).Append(mobOk ? " O" : " 🔴").Append(" | ").Append(proj).Append(projOk ? " O" : " 🔴")
.Append(" |\n");
}
sb.Append("새 행 정상 = ").Append(ok).Append(" / ").Append(kEliteSpawners.Length).Append("\n");
// 기존 존 행 무변경 확인(813u 와의 충돌 방지 규칙)
sb.Append("기존 존 행(813001~813005 · 813010) 값 = ");
for (int i = 0; i < kZoneSpawners.Length; i++)
{
string r = Row(appear, "n_SpawnerID", kZoneSpawners[i].ToString());
sb.Append(kZoneSpawners[i]).Append(":HP").Append(F(r, "n_MonsterHP")).Append("/몹").Append(F(r, "s_AppearMonster")).Append(" ");
}
sb.Append("\n");
// WL_Nature 스포너 전수
var map = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>(kMap);
if (map == null) sb.Append("🔴 ").Append(kMap).Append(" 로드 실패\n");
else
{
var mgrs = map.GetComponentsInChildren<MobControlMgr>(true);
int nullText = 0, eliteNodes = 0;
sb.Append("WL_Nature 스포너 ").Append(mgrs.Length).Append("개 — ");
for (int i = 0; i < mgrs.Length; i++)
{
if (mgrs[i].text_lv == null) nullText++;
for (int j = 0; j < kEliteSpawners.Length; j++) if (mgrs[i].SpawnerID == kEliteSpawners[j]) eliteNodes++;
}
sb.Append("엘리트 노드 ").Append(eliteNodes).Append("/4 · text_lv null ").Append(nullText).Append("\n");
for (int i = 0; i < mgrs.Length; i++)
{
bool isElite = false;
for (int j = 0; j < kEliteSpawners.Length; j++) if (mgrs[i].SpawnerID == kEliteSpawners[j]) isElite = true;
if (!isElite) continue;
var t = mgrs[i].transform;
var rend = mgrs[i].GetComponentInChildren<UnityEngine.MeshRenderer>(true);
sb.Append(" ").Append(Path(t)).Append(" id=").Append(mgrs[i].SpawnerID)
.Append(" pos=").Append(t.position.ToString("F1")).Append(" range=").Append(mgrs[i].MobGenRange.ToString("F0"))
.Append(" lv라벨렌더러=").Append(rend == null ? "없음" : (rend.enabled ? "켬" : "끔")).Append("\n");
}
// 같은 좌표의 존 스포너와 대조
for (int j = 0; j < kZoneSpawners.Length; j++)
{
UnityEngine.Vector3 zp = UnityEngine.Vector3.zero, ep = UnityEngine.Vector3.zero;
bool hz = false, he = false;
for (int i = 0; i < mgrs.Length; i++)
{
if (mgrs[i].SpawnerID == kZoneSpawners[j]) { zp = mgrs[i].transform.position; hz = true; }
if (mgrs[i].SpawnerID == kEliteSpawners[j]) { ep = mgrs[i].transform.position; he = true; }
}
if (hz && he)
sb.Append(" 존 ").Append(kZoneSpawners[j]).Append(" ↔ 엘리트 ").Append(kEliteSpawners[j])
.Append(" 거리 ").Append(UnityEngine.Vector3.Distance(zp, ep).ToString("F2")).Append(" m\n");
}
}
sb.Append("\n");
}
// ═══════════════════════════════════════════════ 준비
static void BuildFakes(System.Text.StringBuilder sb)
{
sb.Append("## 준비: 진짜 엘리트 프리팹으로 가짜 액터\n");
s_root = new UnityEngine.GameObject("[813s] root");
s_root.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
s_root.SetActive(false);
string appear = System.IO.File.ReadAllText(kAppear);
string list = System.IO.File.ReadAllText(kList);
string mobId = F(Row(appear, "n_SpawnerID", "813021"), "s_AppearMonster");
string mrow = Row(list, "n_MonsterID", mobId);
string prefabName = mrow != null ? F(mrow, "s_MonsterPrefab") : "Elite/Aspethis_D";
float defScale = mrow != null ? Num(F(mrow, "f_DefaultScale")) : 1f;
var prefab = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>("Assets/Res_Addr/Mobs/" + prefabName + ".prefab");
if (prefab == null) { sb.Append("🔴 엘리트 프리팹 로드 실패 ").Append(prefabName).Append("\n\n"); return; }
s_eliteGo = UnityEngine.Object.Instantiate(prefab, s_root.transform);
s_eliteGo.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
s_eliteGo.name = "[813s] elite " + prefabName;
s_elite = s_eliteGo.GetComponent<MobActor>();
if (s_elite == null) s_elite = s_eliteGo.AddComponent<MobActor>();
s_elite.m_Role = eRole.Mob;
s_elite.m_SubRole = eSubRol.Elite; // 원본 MobActor.Set(:82) 이 e_MonsterType 으로 넣는 값
s_elite.transform.localScale = defScale * UnityEngine.Vector3.one; // 원본 MobActor.Set(:87) 과 같은 대입
s_eliteBaseScale = defScale;
var normalPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.GameObject>("Assets/Res_Addr/Mobs/Mob/Batty_A.prefab");
if (normalPrefab != null)
{
s_normalGo = UnityEngine.Object.Instantiate(normalPrefab, s_root.transform);
s_normalGo.hideFlags = UnityEngine.HideFlags.HideAndDontSave;
s_normalGo.name = "[813s] normal Batty_A";
s_normal = s_normalGo.GetComponent<MobActor>();
if (s_normal != null) { s_normal.m_Role = eRole.Mob; s_normal.m_SubRole = eSubRol.None; }
}
var rends = s_eliteGo.GetComponentsInChildren<UnityEngine.Renderer>(true);
sb.Append("엘리트 = ").Append(prefabName).Append(" · Renderer ").Append(rends.Length)
.Append(" · 기본 스케일 ").Append(defScale.ToString("F2")).Append(" · IsSubRole(Elite)=").Append(s_elite.IsSubRole(eSubRol.Elite)).Append("\n");
if (rends.Length > 0 && rends[0].sharedMaterial != null && rends[0].sharedMaterial.shader != null)
{
var sh = rends[0].sharedMaterial.shader;
sb.Append("셰이더[0] = ").Append(sh.name)
.Append(" · _AlbedoColor=").Append(sh.FindPropertyIndex("_AlbedoColor") >= 0)
.Append(" · _EmissionColor=").Append(sh.FindPropertyIndex("_EmissionColor") >= 0)
.Append(" · _RimColor=").Append(sh.FindPropertyIndex("_RimColor") >= 0)
.Append(" (🔴 _RimColor 는 _MK_RIM_* shader_feature 게이팅이라 MPB 로 못 켠다 → 쓰지 않는다)\n");
}
sb.Append("\n");
}
// ═══════════════════════════════════════════════ B. 마커
static void SectionB(System.Text.StringBuilder sb)
{
sb.Append("## B. 마커 — 크기 1.3× · 상시 색 · 멱등 · 처치 시간\n");
if (s_elite == null) { sb.Append("🔴 엘리트 액터 없음 — 건너뜀\n\n"); return; }
WL.Combat.Reaction.WLEliteSettings.RuntimeDisabled = false;
WL.Combat.Reaction.EliteMarker.ClearAll();
WL.Combat.Reaction.EliteMarker.ResetDiagnostics();
WL.Combat.Reaction.MobHitFlash.ResetDiagnostics();
WL.Combat.Reaction.ImpactRunner.ResetForceClock();
var el = WL.Combat.Reaction.WLEliteSettings.Instance;
float before = s_elite.transform.localScale.x;
WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_elite);
float after1 = s_elite.transform.localScale.x;
bool tinted1 = WL.Combat.Reaction.MobHitFlash.HasEliteTint(s_elite);
bool block1 = WL.Combat.Reaction.MobHitFlash.HasAnyBlock(s_elite);
WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_elite); // 멱등 확인(풀 재사용 재등장)
WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_elite);
float after3 = s_elite.transform.localScale.x;
sb.Append("B-1 크기: 기본 ").Append(before.ToString("F3"))
.Append(" → 1회 ").Append(after1.ToString("F3"))
.Append(" (기대 ").Append((before * (el != null ? el.scaleMultiplier : 1.3f)).ToString("F3")).Append(")")
.Append(" → 3회 ").Append(after3.ToString("F3"))
.Append(" · 멱등 ").Append(UnityEngine.Mathf.Abs(after1 - after3) < 0.0005f ? "PASS" : "🔴 FAIL")
.Append(" · EliteMarker.BaseScaleOf=").Append(WL.Combat.Reaction.EliteMarker.BaseScaleOf(s_elite).ToString("F3")).Append("\n");
sb.Append("B-2 상시 색: HasEliteTint=").Append(tinted1)
.Append(" · MPB 부착=").Append(block1)
.Append(" · TintApplied=").Append(WL.Combat.Reaction.EliteMarker.TintApplied)
.Append(" TintSkipped=").Append(WL.Combat.Reaction.EliteMarker.TintSkipped)
.Append(" · MobHitFlash.StatesCreated=").Append(WL.Combat.Reaction.MobHitFlash.StatesCreated).Append("\n");
// 일반 몹은 마커 대상이 아니다
if (s_normal != null)
{
float nb = s_normal.transform.localScale.x;
WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_normal);
sb.Append("B-3 일반 몹(Batty_A): 스케일 ").Append(nb.ToString("F3")).Append(" → ").Append(s_normal.transform.localScale.x.ToString("F3"))
.Append(" · 색=").Append(WL.Combat.Reaction.MobHitFlash.HasEliteTint(s_normal))
.Append(" · SkippedNotElite=").Append(WL.Combat.Reaction.EliteMarker.SkippedNotElite)
.Append(UnityEngine.Mathf.Abs(nb - s_normal.transform.localScale.x) < 0.0005f ? " → PASS" : " → 🔴 FAIL").Append("\n");
}
// 처치 시간 — 시뮬 시계를 10 s 민다(811gh ImpactRunner.ForceTick)
for (int i = 0; i < 20; i++) WL.Combat.Reaction.ImpactRunner.ForceTick(0.5f);
WL.Combat.Reaction.EliteMarker.ProbeKilled(s_elite, eSubRol.Elite);
sb.Append("B-4 처치: TTK=").Append(WL.Combat.Reaction.EliteMarker.LastKillTime.ToString("F2")).Append(" s (시뮬 10.00 s 주입)")
.Append(" · 색 뗌=").Append(!WL.Combat.Reaction.MobHitFlash.HasEliteTint(s_elite))
.Append(" · 크기 유지=").Append(s_elite.transform.localScale.x.ToString("F3"))
.Append(" · KillCount=").Append(WL.Combat.Reaction.EliteMarker.KillCount).Append("\n");
WL.Combat.Reaction.ImpactRunner.ResetForceClock();
WL.Combat.Reaction.EliteMarker.RestoreAll();
sb.Append("B-5 RestoreAll: 스케일 ").Append(s_elite.transform.localScale.x.ToString("F3"))
.Append(" (기대 ").Append(s_eliteBaseScale.ToString("F3")).Append(")")
.Append(" · MPB 잔류=").Append(WL.Combat.Reaction.MobHitFlash.HasAnyBlock(s_elite))
.Append(UnityEngine.Mathf.Abs(s_elite.transform.localScale.x - s_eliteBaseScale) < 0.0005f ? " → PASS" : " → 🔴 FAIL").Append("\n\n");
}
// ═══════════════════════════════════════════════ C. 연계(킬캠 · 드랍 · 티어)
static void SectionC(System.Text.StringBuilder sb)
{
sb.Append("## C. 연계 — 킬캠(811d) · 드랍(813f) · 임팩트 티어(811gh)\n");
// C-1 드랍 버스트 수 — 실제 함수 실행
var loot = WL.Combat.Loot.WLLootSettings.Instance;
if (loot == null) sb.Append("C-1 🔴 WLLootSettings 없음\n");
else
{
int min = int.MaxValue, max = int.MinValue, zero = 0;
for (int i = 0; i < 200; i++)
{
int c = WL.Combat.Loot.LootBurst.BurstCount(loot, eSubRol.Elite);
if (c < min) min = c; if (c > max) max = c; if (c <= 0) zero++;
}
int nrm = WL.Combat.Loot.LootBurst.BurstCount(loot, eSubRol.None);
int bos = WL.Combat.Loot.LootBurst.BurstCount(loot, eSubRol.Boss);
sb.Append("C-1 LootBurst.BurstCount(Elite) 200회 → ").Append(min).Append("~").Append(max)
.Append(" · 0건 ").Append(zero).Append("회 (0 이면 「드랍 100 %」 성립)")
.Append(" · 일반=").Append(nrm).Append(" 보스=").Append(bos).Append("\n");
sb.Append(" 버스트 1건은 백(").Append(loot.burstRollsBag ? "8130001 추첨" : "추첨 안 함")
.Append(") → 빈손이면 골드(비중 ").Append(loot.burstGoldShare.ToString("F2")).Append(")로 대체 = 무조건 무언가 떨어진다\n");
}
// C-2 임팩트 티어 — bossKillIncludesElite 실값(소스 ImpactTier.cs:130 의 유일한 분기)
var tier = WL.Combat.Reaction.WLImpactTierSettings.Instance;
sb.Append("C-2 ImpactTier.bossKillIncludesElite = ").Append(tier == null ? "?" : tier.bossKillIncludesElite.ToString())
.Append(" (이 값이 1 이면 Elite 처치가 BossKill 티어 = 히트스톱 ")
.Append(tier != null && tier.hitStopMs != null && tier.hitStopMs.Length > 3 ? tier.hitStopMs[3].ToString("F0") : "?")
.Append(" ms · 셰이크 배수 ")
.Append(tier != null && tier.shakeMultiplier != null && tier.shakeMultiplier.Length > 3 ? tier.shakeMultiplier[3].ToString("F2") : "?")
.Append(") · 이번 작업에서 값 변경 없음(이미 1)\n");
// C-3 킬캠 — 리플렉션으로 구독시키고 진짜 Killed 를 올린다
float ts0 = UnityEngine.Time.timeScale;
var camType = typeof(WL.CombatCamera.CombatCameraDirector);
var reg = camType.GetMethod("Register", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static);
if (reg == null || s_elite == null) sb.Append("C-3 🔴 Register/엘리트 없음 — 건너뜀\n");
else
{
WL.Combat.Core.CombatEvents.Killed.Clear();
WL.Combat.Core.CombatEvents.Spawned.Clear();
WL.Combat.Core.CombatEvents.ComboStage.Clear();
reg.Invoke(null, null);
WL.CombatCamera.CombatCameraDirector.ResetDiagnostics();
WL.CombatCamera.CombatCameraDirector.ResetRun();
WL.CombatCamera.CombatCameraDirector.ResetCooldown();
WL.Combat.Core.CombatEvents.RaiseKilled(s_elite);
int eliteCam = WL.CombatCamera.CombatCameraDirector.KillCamCount;
int eliteRole = WL.CombatCamera.CombatCameraDirector.KillCamSkippedRole;
string eliteInfo = WL.CombatCamera.CombatCameraDirector.LastInfo;
var slow = WL.CombatCamera.CombatCameraDirector.LastSlowMoResult;
WL.CombatCamera.CombatCameraDirector.ResetCooldown();
int camBeforeNormal = WL.CombatCamera.CombatCameraDirector.KillCamCount;
if (s_normal != null) WL.Combat.Core.CombatEvents.RaiseKilled(s_normal);
int normalCam = WL.CombatCamera.CombatCameraDirector.KillCamCount - camBeforeNormal;
int normalRole = WL.CombatCamera.CombatCameraDirector.KillCamSkippedRole - eliteRole;
sb.Append("C-3 킬캠: Killed(Elite) → KillCamCount ").Append(eliteCam)
.Append(" · 역할 스킵 ").Append(eliteRole)
.Append(" · 슬로모 ").Append(slow).Append(" · info=\"").Append(eliteInfo).Append("\"\n");
sb.Append(" 대조 Killed(일반 몹) → KillCamCount +").Append(normalCam)
.Append(" · 역할 스킵 +").Append(normalRole).Append(" (killCamOnNormal=0 이라 스킵이 정상)\n");
sb.Append(" 판정: 엘리트 킬캠 조건 ").Append(eliteCam >= 1 ? "열림 PASS" : "🔴 닫힘").Append("\n");
WL.CombatCamera.CombatCameraDirector.ReleaseAll();
WL.Combat.Core.TimeScaleArbiter.ReleaseAll();
WL.Combat.Core.CombatEvents.Killed.Clear();
WL.Combat.Core.CombatEvents.Spawned.Clear();
WL.Combat.Core.CombatEvents.ComboStage.Clear();
}
UnityEngine.Time.timeScale = ts0;
sb.Append(" Time.timeScale ").Append(ts0.ToString("F2")).Append(" → ").Append(UnityEngine.Time.timeScale.ToString("F2")).Append(" (복원)\n\n");
}
// ═══════════════════════════════════════════════ D. GC
static void SectionD(System.Text.StringBuilder sb)
{
sb.Append("## D. GC (0 B 목표)\n");
if (s_elite == null) { sb.Append("🔴 건너뜀\n\n"); return; }
WL.Combat.Reaction.WLEliteSettings.RuntimeDisabled = false;
// 상태·MPB 를 미리 만들어 두고(1회 할당은 풀 크기 상한) 반복분만 잰다
WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_elite);
WL.Combat.Reaction.EliteMarker.ProbeKilled(s_elite, eSubRol.Elite);
long a0 = System.GC.GetAllocatedBytesForCurrentThread();
for (int i = 0; i < 100; i++) WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_elite);
long a1 = System.GC.GetAllocatedBytesForCurrentThread();
for (int i = 0; i < 100; i++) { WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_elite); WL.Combat.Reaction.EliteMarker.ProbeKilled(s_elite, eSubRol.Elite); }
long a2 = System.GC.GetAllocatedBytesForCurrentThread();
sb.Append("Spawned ×100 = ").Append(a1 - a0).Append(" B · Spawned+Killed ×100 = ").Append(a2 - a1).Append(" B\n");
sb.Append("(killTimeLogEnabled=").Append(WL.Combat.Reaction.WLEliteSettings.Instance != null && WL.Combat.Reaction.WLEliteSettings.Instance.killTimeLogEnabled)
.Append(" · 켜져 있으면 Debug.Log 문자열이 잡힌다 = 값이 0 이 아니면 그 로그분)\n\n");
}
// ═══════════════════════════════════════════════ E. C8
static void SectionE(System.Text.StringBuilder sb)
{
sb.Append("## E. C8 — WLEliteSettings 를 끄면 원본 동작 100 %\n");
if (s_elite == null) { sb.Append("🔴 건너뜀\n\n"); return; }
WL.Combat.Reaction.EliteMarker.ClearAll();
s_elite.transform.localScale = s_eliteBaseScale * UnityEngine.Vector3.one;
WL.Combat.Reaction.EliteMarker.ResetDiagnostics();
WL.Combat.Reaction.WLEliteSettings.RuntimeDisabled = true;
sb.Append("Enabled=").Append(WL.Combat.Reaction.WLEliteSettings.Enabled).Append(" (기대 False)\n");
WL.Combat.Reaction.EliteMarker.ProbeSpawned(s_elite);
bool sizeOk = UnityEngine.Mathf.Abs(s_elite.transform.localScale.x - s_eliteBaseScale) < 0.0005f;
bool tintOff = !WL.Combat.Reaction.MobHitFlash.HasEliteTint(s_elite);
bool blockOff = !WL.Combat.Reaction.MobHitFlash.HasAnyBlock(s_elite);
sb.Append("크기 ").Append(s_elite.transform.localScale.x.ToString("F3")).Append(" (원본 ").Append(s_eliteBaseScale.ToString("F3")).Append(")")
.Append(" · 색 ").Append(tintOff ? "0" : "🔴 남음").Append(" · MPB ").Append(blockOff ? "0" : "🔴 남음")
.Append(" · SkippedDisabled=").Append(WL.Combat.Reaction.EliteMarker.SkippedDisabled)
.Append(sizeOk && tintOff && blockOff ? " → PASS" : " → 🔴 FAIL").Append("\n");
WL.Combat.Reaction.WLEliteSettings.RuntimeDisabled = false;
sb.Append("\n");
}
// ═══════════════════════════════════════════════ F. 원본 · 배선
static void SectionF(System.Text.StringBuilder sb)
{
sb.Append("## F. 원본 무수정 · 배선\n");
string[] originals = new string[] {
"Assets/Script/Character/Actor.cs",
"Assets/Script/Character/Mob/MobActor.cs",
"Assets/Script/Mgr/MobControlMgr.cs",
"Assets/WL/Combat/Core/CombatEvents.cs",
"Assets/WL/Combat/Core/WLCombatCoreSettings.cs",
};
for (int i = 0; i < originals.Length; i++)
{
if (!System.IO.File.Exists(originals[i])) { sb.Append(" ").Append(originals[i]).Append(" 🔴 없음\n"); continue; }
string t = System.IO.File.ReadAllText(originals[i]);
sb.Append(" ").Append(originals[i]).Append(" — \"EliteMarker\" ").Append(t.Contains("EliteMarker") ? "🔴 있음" : "0")
.Append(" · \"813s\" ").Append(t.Contains("813s") ? "🔴 있음" : "0").Append("\n");
}
string flash = System.IO.File.Exists(kFlash) ? System.IO.File.ReadAllText(kFlash) : "";
sb.Append(" MobHitFlash 합성 배선 — SetEliteTint ").Append(flash.Contains("SetEliteTint") ? "O" : "🔴")
.Append(" · Apply 안 s.elite ").Append(flash.Contains("if (s.elite)") ? "O" : "🔴")
.Append(" · RestoreAll 포함 ").Append(flash.Contains("!s.tint && !s.elite") ? "O" : "🔴").Append("\n\n");
}
// ═══════════════════════════════════════════════ 정리 · 헬퍼
static void Cleanup(System.Text.StringBuilder sb)
{
WL.Combat.Reaction.WLEliteSettings.RuntimeDisabled = false;
try { WL.Combat.Reaction.EliteMarker.ClearAll(); } catch (System.Exception) { }
try { WL.Combat.Reaction.MobHitFlash.ClearAll(); } catch (System.Exception) { }
try { WL.Combat.Reaction.ImpactRunner.ResetForceClock(); } catch (System.Exception) { }
if (s_root != null) { UnityEngine.Object.DestroyImmediate(s_root); s_root = null; }
s_eliteGo = null; s_normalGo = null; s_elite = null; s_normal = null;
sb.Append("\n## 정리: 임시 오브젝트 파괴 · 상태 비움 완료\n");
}
static bool Exists(string path) { return UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path) != null; }
static string Path(UnityEngine.Transform t)
{
string p = t.name;
while (t.parent != null) { t = t.parent; p = t.name + "/" + p; }
return p;
}
/// <summary>단일 라인 JSON 에서 key == value 인 객체 하나를 문자열로 잘라 온다.</summary>
static string Row(string json, string key, string value)
{
if (json == null || value == null) return null;
string needle = "\"" + key + "\": \"" + value + "\"";
int i = json.IndexOf(needle, System.StringComparison.Ordinal);
if (i < 0) return null;
int s = json.LastIndexOf('{', i);
int e = json.IndexOf('}', i);
return s < 0 || e < 0 ? null : json.Substring(s, e - s + 1);
}
static string F(string row, string key)
{
if (row == null) return "?";
string needle = "\"" + key + "\": \"";
int i = row.IndexOf(needle, System.StringComparison.Ordinal);
if (i < 0) return "?";
i += needle.Length;
int e = row.IndexOf('"', i);
return e < 0 ? "?" : row.Substring(i, e - i);
}
static float Num(string s)
{
float v;
return float.TryParse(s, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out v) ? v : 0f;
}
}

File diff suppressed because one or more lines are too long

View File

@ -1874,6 +1874,10 @@ Transform:
- {fileID: 9148239127049813559}
- {fileID: 4756645399688030805}
- {fileID: 2585914379847131988}
- {fileID: 8130210000000000002}
- {fileID: 8130220000000000002}
- {fileID: 8130230000000000002}
- {fileID: 8130240000000000002}
m_Father: {fileID: 4502284306717827522}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &2416751648744311364
@ -68686,3 +68690,923 @@ MonoBehaviour:
n_MonsterID: 10006
n_SpawnerId: 813010
RegenTime: 60
--- !u!1 &8130210000000000001
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130210000000000002}
- component: {fileID: 8130210000000000003}
m_Layer: 3
m_Name: e1
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 2147483647
m_IsActive: 1
--- !u!4 &8130210000000000002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130210000000000001}
serializedVersion: 2
m_LocalRotation: {x: -0, y: 0.8949344, z: -0, w: -0.44619775}
m_LocalPosition: {x: 115, y: 0.38610268, z: -22}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8130210000000000005}
m_Father: {fileID: 5625234380910883685}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8130210000000000003
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130210000000000001}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 06269e6c1653db34090895cd16244df9, type: 3}
m_Name:
m_EditorClassIdentifier:
SpawnerID: 813021
MobGenRange: 6
text_lv: {fileID: 8130210000000000007}
--- !u!1 &8130210000000000004
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130210000000000005}
- component: {fileID: 8130210000000000006}
- component: {fileID: 8130210000000000007}
m_Layer: 3
m_Name: lv
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 119
m_IsActive: 1
--- !u!224 &8130210000000000005
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130210000000000004}
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0, y: 0, z: 3.14}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8130210000000000002}
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0.01}
m_SizeDelta: {x: 20, y: 5}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &8130210000000000006
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130210000000000004}
m_Enabled: 0
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &8130210000000000007
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130210000000000004}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Lv.1
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_sharedMaterial: {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 4096
m_textAlignment: 65535
m_characterSpacing: 0
m_characterHorizontalScale: 1
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 0
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 8130210000000000006}
m_maskType: 0
--- !u!1 &8130220000000000001
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130220000000000002}
- component: {fileID: 8130220000000000003}
m_Layer: 3
m_Name: e2
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 2147483647
m_IsActive: 1
--- !u!4 &8130220000000000002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130220000000000001}
serializedVersion: 2
m_LocalRotation: {x: -0, y: 0.8949344, z: -0, w: -0.44619775}
m_LocalPosition: {x: 147, y: 2.5930157, z: 30}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8130220000000000005}
m_Father: {fileID: 5625234380910883685}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8130220000000000003
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130220000000000001}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 06269e6c1653db34090895cd16244df9, type: 3}
m_Name:
m_EditorClassIdentifier:
SpawnerID: 813022
MobGenRange: 6
text_lv: {fileID: 8130220000000000007}
--- !u!1 &8130220000000000004
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130220000000000005}
- component: {fileID: 8130220000000000006}
- component: {fileID: 8130220000000000007}
m_Layer: 3
m_Name: lv
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 119
m_IsActive: 1
--- !u!224 &8130220000000000005
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130220000000000004}
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0, y: 0, z: 3.14}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8130220000000000002}
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0.01}
m_SizeDelta: {x: 20, y: 5}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &8130220000000000006
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130220000000000004}
m_Enabled: 0
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &8130220000000000007
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130220000000000004}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Lv.1
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_sharedMaterial: {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 4096
m_textAlignment: 65535
m_characterSpacing: 0
m_characterHorizontalScale: 1
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 0
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 8130220000000000006}
m_maskType: 0
--- !u!1 &8130230000000000001
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130230000000000002}
- component: {fileID: 8130230000000000003}
m_Layer: 3
m_Name: e3
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 2147483647
m_IsActive: 1
--- !u!4 &8130230000000000002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130230000000000001}
serializedVersion: 2
m_LocalRotation: {x: -0, y: 0.8949344, z: -0, w: -0.44619775}
m_LocalPosition: {x: 71, y: -0.2855866, z: 18}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8130230000000000005}
m_Father: {fileID: 5625234380910883685}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8130230000000000003
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130230000000000001}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 06269e6c1653db34090895cd16244df9, type: 3}
m_Name:
m_EditorClassIdentifier:
SpawnerID: 813023
MobGenRange: 6
text_lv: {fileID: 8130230000000000007}
--- !u!1 &8130230000000000004
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130230000000000005}
- component: {fileID: 8130230000000000006}
- component: {fileID: 8130230000000000007}
m_Layer: 3
m_Name: lv
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 119
m_IsActive: 1
--- !u!224 &8130230000000000005
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130230000000000004}
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0, y: 0, z: 3.14}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8130230000000000002}
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0.01}
m_SizeDelta: {x: 20, y: 5}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &8130230000000000006
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130230000000000004}
m_Enabled: 0
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &8130230000000000007
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130230000000000004}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Lv.1
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_sharedMaterial: {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 4096
m_textAlignment: 65535
m_characterSpacing: 0
m_characterHorizontalScale: 1
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 0
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 8130230000000000006}
m_maskType: 0
--- !u!1 &8130240000000000001
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130240000000000002}
- component: {fileID: 8130240000000000003}
m_Layer: 3
m_Name: e4
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 2147483647
m_IsActive: 1
--- !u!4 &8130240000000000002
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130240000000000001}
serializedVersion: 2
m_LocalRotation: {x: -0, y: 0.8949344, z: -0, w: -0.44619775}
m_LocalPosition: {x: 159, y: 0.8762447, z: -22}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8130240000000000005}
m_Father: {fileID: 5625234380910883685}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8130240000000000003
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130240000000000001}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 06269e6c1653db34090895cd16244df9, type: 3}
m_Name:
m_EditorClassIdentifier:
SpawnerID: 813024
MobGenRange: 6
text_lv: {fileID: 8130240000000000007}
--- !u!1 &8130240000000000004
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8130240000000000005}
- component: {fileID: 8130240000000000006}
- component: {fileID: 8130240000000000007}
m_Layer: 3
m_Name: lv
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 119
m_IsActive: 1
--- !u!224 &8130240000000000005
RectTransform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130240000000000004}
m_LocalRotation: {x: 0.7071068, y: 0, z: 0, w: 0.7071068}
m_LocalPosition: {x: 0, y: 0, z: 3.14}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8130240000000000002}
m_LocalEulerAnglesHint: {x: 90, y: 0, z: 0}
m_AnchorMin: {x: 0.5, y: 0.5}
m_AnchorMax: {x: 0.5, y: 0.5}
m_AnchoredPosition: {x: 0, y: 0.01}
m_SizeDelta: {x: 20, y: 5}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!23 &8130240000000000006
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130240000000000004}
m_Enabled: 0
m_CastShadows: 0
m_ReceiveShadows: 0
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}
--- !u!114 &8130240000000000007
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8130240000000000004}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
m_Name:
m_EditorClassIdentifier:
m_Material: {fileID: 0}
m_Color: {r: 1, g: 1, b: 1, a: 1}
m_RaycastTarget: 1
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
m_Maskable: 1
m_OnCullStateChanged:
m_PersistentCalls:
m_Calls: []
m_text: Lv.1
m_isRightToLeft: 0
m_fontAsset: {fileID: 11400000, guid: a387e325271126742ad15569dba1ac57, type: 2}
m_sharedMaterial: {fileID: -6459762427321423278, guid: a387e325271126742ad15569dba1ac57,
type: 2}
m_fontSharedMaterials: []
m_fontMaterial: {fileID: 0}
m_fontMaterials: []
m_fontColor32:
serializedVersion: 2
rgba: 4294967295
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
m_enableVertexGradient: 0
m_colorMode: 3
m_fontColorGradient:
topLeft: {r: 1, g: 1, b: 1, a: 1}
topRight: {r: 1, g: 1, b: 1, a: 1}
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
bottomRight: {r: 1, g: 1, b: 1, a: 1}
m_fontColorGradientPreset: {fileID: 0}
m_spriteAsset: {fileID: 0}
m_tintAllSprites: 0
m_StyleSheet: {fileID: 0}
m_TextStyleHashCode: -1183493901
m_overrideHtmlColors: 0
m_faceColor:
serializedVersion: 2
rgba: 4294967295
m_fontSize: 36
m_fontSizeBase: 36
m_fontWeight: 400
m_enableAutoSizing: 0
m_fontSizeMin: 18
m_fontSizeMax: 72
m_fontStyle: 0
m_HorizontalAlignment: 2
m_VerticalAlignment: 4096
m_textAlignment: 65535
m_characterSpacing: 0
m_characterHorizontalScale: 1
m_wordSpacing: 0
m_lineSpacing: 0
m_lineSpacingMax: 0
m_paragraphSpacing: 0
m_charWidthMaxAdj: 0
m_TextWrappingMode: 1
m_wordWrappingRatios: 0.4
m_overflowMode: 0
m_linkedTextComponent: {fileID: 0}
parentLinkedComponent: {fileID: 0}
m_enableKerning: 1
m_ActiveFontFeatures: 6e72656b
m_enableExtraPadding: 0
checkPaddingRequired: 0
m_isRichText: 1
m_EmojiFallbackSupport: 1
m_parseCtrlCharacters: 1
m_isOrthographic: 0
m_isCullingEnabled: 0
m_horizontalMapping: 0
m_verticalMapping: 0
m_uvLineOffset: 0
m_geometrySortingOrder: 0
m_IsTextObjectScaleStatic: 0
m_VertexBufferAutoSizeReduction: 0
m_useMaxVisibleDescender: 1
m_pageToDisplay: 1
m_margin: {x: 0, y: 0, z: 0, w: 0}
m_isUsingLegacyAnimationComponent: 0
m_isVolumetricText: 0
_SortingLayer: 0
_SortingLayerID: 0
_SortingOrder: 0
m_hasFontAssetChanged: 0
m_renderer: {fileID: 8130240000000000006}
m_maskType: 0

View File

@ -0,0 +1,275 @@
// ─────────────────────────────────────────────────────────────────────────────
// EliteMarker.cs — 엘리트 몹 마커: 크기 1.3× + 상시 색 + 처치 시간(TTK) 측정
//
// PD 지시 #813 · 발주서 WL-813s §1-2 · 기준서 v1 §D-2 813s 행 · §B 요소 1 (2026-09-09)
//
// ■ 무엇을 하나 (원본 훅 0 · Assets/Script/** 무수정 · 정적 · 러너 0)
// Spawned(isElite) → ⓐ localScale = 테이블 기본 스케일 × WLEliteSettings.scaleMultiplier(1.3)
// — **멱등**이다. 풀 재사용 몹이 다시 등장해도 기준 스케일에서 다시 곱하므로 1.3^n 이 되지 않는다.
// ⓑ MobHitFlash 에 「상시 엘리트 색」을 등록한다(MPB · 아래 참고).
// ⓒ 등장 시각을 적어 둔다(TTK).
// Killed(Elite) → ⓐ 등장 → 처치 시간(TTK)을 재서 기준서 8~12 s 대조 로그를 남긴다(링버퍼 · GC 0)
// ⓑ 상시 색을 뗀다(디졸브·풀 잔류 0). **크기는 그대로 둔다** — 사망 순간에 되돌리면
// 죽는 프레임에 몸집이 튄다. 되돌림은 RestoreAll/ClearAll(씬 전환·C8)에서만.
//
// ■ 왜 색을 MobHitFlash 에 넘기는가 (렌더러 MPB 의 소유자는 하나여야 한다)
// MobHitFlash.Apply 는 렌더러별 MPB 를 **매번 Clear 후 재구성**하고, 오버라이드가 없으면 SetPropertyBlock(null)
// 로 블록을 떼어 SRP Batcher 로 되돌린다. 여기서 별도의 MPB 를 쓰면 첫 피격 점멸에서 통째로 지워진다.
// → 상시 색을 MobHitFlash 의 상태(State.elite)로 넣어 **같은 Apply 가 합성**하게 했다.
// 우선순위 = 피격 점멸(0.03 s) > 상시 엘리트 색. 점멸이 꺼지면 상시 색으로 복귀한다.
//
// ■ 러너를 만들지 않았다
// 크기는 등장 1회 · 색은 상시(MobHitFlash 가 이미 틱을 갖는다) · TTK 는 이벤트 2개의 시각 차이라
// **매 프레임 할 일이 없다**. 씬 전환 정리만 SceneManager.activeSceneChanged 로 직접 잡는다
// (811gh ImpactRunner · 811def WLReactionRunner 어느 쪽 파일도 건드리지 않는다 = 병합 충돌 0).
// 시각은 ImpactRunner.Now(Play = Time.unscaledTime · 프로브 = 시뮬 시계)를 읽어 에디트 모드에서도 TTK 를 잴 수 있다.
//
// ■ 값(C45) — 게임 수치 상수 0. 전부 Assets/WL/Combat/Settings/Resources/WL/WLEliteSettings.asset.
// HP(8~12 s)는 코드가 아니라 **데이터**다 — MonsterAppear.json 엘리트 스포너 행 813021~813024 의 n_MonsterHP.
// 킬캠(811d)·드랍(813f)·임팩트 티어(811gh)는 이미 eSubRol.Elite 분기를 갖고 있어 이 파일이 손대지 않는다.
//
// 🔴 어셈블리 주의: Assets/WL/Combat/ 에 .asmdef 를 만들지 말 것.
// ─────────────────────────────────────────────────────────────────────────────
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using WL.Combat.Core;
namespace WL.Combat.Reaction
{
/// <summary>엘리트 몹 마커. 정적 · 새 Manager/Singleton 0 · 러너 0 · GC 0(상태는 액터당 1회 할당 = 풀 크기 상한).</summary>
public static class EliteMarker
{
sealed class State
{
public Actor actor;
public Vector3 baseScale; // 마커 적용 전(= MonsterList.f_DefaultScale) 스케일
public bool baseCaptured; // 기준 스케일을 잡았는가(멱등 보장)
public bool scaled; // 지금 배수가 걸려 있는가
public bool tinted;
public float spawnAt; // 등장 시각(ImpactRunner.Now)
public bool alive;
}
static readonly Dictionary<Actor, State> s_states = new Dictionary<Actor, State>(16);
static bool s_sceneHooked;
// ── 처치 시간(TTK) 표본 — 사전 할당 링버퍼(GC 0)
const int kSamples = 16;
static readonly float[] s_ttk = new float[kSamples];
static int s_ttkCount, s_ttkHead;
// ── 진단(프로브가 읽는다)
public static bool Subscribed;
public static int SpawnCount, KillCount, ScaleApplied, ScaleSkipped, TintApplied, TintSkipped, StatesCreated, SkippedNotElite, SkippedDisabled;
public static string LastInfo = "";
public static float LastKillTime = -1f;
public static float LastAppliedScale;
public static int StateCount { get { return s_states.Count; } }
public static int TtkCount { get { return s_ttkCount; } }
/// <summary>표본 평균 처치 시간(초). 표본이 없으면 -1.</summary>
public static float TtkAverage
{
get
{
if (s_ttkCount == 0) return -1f;
float sum = 0f;
for (int i = 0; i < s_ttkCount; i++) sum += s_ttk[i];
return sum / s_ttkCount;
}
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterAssembliesLoaded)]
static void Register()
{
CombatEvents.Spawned.Add(OnSpawned);
CombatEvents.Killed.Add(OnKilled);
if (!s_sceneHooked) { SceneManager.activeSceneChanged += OnSceneChanged; s_sceneHooked = true; }
Subscribed = true;
}
static void OnSceneChanged(Scene from, Scene to) { ClearAll(); }
static WLEliteSettings St { get { return WLEliteSettings.Instance; } }
static void Log(string msg)
{
var st = St;
if (st != null && st.verboseLog) Debug.Log("[EliteMarker] " + msg);
}
/// <summary>엘리트 판정 — 이벤트 스냅샷을 먼저 보고, 없으면 액터를 다시 읽는다(둘 다 Actor.m_SubRole 이 출처).</summary>
static bool IsElite(Actor a, bool snapshot)
{
return snapshot || (a != null && a.IsSubRole(eSubRol.Elite));
}
// ───────────────────────────────────────── 이벤트
static void OnSpawned(in SpawnedEvent e)
{
var actor = e.actor;
if (actor == null) return;
if (!IsElite(actor, e.isElite)) { SkippedNotElite++; return; }
if (!WLEliteSettings.Enabled) { SkippedDisabled++; return; }
var st = St;
var s = GetState(actor);
s.alive = true;
s.spawnAt = ImpactRunner.Now;
SpawnCount++;
ApplyScale(s, st);
ApplyTint(s, st);
LastInfo = "spawn";
Log("등장 " + actor.name + " scale=" + actor.transform.localScale.x.ToString("F2")
+ " (기본 " + s.baseScale.x.ToString("F2") + ") 색=" + s.tinted);
}
static void OnKilled(in KilledEvent e)
{
var victim = e.victim;
if (victim == null) return;
if (e.subRole != eSubRol.Elite && !IsElite(victim, false)) return;
State s;
if (!s_states.TryGetValue(victim, out s)) return;
if (!s.alive) return;
s.alive = false;
KillCount++;
var st = St;
float ttk = ImpactRunner.Now - s.spawnAt;
if (ttk >= 0f)
{
LastKillTime = ttk;
s_ttk[s_ttkHead] = ttk;
s_ttkHead = (s_ttkHead + 1) % kSamples;
if (s_ttkCount < kSamples) s_ttkCount++;
if (st != null && st.killTimeLogEnabled)
{
string verdict = ttk < st.killTimeTargetMin ? "빠름" : ttk > st.killTimeTargetMax ? "느림" : "목표";
Debug.Log("[EliteMarker] 엘리트 처치 " + victim.name + " " + ttk.ToString("F1") + " s ("
+ verdict + " · 목표 " + st.killTimeTargetMin.ToString("F0") + "~"
+ st.killTimeTargetMax.ToString("F0") + " s · 평균 " + TtkAverage.ToString("F1") + " s)");
}
}
// 색만 뗀다(디졸브·풀 잔류 0) · 크기는 유지(사망 프레임 몸집 튐 방지)
if (s.tinted) { MobHitFlash.ClearEliteTint(victim); s.tinted = false; }
LastInfo = "kill";
}
// ───────────────────────────────────────── 적용
static State GetState(Actor actor)
{
State s;
if (s_states.TryGetValue(actor, out s)) return s;
s = new State { actor = actor };
s_states.Add(actor, s);
StatesCreated++;
return s;
}
static void ApplyScale(State s, WLEliteSettings st)
{
if (st == null || !st.scaleEnabled) { ScaleSkipped++; return; }
var tf = s.actor != null ? s.actor.transform : null;
if (tf == null) { ScaleSkipped++; return; }
// 기준 스케일은 처음 볼 때 1회만 잡는다. 원본 MobActor.Set 이 f_DefaultScale 로 넣은 값이다.
if (!s.baseCaptured) { s.baseScale = tf.localScale; s.baseCaptured = true; }
float mul = st.scaleMultiplier;
if (mul <= 0f) { ScaleSkipped++; return; }
var target = s.baseScale * mul;
if (st.scaleMaxAbsolute > 0f && target.x > st.scaleMaxAbsolute)
target = s.baseScale * (st.scaleMaxAbsolute / Mathf.Max(0.0001f, s.baseScale.x));
tf.localScale = target; // 대입(누적 곱이 아니다) = 멱등
s.scaled = true;
LastAppliedScale = target.x;
ScaleApplied++;
}
static void ApplyTint(State s, WLEliteSettings st)
{
if (st == null || !st.tintEnabled) { TintSkipped++; return; }
if (MobHitFlash.SetEliteTint(s.actor, st.tintAlbedo, st.tintEmission)) { s.tinted = true; TintApplied++; }
else TintSkipped++;
}
// ───────────────────────────────────────── 정리 (C8 · 씬 전환 · 프로브)
/// <summary>모든 엘리트의 크기·색을 원복한다. 상태 캐시는 유지.</summary>
public static void RestoreAll()
{
foreach (var kv in s_states)
{
var s = kv.Value;
if (s.scaled && s.baseCaptured && s.actor != null && s.actor.transform != null)
s.actor.transform.localScale = s.baseScale;
s.scaled = false;
if (s.tinted) { MobHitFlash.ClearEliteTint(s.actor); s.tinted = false; }
s.alive = false;
}
}
/// <summary>씬 전환: 원복 후 상태 캐시(파괴된 Actor 참조)를 버린다.</summary>
public static void ClearAll()
{
RestoreAll();
s_states.Clear();
}
/// <summary>프로브용 — 이 액터가 지금 마커 상태인가.</summary>
public static bool IsMarked(Actor actor)
{
State s;
return actor != null && s_states.TryGetValue(actor, out s) && (s.scaled || s.tinted);
}
/// <summary>프로브용 — 이 액터의 기준(원본) 스케일. 없으면 -1.</summary>
public static float BaseScaleOf(Actor actor)
{
State s;
return actor != null && s_states.TryGetValue(actor, out s) && s.baseCaptured ? s.baseScale.x : -1f;
}
/// <summary>프로브용 — 에디트 모드에는 구독자가 없다(RuntimeInitializeOnLoadMethod 는 Play 전용) → 핸들러를 직접 부른다.</summary>
public static void ProbeSpawned(Actor actor)
{
var e = new SpawnedEvent
{
actor = actor,
isBoss = actor != null && actor.IsSubRole(eSubRol.Boss),
isElite = actor != null && actor.IsSubRole(eSubRol.Elite),
position = actor != null ? actor.Get_position() : Vector3.zero,
time = Time.unscaledTime, frame = Time.frameCount
};
OnSpawned(in e);
}
/// <summary>프로브용 — 가짜 Killed.</summary>
public static void ProbeKilled(Actor victim, eSubRol subRole)
{
var e = new KilledEvent
{
victim = victim, killer = null, subRole = subRole,
id = victim != null ? victim.Get_ID() : 0,
position = victim != null ? victim.Get_position() : Vector3.zero,
byDirectHit = true, time = Time.unscaledTime, frame = Time.frameCount
};
OnKilled(in e);
}
/// <summary>프로브용 카운터 초기화.</summary>
public static void ResetDiagnostics()
{
SpawnCount = KillCount = ScaleApplied = ScaleSkipped = TintApplied = TintSkipped = StatesCreated = SkippedNotElite = SkippedDisabled = 0;
LastInfo = ""; LastKillTime = -1f; LastAppliedScale = 0f;
s_ttkCount = 0; s_ttkHead = 0;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 603dc257f7e9450f8fbeb54341cb5aeb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -40,6 +40,9 @@ namespace WL.Combat.Reaction
public int activeIndex = -1;
// WL #811gh — 임팩트 티어별 점멸 강도. 1 = 기존 동작(티어 시스템 off 이면 항상 1).
public float blinkColorMul = 1f, blinkTimeMul = 1f;
// WL #813s — 엘리트 상시 색(EliteMarker 가 등록). false = 기존 동작 그대로.
public bool elite;
public Color eliteAlbedo, eliteEmission;
}
static readonly Dictionary<Actor, State> s_states = new Dictionary<Actor, State>(64);
@ -239,6 +242,13 @@ namespace WL.Combat.Reaction
if (r == null) continue;
var mpb = s.blocks[i];
mpb.Clear();
// WL #813s — 엘리트 상시 색을 먼저 깐다. 아래 점멸이 같은 프로퍼티를 덮으므로 우선순위 = 점멸 > 상시.
if (s.elite)
{
var eres = s.resolved[i];
if (eres.hasColor) mpb.SetColor(eres.colorId, s.eliteAlbedo);
if (eres.hasEmission) mpb.SetColor(eres.emissionId, s.eliteEmission);
}
if (s.blinkOn)
{
var res = s.resolved[i];
@ -307,8 +317,8 @@ namespace WL.Combat.Reaction
foreach (var kv in s_states)
{
var s = kv.Value;
if (!s.blinkOn && !s.tint) continue;
s.blinkOn = false; s.tint = false;
if (!s.blinkOn && !s.tint && !s.elite) continue;
s.blinkOn = false; s.tint = false; s.elite = false;
if (st != null) Apply(s, st);
else for (int i = 0; i < s.renderers.Length; i++) if (s.renderers[i] != null) { s.blocks[i].Clear(); s.renderers[i].SetPropertyBlock(null); }
}
@ -323,6 +333,45 @@ namespace WL.Combat.Reaction
s_states.Clear();
}
// ───────────────────────────────────────── WL #813s — 엘리트 상시 색 (EliteMarker 가 부른다)
// 렌더러 MPB 의 소유자를 하나로 유지하기 위한 진입점이다. 별도 MPB 를 쓰면 이 클래스의 Apply(=Clear 후 재구성)가
// 첫 피격 점멸에서 통째로 지운다. 상태만 넣고 합성은 기존 Apply 가 한다(우선순위 = 점멸 > 상시).
// WLHitBlinkSettings 의 enabled 와는 무관하다 — 이 SO 는 프로퍼티명 목록(셰이더 실측)의 출처로만 쓴다.
/// <summary>엘리트 상시 색을 건다. 렌더러·프로퍼티를 못 찾으면 false(색 없음).</summary>
public static bool SetEliteTint(Actor actor, Color albedo, Color emission)
{
var st = St;
if (actor == null || st == null) return false;
var s = GetState(actor, st);
if (s == null) return false;
bool any = false;
for (int i = 0; i < s.resolved.Length; i++) if (s.resolved[i].hasColor || s.resolved[i].hasEmission) { any = true; break; }
if (!any) { SkippedNoProperty++; return false; }
s.elite = true; s.eliteAlbedo = albedo; s.eliteEmission = emission;
Apply(s, st);
if (Verbose) Log("엘리트 상시 색 on " + actor.name + " renderers=" + s.renderers.Length);
return true;
}
/// <summary>엘리트 상시 색을 뗀다(처치·정리). 점멸/디졸브 상태는 건드리지 않는다.</summary>
public static void ClearEliteTint(Actor actor)
{
State s;
if (actor == null || !s_states.TryGetValue(actor, out s) || !s.elite) return;
s.elite = false;
var st = St;
if (st != null) Apply(s, st);
else for (int i = 0; i < s.renderers.Length; i++) if (s.renderers[i] != null) { s.blocks[i].Clear(); s.renderers[i].SetPropertyBlock(null); }
}
/// <summary>프로브용: 이 액터에 엘리트 상시 색이 걸려 있는가.</summary>
public static bool HasEliteTint(Actor actor)
{
State s;
return actor != null && s_states.TryGetValue(actor, out s) && s.elite;
}
/// <summary>프로브용: 특정 액터의 렌더러가 지금 프로퍼티 블록을 갖고 있는가(잔류 검사).</summary>
public static bool HasAnyBlock(Actor actor)
{

View File

@ -0,0 +1,102 @@
// ─────────────────────────────────────────────────────────────────────────────
// WLEliteSettings.cs — 엘리트 몹 마커(크기 · 상시 색 · 처치 시간 로그) 값의 단일 출처(SOT · C45)
//
// PD 지시 #813 · 발주서 WL-813s §1-2 · 기준서 v1 §B 요소 1 「엘리트 = 8~12 s」 · §D-2 813s 행 (2026-09-09)
//
// 에셋 경로(고정): Assets/WL/Combat/Settings/Resources/WL/WLEliteSettings.asset
// → Resources.Load<WLEliteSettings>("WL/WLEliteSettings") 로 1회 로드 후 캐시.
// 에셋이 없거나 enabled = false 또는 RuntimeDisabled 면 EliteMarker 가 아무 것도 하지 않는다
// (C8 · 원본 = 테이블 f_DefaultScale 그대로 · MPB 0 · 813e 배치 동작 100 %).
//
// 【아웃라인 실측 · 2026-09-09】
// · 기준서가 적은 `QuickOutline` 컴포넌트는 **이 프로젝트에 없다**(Assets 전수 검색 결과 Outline 이름 자산은
// TMP 아웃라인 피드백 · VFX 링 머티리얼뿐 · 메시 아웃라인 컴포넌트 0).
// · 몹 셰이더는 MK Toon URP Standard Simple 1종(811def 실측 299 프리팹 중 312 머티리얼).
// 림라이트 프로퍼티(`_RimColor`/`_RimSize`)는 **있으나** `#pragma shader_feature_local __ _MK_RIM_DEFAULT _MK_RIM_SPLIT`
// 키워드 게이팅이라 MaterialPropertyBlock 으로는 켤 수 없고, 이미 켜진 머티리얼에 쓰면 **아트 색을 덮어쓴다**
// → `_RimColor` 는 건드리지 않는다(811gh 교훈 「프로퍼티가 있다고 효과가 있는 게 아니다」).
// · 그래서 발주서가 지정한 대체안 = 811gh PcHitReaction 방식의 **MPB 상시 색**.
// `_EmissionColor`(MK Toon Config.hlsl 이 MK_EMISSION 을 항상 정의 → 키워드 없이 가산 · 확실히 보인다) 가 주 성분,
// `_AlbedoColor`([MainColor] · 게이팅 없음) 가 보조. 새 셰이더/머티리얼 에셋 0 · 머티리얼 인스턴스 0 · 드로우 +0.
//
// 🔴 어셈블리 주의: Assets/WL/Combat/ 에 .asmdef 를 만들지 말 것.
// ─────────────────────────────────────────────────────────────────────────────
using UnityEngine;
namespace WL.Combat.Reaction
{
[CreateAssetMenu(fileName = "WLEliteSettings", menuName = "WL/Elite Settings", order = 325)]
public sealed class WLEliteSettings : ScriptableObject
{
public const string ResourcesPath = "WL/WLEliteSettings";
static WLEliteSettings s_cached;
static bool s_lookupDone;
public static WLEliteSettings Instance
{
get
{
if (!s_lookupDone)
{
s_cached = Resources.Load<WLEliteSettings>(ResourcesPath);
s_lookupDone = true;
}
return s_cached;
}
}
/// <summary>진단·A/B 전용 런타임 스위치. 에셋을 건드리지 않고 마커만 끈다.</summary>
public static bool RuntimeDisabled;
public static bool Enabled
{
get { var i = Instance; return i != null && i.enabled && !RuntimeDisabled; }
}
public static void ClearCache() { s_cached = null; s_lookupDone = false; }
// ─────────────────────────────────────────── 전체 스위치
[Header("전체 스위치")]
[Tooltip("끄면 크기 배수·상시 색·처치 시간 로그가 전부 비활성 = 813e 배치 그대로(원본 동작). 롤백 1순위.")]
public bool enabled = true;
[Tooltip("등장·처치를 Console 에 남긴다(검증용 · GC 발생).")]
public bool verboseLog = false;
// ─────────────────────────────────────────── 크기
[Header("크기 (Spawned(isElite) → localScale = 테이블 기본 스케일 × 배수)")]
[Tooltip("끄면 크기를 건드리지 않는다.")]
public bool scaleEnabled = true;
[Tooltip("MonsterList.f_DefaultScale 로 정해진 원본 스케일에 곱하는 배수. 기준서 813s = 1.3.\n" +
"🔴 NavMeshAgent 반경·stoppingDistance 는 건드리지 않는다(원본 MobActor.Set 이 이미 정한 값 유지).")]
public float scaleMultiplier = 1.3f;
[Tooltip("이 값보다 큰 최종 스케일은 여기서 자른다(카메라 가림 방지 · 0 이하면 제한 없음).")]
public float scaleMaxAbsolute = 6f;
// ─────────────────────────────────────────── 상시 색(아웃라인 대체)
[Header("상시 색 (MPB · 머티리얼 인스턴스 0 · 새 셰이더/머티리얼 0)")]
[Tooltip("끄면 색을 쓰지 않는다. 피격 점멸(MobHitFlash)이 켜지는 동안은 점멸이 이 색을 덮는다(우선순위 = 점멸 > 상시).")]
public bool tintEnabled = true;
[Tooltip("알베도 색 프로퍼티에 쓰는 상시 색(HDR · MK Toon [MainColor] _AlbedoColor). 1 .")]
[ColorUsage(true, true)] public Color tintAlbedo = new Color(1.25f, 1.02f, 0.72f, 1f);
[Tooltip("에미션 프로퍼티에 쓰는 상시 색(HDR · MK Toon _EmissionColor = 키워드 없이 가산). 엘리트의 '테두리 광'.")]
[ColorUsage(true, true)] public Color tintEmission = new Color(0.85f, 0.45f, 0.08f, 1f);
// ─────────────────────────────────────────── 처치 시간(기준서 검증용)
[Header("처치 시간 로그 (기준서 §B 요소1 「엘리트 = 8~12 s」)")]
[Tooltip("등장 → 처치까지 걸린 시간을 재서 Console 에 남긴다(QA 판정 근거). 표본은 링버퍼에 사전 할당 = GC 0.")]
public bool killTimeLogEnabled = true;
[Tooltip("목표 하한(초).")]
public float killTimeTargetMin = 8f;
[Tooltip("목표 상한(초).")]
public float killTimeTargetMax = 12f;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4a28c4d2e3ea4ce9a58ae342a4b33bf5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,25 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 4a28c4d2e3ea4ce9a58ae342a4b33bf5, type: 3}
m_Name: WLEliteSettings
m_EditorClassIdentifier: Assembly-CSharp::WL.Combat.Reaction.WLEliteSettings
enabled: 1
verboseLog: 0
scaleEnabled: 1
scaleMultiplier: 1.3
scaleMaxAbsolute: 6
tintEnabled: 1
tintAlbedo: {r: 1.25, g: 1.02, b: 0.72, a: 1}
tintEmission: {r: 0.85, g: 0.45, b: 0.08, a: 1}
killTimeLogEnabled: 1
killTimeTargetMin: 8
killTimeTargetMax: 12

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8ddb616ff5cc4f30851c6a02698405f2
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -47,8 +47,8 @@ MonoBehaviour:
magnetRiseHeight: 3
magnetRiseSpeed: 5
burstEnabled: 1
eliteBurstMin: 1
eliteBurstMax: 2
eliteBurstMin: 2
eliteBurstMax: 3
bossBurstMin: 3
bossBurstMax: 5
normalBurstCount: 0