refactor(battlenode): guard generated iface-impl against regen + stub visibility (M-HC-0 review)

- _IfaceImpl.g.cs: extend header to warn about hand-edits; tag all bare
  // HEADLESS-FIX lines with their milestone (M13 on GetSideLogControl ×2)
  so `grep HEADLESS-FIX` reliably surfaces every block before a regen.
- HeadlessHandViewStub / HeadlessPlayQueueViewStub: narrow from public to
  internal sealed — both stubs are consumed only within SVSim.BattleEngine
  (via the generated partial impls); no public surface exposes the concrete
  type, so internal is correct and aligns with HeadlessIconAnimations.
- SessionBattleEngine.SeedMulliganInfoControl: add one-line comment on the
  GetComponent<MulliganInfoControl>() call explaining the shim's lazy
  materialisation behaviour (otherwise reads like a guaranteed NRE).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-06 20:20:34 -04:00
parent 35e9847911
commit e96cc3363c
4 changed files with 7 additions and 5 deletions

View File

@@ -1,4 +1,6 @@
// AUTO-GENERATED (m1_iface_impl) — explicit no-op interface impls layered onto hierarchy bases. // AUTO-GENERATED (m1_iface_impl) — explicit no-op interface impls layered onto hierarchy bases.
// CONTAINS HAND-EDITS. Before any regen, grep this file for "HEADLESS-FIX" and re-apply those blocks;
// a plain regen will clobber them.
namespace Wizard.Battle.View { namespace Wizard.Battle.View {
using System; using System;
@@ -280,7 +282,7 @@ namespace Wizard.Battle.View {
Vector3 global::Wizard.Battle.View.IBattlePlayerView.GetBPLabelPosition() => default!; Vector3 global::Wizard.Battle.View.IBattlePlayerView.GetBPLabelPosition() => default!;
VfxBase global::Wizard.Battle.View.IBattlePlayerView.CreateBeforeFusionVfx(BattleCardBase fusionCard, List<BattleCardBase> ingredientCards) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.CreateBeforeFusionVfx(BattleCardBase fusionCard, List<BattleCardBase> ingredientCards) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
VfxBase global::Wizard.Battle.View.IBattlePlayerView.ReturnActCardAfterFusion(IBattleCardView fusionCardView, bool isFusionMetamorphose = false) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.ReturnActCardAfterFusion(IBattleCardView fusionCardView, bool isFusionMetamorphose = false) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
SideLogControl global::Wizard.Battle.View.IBattlePlayerView.GetSideLogControl(bool isSkillTargetSelect) => new SideLogControl(); // HEADLESS-FIX SideLogControl global::Wizard.Battle.View.IBattlePlayerView.GetSideLogControl(bool isSkillTargetSelect) => new SideLogControl(); // HEADLESS-FIX (M13): generator emitted default! (null); the emit path calls GetSideLogControl and enumerates the result.
VfxBase global::Wizard.Battle.View.IBattlePlayerView.SetIsNowTurnEnd(bool flg) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.SetIsNowTurnEnd(bool flg) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryInPlayCards() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryInPlayCards() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryClassAndInPlayCardAttachSkillEffect() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryClassAndInPlayCardAttachSkillEffect() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
@@ -387,7 +389,7 @@ namespace Wizard.Battle.View {
Vector3 global::Wizard.Battle.View.IBattlePlayerView.GetBPLabelPosition() => default!; Vector3 global::Wizard.Battle.View.IBattlePlayerView.GetBPLabelPosition() => default!;
VfxBase global::Wizard.Battle.View.IBattlePlayerView.CreateBeforeFusionVfx(BattleCardBase fusionCard, List<BattleCardBase> ingredientCards) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.CreateBeforeFusionVfx(BattleCardBase fusionCard, List<BattleCardBase> ingredientCards) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
VfxBase global::Wizard.Battle.View.IBattlePlayerView.ReturnActCardAfterFusion(IBattleCardView fusionCardView, bool isFusionMetamorphose = false) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.ReturnActCardAfterFusion(IBattleCardView fusionCardView, bool isFusionMetamorphose = false) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
SideLogControl global::Wizard.Battle.View.IBattlePlayerView.GetSideLogControl(bool isSkillTargetSelect) => new SideLogControl(); // HEADLESS-FIX SideLogControl global::Wizard.Battle.View.IBattlePlayerView.GetSideLogControl(bool isSkillTargetSelect) => new SideLogControl(); // HEADLESS-FIX (M13): generator emitted default! (null); the emit path calls GetSideLogControl and enumerates the result.
VfxBase global::Wizard.Battle.View.IBattlePlayerView.SetIsNowTurnEnd(bool flg) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.SetIsNowTurnEnd(bool flg) => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryInPlayCards() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryInPlayCards() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();
VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryClassAndInPlayCardAttachSkillEffect() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance(); VfxBase global::Wizard.Battle.View.IBattlePlayerView.RecoveryClassAndInPlayCardAttachSkillEffect() => global::Wizard.Battle.View.Vfx.NullVfx.GetInstance();

View File

@@ -12,7 +12,7 @@ using UnityEngine;
namespace Wizard.Battle.View namespace Wizard.Battle.View
{ {
public sealed class HeadlessHandViewStub : HandViewBase internal sealed class HeadlessHandViewStub : HandViewBase
{ {
// Shared instance the generated IBattlePlayerView.HandView getters return headless. // Shared instance the generated IBattlePlayerView.HandView getters return headless.
public static readonly HeadlessHandViewStub Instance = new HeadlessHandViewStub(); public static readonly HeadlessHandViewStub Instance = new HeadlessHandViewStub();

View File

@@ -16,7 +16,7 @@ using Wizard.Battle.View.Vfx;
namespace Wizard.Battle.View namespace Wizard.Battle.View
{ {
public sealed class HeadlessPlayQueueViewStub : PlayQueueViewBase internal sealed class HeadlessPlayQueueViewStub : PlayQueueViewBase
{ {
// Shared instance the generated IBattlePlayerView.PlayQueueView getters return headless. // Shared instance the generated IBattlePlayerView.PlayQueueView getters return headless.
public static readonly HeadlessPlayQueueViewStub Instance = new HeadlessPlayQueueViewStub(); public static readonly HeadlessPlayQueueViewStub Instance = new HeadlessPlayQueueViewStub();

View File

@@ -277,7 +277,7 @@ internal sealed class SessionBattleEngine
// (it isn't a Component, so WireComponentFields skips it). Node seed (allowed) — pure no-op view leaves. // (it isn't a Component, so WireComponentFields skips it). Node seed (allowed) — pure no-op view leaves.
private static void SeedMulliganInfoControl(GameObject prefab) private static void SeedMulliganInfoControl(GameObject prefab)
{ {
var ctrl = prefab.GetComponent<MulliganInfoControl>(); var ctrl = prefab.GetComponent<MulliganInfoControl>(); // Shim GameObject.GetComponent<T>() lazily materialises a no-op component — not a real Unity scene; this is intentional and will not NRE.
var partsType = typeof(MulliganInfoControl) var partsType = typeof(MulliganInfoControl)
.GetNestedType("MulliganParts", BindingFlags.NonPublic) .GetNestedType("MulliganParts", BindingFlags.NonPublic)
?? throw new InvalidOperationException("MulliganInfoControl.MulliganParts nested type not found"); ?? throw new InvalidOperationException("MulliganInfoControl.MulliganParts nested type not found");