fix(BT12-Dev): 잔존 spawn cleanup 강화 — 3중 진입점 + FX clone catch (PD 지시 2026-05-14)
PD 추가 보고: "여전히 씬을 실행할 때 이전에 생성 된 풀링 오브젝트가 남아있어"
직전 commit 01865b8 Awake cleanup 1회만 호출 — 진입점 보강.
강화 사항:
1. RuntimeInitializeOnLoadMethod(AfterSceneLoad) 정적 cleanup 추가
— Awake 보다 선행하는 Scene load 직후 진입점.
2. Awake cleanup 무조건 Debug.Log (removed=0 케이스도 호출 확인 가능).
3. DelayedCleanupCoroutine — Awake 후 1·3·10 frame 추가 cleanup
(다른 컴포넌트 Awake/Start spawn 케이스 catch).
4. StaleClonePrefixes 신규 — FX clone 7종 prefix 매칭
(FX_Fireball_Bullet·FX_Lightningball·FX_Dragonfire·FX_Thunder·
FX_SLASH·FX_PinkMagicArrow·Projectile_*).
5. DoCleanupStalePooledSpawns static 메서드 통합 — useImmediate 옵션
(정적 호출 시 DestroyImmediate·Awake 호출 시 Destroy).
측정 (Play 진입 직후):
- AfterSceneLoad static cleanup removed=0
- Awake cleanup removed=0
→ 이전 Play 잔존은 0건. Hierarchy 영역 보이는 spawn 은
현재 Play 의 정상 자동 발사 결과 (BaseCooldown Tick spawn) 로 추정.
후속: PD 재현 시나리오 (Stop→Play 또는 Editor crash 후 재실행 등)
직접 확인 필요. Console 영역 "[PlayerSkillInventory] ... removed=" 로그로
cleanup 호출·잔존 카운트 확인 가능.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
01865b88fb
commit
ea239fef54
|
|
@ -43,19 +43,42 @@ namespace EerieVillage.Skills
|
|||
public event System.Action<EnemyKillContext> OnEnemyKilled;
|
||||
public event System.Action<float> OnPlayerDamaged;
|
||||
|
||||
// PD 지시 2026-05-14 — Scene load 직후 정적 cleanup (가장 이른 진입점·Awake 보다 선행)
|
||||
[UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.AfterSceneLoad)]
|
||||
static void OnSceneLoadedStaticCleanup()
|
||||
{
|
||||
int removed = DoCleanupStalePooledSpawns(true); // useDestroyImmediate=true (정적·Awake 이전)
|
||||
Debug.Log("[PlayerSkillInventory] AfterSceneLoad static cleanup removed=" + removed);
|
||||
}
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// PD 지시 2026-05-14 — 게임 재실행 시 이전 Play 잔존 spawn (투사체·박스·Range) 강제 cleanup.
|
||||
// HideFlags.DontSave 정합 외 DontDestroyOnLoad·Scene 영구 저장·메모리 잔존 경로 방어.
|
||||
CleanupStalePooledSpawns();
|
||||
// 이중 방어: AfterSceneLoad 정적 cleanup 외 Awake·1 frame 후 (Coroutine) 추가 cleanup.
|
||||
int removed = DoCleanupStalePooledSpawns(false);
|
||||
Debug.Log("[PlayerSkillInventory] Awake cleanup removed=" + removed);
|
||||
StartCoroutine(DelayedCleanupCoroutine());
|
||||
|
||||
Stats = new PlayerStats();
|
||||
PlayerStats.Current = Stats;
|
||||
_health = GetComponent<Health>();
|
||||
}
|
||||
|
||||
// PD 지시 2026-05-14 — 1·3·10 frame 후 추가 cleanup. Awake 시점 미발화 spawn·다른 컴포넌트 Awake/Start spawn 모두 catch.
|
||||
System.Collections.IEnumerator DelayedCleanupCoroutine()
|
||||
{
|
||||
int[] delays = { 1, 3, 10 };
|
||||
foreach (int d in delays)
|
||||
{
|
||||
for (int i = 0; i < d; i++) yield return null;
|
||||
int removed = DoCleanupStalePooledSpawns(false);
|
||||
if (removed > 0)
|
||||
Debug.Log("[PlayerSkillInventory] Delayed cleanup frame=" + d + " removed=" + removed);
|
||||
}
|
||||
}
|
||||
|
||||
// PD 지시 2026-05-14 — 잔존 풀링 GameObject 강제 cleanup
|
||||
// 대상: Projectile 및 파생 (HomingProjectile·PiercingProjectile) + 박스 시각화 GameObject
|
||||
// 대상: Projectile 및 파생 (HomingProjectile·PiercingProjectile) + 박스·Range·FX (Clone) 시각화 GameObject
|
||||
static readonly System.Collections.Generic.HashSet<string> StaleSpawnNames =
|
||||
new System.Collections.Generic.HashSet<string>
|
||||
{
|
||||
|
|
@ -66,7 +89,19 @@ namespace EerieVillage.Skills
|
|||
"Range_Debug",
|
||||
};
|
||||
|
||||
void CleanupStalePooledSpawns()
|
||||
// PD 지시 2026-05-14 — FX clone 카탈로그 (Projectile component 미부착 — Cast FX·HitFx 등)
|
||||
static readonly string[] StaleClonePrefixes =
|
||||
{
|
||||
"FX_Fireball_Bullet",
|
||||
"FX_Lightningball",
|
||||
"FX_Dragonfire",
|
||||
"FX_Thunder",
|
||||
"FX_SLASH",
|
||||
"FX_PinkMagicArrow",
|
||||
"Projectile_", // CreateFallbackProjectile name 패턴
|
||||
};
|
||||
|
||||
static int DoCleanupStalePooledSpawns(bool useImmediate)
|
||||
{
|
||||
int removed = 0;
|
||||
// (1) Projectile 및 파생 component GameObject — root 단위 destroy
|
||||
|
|
@ -75,23 +110,35 @@ namespace EerieVillage.Skills
|
|||
{
|
||||
if (p == null || p.gameObject == null) continue;
|
||||
if (!p.gameObject.scene.IsValid()) continue; // prefab asset 제외
|
||||
Destroy(p.gameObject);
|
||||
if (useImmediate) DestroyImmediate(p.gameObject); else Destroy(p.gameObject);
|
||||
removed++;
|
||||
}
|
||||
// (2) 박스 시각화 — name 기반 (자체 부착 컴포넌트 부재 케이스)
|
||||
// (2) 박스·Range 시각화 + FX clone — name 기반
|
||||
var allGOs = Resources.FindObjectsOfTypeAll<GameObject>();
|
||||
foreach (var go in allGOs)
|
||||
{
|
||||
if (go == null) continue;
|
||||
if (!go.scene.IsValid()) continue;
|
||||
if (StaleSpawnNames.Contains(go.name))
|
||||
bool matchName = StaleSpawnNames.Contains(go.name);
|
||||
bool matchPrefix = false;
|
||||
if (!matchName)
|
||||
{
|
||||
Destroy(go);
|
||||
foreach (var pre in StaleClonePrefixes)
|
||||
{
|
||||
if (go.name.StartsWith(pre) && go.name.EndsWith("(Clone)"))
|
||||
{
|
||||
matchPrefix = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matchName || matchPrefix)
|
||||
{
|
||||
if (useImmediate) DestroyImmediate(go); else Destroy(go);
|
||||
removed++;
|
||||
}
|
||||
}
|
||||
if (removed > 0)
|
||||
Debug.Log("[PlayerSkillInventory] CleanupStalePooledSpawns removed=" + removed);
|
||||
return removed;
|
||||
}
|
||||
|
||||
// PD 지시 2026-05-13 — Start 시점에 기본 습득 스킬 자동 장착 (Resources 로드 완료 후·Awake 영역 아님)
|
||||
|
|
|
|||
Loading…
Reference in New Issue