engine cleanup passes 4-7 + multi-instancing ambient rip
Squashes 146 commits from battle-engine-extraction. Net: 2,045 files changed, +11,896 / -158,687 lines. Ships engine passes 4-7 (dead-code cull, view-layer stub, receive-path shrink) plus the Phase-5 AsyncLocal ambient deletion that turns concurrent battles into a type-system property rather than a scope contract. ## What landed **Passes 4-7 (chunks 1-34):** Extended the Phase-4 const-false collapse into a cascading cull across the skill graph, view layer, and receive-path periphery. Six mode flags (IsWatchBattle/IsReplayBattle/IsAdmin/IsAdminWatch/IsPuzzleQuest/ IsAINetwork) became `const false`, every guarded block deleted. Field*.cs subclass ctors + BackGroundBase + ObjectChecker culled to no-ops. Mulligan family reworked to take a mgr param through IMulliganMgr.InitMulligan. Emotion/Recovery/Resource clusters null-stubbed. Prediction/OperationSimulator/ skill filters converted from static ambient reads to per-mgr reads via SkillPrm.ownerCard.SelfBattlePlayer.BattleMgr / ins.BattleMgr / this.BattleMgr. **Phase-5 ambient rip (chunks 35-47):** Deleted BattleAmbient / BattleAmbient- Context / TestBattleScope in full. Every per-battle mutable slot now lives on the mgr instance itself: mgr.InstanceIsForecast / InstanceIsRandomDraw / InstanceRecoveryInfo / InstanceViewerId / InstanceNetworkAgent / GameMgr BattleManagerBase.GetIns() returns null unconditionally; the residual static flags + 3 façades (Certification.ViewerId, Data.BattleRecoveryInfo, ToolboxGame.RealTimeNetworkAgent) are null-tolerant defaults kept for the handful of engine-internal readers that still reference their types. Zero BattleAmbient references anywhere in engine + node + tests. Added pre-seeded GameMgr ctor overload threaded through the mgr chain (BattleManagerBase → SingleBattleMgr / NetworkBattleManagerBase → NetworkStandard- BattleMgr → HeadlessBattleMgr / HeadlessNetworkBattleMgr). Fixtures build a GameMgr, seed it via HeadlessEngineEnv.SeedCharaIds/SeedNetUser, and pass it to the mgr's ctor — no ambient reach. Node side (SVSim.BattleNode/SessionBattleEngine): _ctx replaced with a plain GameMgr field; 34 `using var _ambient = BattleAmbient.Enter(_ctx)` scope wraps ripped from every accessor and mutator; EngineGlobalInit.WirePerSessionGameMgr takes GameMgr as a param and runs from SessionBattleEngine.SetupInternal BEFORE mgr construction. Test side: TestBattleScope deleted; 18 fixture [SetUp]s migrated to `HeadlessEngineEnv.EnsureProcessGlobals()`; MultiInstanceEngineTests rewritten around per-mgr construction (GetIns() → null is the pinned invariant). ## Regression fixes - **chunk-48** (MulliganCtrl): chunk-35's `= null` stubs on card lookups broke the live receive-driven Deal path (BattlePlayerBase.DrawCard NRE'd downstream of NetworkPlayerMulliganCtrl.StartMulliganVfx). Restored the three lookups via `_battlePlayer.BattleMgr.GetBattleCardIdx`. Engine tests were satisfied by the WireMulliganPhase seam; unit tests exposed the live-path gap. ## Ship state - SVSim.BattleEngine.Tests: 56/56 pass, 2 skip - SVSim.UnitTests: 1554/1554 pass (was 1523/31-fail before chunk 48) - Solution build: 0 source warnings (40 pre-existing NU1902 MessagePack CVEs in SVSim.EmulatedEntrypoint, unrelated) - Sequential PVP smoke: verified live (two back-to-back battles, no regression on cleanup/spinup) - Concurrent PVP smoke: verified live Adds tools/engine-port/ClosureAnalyzer/ — the Roslyn transitive-type-closure analyzer needed to make future cascade cleanup safe (per feedback memory "Engine cleanup needs closure tool" from the 2026-06-28 pass-3 failure). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -28,16 +28,6 @@ public class AreaSelectUI : UIBase
|
||||
Loaded
|
||||
}
|
||||
|
||||
private const float CLEAR_EFFECT_WAIT_SEC = 1.1f;
|
||||
|
||||
private const float CLEAR_LABEL_DELAY_SEC = 0.4f;
|
||||
|
||||
private const float NEWCHAPTER_FOCUS_SEC = 1f;
|
||||
|
||||
private const float NEWCHAPTER_FOCUS_MAPICON_ENABLE_THRESHOLD = 0.55f;
|
||||
|
||||
private const float MAPICON_EFFECTWAIT_SEC = 0.05f;
|
||||
|
||||
private CHAPTERUNLOCK_STATE StateChapterUnlock;
|
||||
|
||||
private float NewAreaTimer;
|
||||
@@ -60,32 +50,6 @@ public class AreaSelectUI : UIBase
|
||||
|
||||
private List<string> _loadEffectResources = new List<string>();
|
||||
|
||||
public static readonly string CUESHEETNAME_MAP = "se_st_map";
|
||||
|
||||
public const int CHAPTERLIST_CAPACITY_DEFAULT = 8;
|
||||
|
||||
private const int SORTINGORDER_EFFECT_OVER = 1;
|
||||
|
||||
private const float PLAYERICON_Y = -320f;
|
||||
|
||||
private const float TITLEPANEL_X_IN = 0f;
|
||||
|
||||
private const float TITLEPANEL_X_OUT = 949f;
|
||||
|
||||
private const float CHAPTERLIST_X_IN = -200f;
|
||||
|
||||
private const float CHAPTERLIST_X_OUT = 400f;
|
||||
|
||||
private const int CHAPTERLISTICON_MAX = 5;
|
||||
|
||||
public const float CHAPTERLISTICON_OFFSET_Y = 80f;
|
||||
|
||||
public const int CHAPTERLISTICON_MARGIN = 50;
|
||||
|
||||
public const float CHAPTERLIST_SCROLL_RADIUS = 200f;
|
||||
|
||||
public const float CHAPTERLIST_SWITCH_SEC = 0.5f;
|
||||
|
||||
private static readonly Vector2 CHAPTERLIST_PANEL_CLIPOFFSET = new Vector2(0f, -420f);
|
||||
|
||||
private static readonly Vector2 CHAPTERLIST_PANEL_CLIPPOS = new Vector2(0f, 0f);
|
||||
@@ -189,8 +153,6 @@ public class AreaSelectUI : UIBase
|
||||
|
||||
private bool _isBackTransitionStarted;
|
||||
|
||||
private IProcessing _firstSelectionProcessing;
|
||||
|
||||
private StoryChapterData _anotherEndingAppearanceAnimationChapterData;
|
||||
|
||||
private GameObject _anotherEndingAppearanceEffect;
|
||||
@@ -203,20 +165,6 @@ public class AreaSelectUI : UIBase
|
||||
|
||||
public static readonly Vector3 BG_SCALE_ZOOMIN = new Vector3(0.6f, 0.6f, 0.6f);
|
||||
|
||||
public const float BG_POS_ZOOMIN_OFFSET_Y = -400f;
|
||||
|
||||
private const float CHAPTERLISTROOT_X_OUT = 800f;
|
||||
|
||||
private const float CHAPTERLISTROOT_X_IN = -25f;
|
||||
|
||||
private const float MAPMOVE_TIMER_IDLE = 1f;
|
||||
|
||||
private const float MAPMOVE_TIMER_ZOOMIN = 1f;
|
||||
|
||||
private const float MAPMOVE_TIMER_TOEND = 1f;
|
||||
|
||||
private const float ANOTHER_ENDING_APPEARANCE_ANIMATION_TIME = 1.5f;
|
||||
|
||||
[SerializeField]
|
||||
private iTween.EaseType BG_ZOOMIN_EASETYPE = iTween.EaseType.easeInOutCubic;
|
||||
|
||||
@@ -461,7 +409,7 @@ public class AreaSelectUI : UIBase
|
||||
{
|
||||
_chapterSelectButtonList[_selectChapterIndex].OnStartClearEffect();
|
||||
IsClearLabelDisplayed = false;
|
||||
GameMgr.GetIns().GetSoundMgr().PlaySe(Se.TYPE.SYS_MAP_CLEAR);
|
||||
|
||||
GameObject obj = ((_selectChapterData.ClearStatus == StoryChapterData.ChapterClearStatus.Cleared) ? _clearEffect : _alreadyReadEffect);
|
||||
obj.transform.parent = _clearEffectPlayingChapter.ClearLabelTransform;
|
||||
obj.transform.localPosition = Vector3.zero;
|
||||
@@ -489,8 +437,8 @@ public class AreaSelectUI : UIBase
|
||||
{
|
||||
_mapIcon.SetActiveMapIcon(_selectChapterIndex, isActive: true);
|
||||
Vector3 mapIconPos = _mapIcon.GetMapIconPos(_selectChapterIndex, isLocal: false);
|
||||
GameMgr.GetIns().GetEffectMgr().Start(EffectMgr.EffectType.CMN_MAP_CHAPTER_1, mapIconPos.x, mapIconPos.y);
|
||||
GameMgr.GetIns().GetSoundMgr().PlaySe(Se.TYPE.SYS_MAP_NEW_AREA_RELEASE);
|
||||
// Pre-Phase-5b: fired CMN_MAP_CHAPTER_1 UI VFX. Dropped headless.
|
||||
|
||||
}
|
||||
IsNewMapIconOpened = true;
|
||||
}
|
||||
@@ -504,7 +452,7 @@ public class AreaSelectUI : UIBase
|
||||
private void StateUnlockChapter_FocusNewChapter_Enter()
|
||||
{
|
||||
SelectChapter(nowAreaAllNum - 1, isplayse: false, iscalcscroll: true, ismapiconeffectenable: false, isFirstClear: true);
|
||||
GameMgr.GetIns().GetSoundMgr().PlaySe(Se.TYPE.SYS_MAP_CAMERA_MOVE);
|
||||
|
||||
NewAreaTimer = ((_BG.TransitionChapterExtraData == null) ? 1f : (1f + _BG.TransitionChapterExtraData.FirstClearMoveOutDelayTime));
|
||||
IsNewMapIconOpened = false;
|
||||
}
|
||||
@@ -599,19 +547,19 @@ public class AreaSelectUI : UIBase
|
||||
|
||||
protected override void onClose()
|
||||
{
|
||||
GameMgr.GetIns().GetEffectMgr().StopBuff(EffectMgr.EffectType.CMN_MAP_PLAYERICON, PlayerIcon);
|
||||
// Pre-Phase-5b: StopBuff CMN_MAP_PLAYERICON. Dropped headless.
|
||||
_mapIcon.Term();
|
||||
_chapterEffect.UnLoadEffect();
|
||||
_chapterEffect.Term();
|
||||
StopEffectTap();
|
||||
if (LoadStatusTutorialEffect.Loaded == _loadStatusTutorialEffect)
|
||||
{
|
||||
GameMgr.GetIns().GetEffectMgr().DisposeLatestMadeEffects();
|
||||
// Pre-Phase-5b: DisposeLatestMadeEffects. Dropped headless.
|
||||
_loadStatusTutorialEffect = LoadStatusTutorialEffect.NotLoad;
|
||||
}
|
||||
Toolbox.ResourcesManager.RemoveAssetGroup(_resourcePathList);
|
||||
_resourcePathList.Clear();
|
||||
GameMgr.GetIns().GetSoundMgr().UnloadSe(CUESHEETNAME_MAP);
|
||||
|
||||
UnloadUnlockChapterResources();
|
||||
_BG.UnLoadBG();
|
||||
_BG.Term();
|
||||
@@ -631,7 +579,7 @@ public class AreaSelectUI : UIBase
|
||||
{
|
||||
if (chapterindex == _selectChapterIndex)
|
||||
{
|
||||
GameMgr.GetIns().GetSoundMgr().PlaySe(Se.TYPE.SYS_BTN_DECIDE);
|
||||
|
||||
StopEffectTap();
|
||||
ExecuteSelectionProcessings();
|
||||
}
|
||||
@@ -666,7 +614,7 @@ public class AreaSelectUI : UIBase
|
||||
{
|
||||
if (chapterindex == _selectChapterIndex)
|
||||
{
|
||||
GameMgr.GetIns().GetSoundMgr().PlaySe(Se.TYPE.SYS_BTN_DECIDE);
|
||||
|
||||
ExecuteSelectionProcessings();
|
||||
}
|
||||
else
|
||||
@@ -676,20 +624,12 @@ public class AreaSelectUI : UIBase
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCancelScenarioSummary()
|
||||
{
|
||||
if (IsUseChapterListTapEffect)
|
||||
{
|
||||
StartEffectTap();
|
||||
}
|
||||
}
|
||||
|
||||
private void StartEffectTap()
|
||||
{
|
||||
if (IsUseChapterListTapEffect && !(null != ChapterListTapEffect))
|
||||
{
|
||||
ChapterListTapEffectLocator = _chapterSelectButtonList[_chapterSelectButtonList.Count - 1].TapEffectLocator;
|
||||
ChapterListTapEffect = GameMgr.GetIns().GetEffectMgr().StartBuff(EffectMgr.EffectType.CMN_TUTORIAL_TAP_1, ChapterListTapEffectLocator);
|
||||
ChapterListTapEffect = null; // Pre-Phase-5b: StartBuff CMN_TUTORIAL_TAP_1. Dropped headless.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -697,7 +637,7 @@ public class AreaSelectUI : UIBase
|
||||
{
|
||||
if (!(null == ChapterListTapEffectLocator))
|
||||
{
|
||||
GameMgr.GetIns().GetEffectMgr().StopBuff(EffectMgr.EffectType.CMN_TUTORIAL_TAP_1, ChapterListTapEffectLocator);
|
||||
// Pre-Phase-5b: StopBuff CMN_TUTORIAL_TAP_1. Dropped headless.
|
||||
ChapterListTapEffectLocator = null;
|
||||
ChapterListTapEffect = null;
|
||||
}
|
||||
@@ -818,7 +758,7 @@ public class AreaSelectUI : UIBase
|
||||
_BG.SetBGDragEnable(!enable);
|
||||
if (isplayse)
|
||||
{
|
||||
GameMgr.GetIns().GetSoundMgr().PlaySe(enable ? Se.TYPE.SYS_TOGGLE_ON : Se.TYPE.SYS_TOGGLE_OFF);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,7 +796,6 @@ public class AreaSelectUI : UIBase
|
||||
_chapterEffect.Init(this, base.transform);
|
||||
SetPlayerIconVisible(isvisible: false);
|
||||
PlayerIcon.transform.localPosition = new Vector3(0f, -320f, 0f);
|
||||
_firstSelectionProcessing = CreateSelectionProcessings(SectionData.IsTutorialCategory);
|
||||
StartCoroutine(Setup());
|
||||
}
|
||||
|
||||
@@ -917,12 +856,11 @@ public class AreaSelectUI : UIBase
|
||||
if (IsUseChapterListTapEffect)
|
||||
{
|
||||
_loadStatusTutorialEffect = LoadStatusTutorialEffect.Loading;
|
||||
GameMgr.GetIns().GetEffectMgr().InitCommonEffect("Json/EffectTutorialData", isBattle: false, isField: false, isBattleEffect: false, delegate
|
||||
{
|
||||
_loadStatusTutorialEffect = LoadStatusTutorialEffect.Loaded;
|
||||
});
|
||||
// Pre-Phase-5b: async-loaded tutorial effect JSON via EffectMgr; callback flipped the
|
||||
// load-status flag. Headless has no EffectMgr; mark loaded synchronously so the
|
||||
// LoadStatusTutorialEffect state machine stays coherent.
|
||||
_loadStatusTutorialEffect = LoadStatusTutorialEffect.Loaded;
|
||||
}
|
||||
GameMgr.GetIns().GetSoundMgr().LoadSe(CUESHEETNAME_MAP);
|
||||
_scenarioSummary = new ScenarioSummary(SectionId, SectionClassId);
|
||||
yield return StartCoroutine(Toolbox.ResourcesManager.LoadAssetGroupAsync(_resourcePathList, null));
|
||||
bool isLoadedClearEffect = false;
|
||||
@@ -1039,7 +977,7 @@ public class AreaSelectUI : UIBase
|
||||
_chapterRewardPanel.SetClearPresent(_selectChapterData);
|
||||
if (isplayse)
|
||||
{
|
||||
GameMgr.GetIns().GetSoundMgr().PlaySe(Se.TYPE.SYS_SCROLL);
|
||||
|
||||
}
|
||||
if (iscalcscroll)
|
||||
{
|
||||
@@ -1125,30 +1063,6 @@ public class AreaSelectUI : UIBase
|
||||
{
|
||||
}
|
||||
|
||||
private static void ShowBuildDeckBuyConfirmDialog(int currentCount, int maxCount)
|
||||
{
|
||||
int productId = PlayerPrefsWrapper.GetValue(PlayerPrefsWrapper.LAST_BATTLE_DECK_ID);
|
||||
if (currentCount < maxCount)
|
||||
{
|
||||
SystemText systemText = Data.SystemText;
|
||||
string message = systemText.Get("Story_0057");
|
||||
if (currentCount > 0)
|
||||
{
|
||||
message = systemText.Get("Story_0058");
|
||||
}
|
||||
DialogBase dialogBase = UIManager.GetInstance().CreateConfirmationDialog(message);
|
||||
dialogBase.SetButtonLayout(DialogBase.ButtonLayout.BlueBtn_CancelBtn);
|
||||
dialogBase.SetTitleLabel(systemText.Get("Story_0056"));
|
||||
dialogBase.SetButtonText(systemText.Get("Shop_0095"), systemText.Get("Common_0005"));
|
||||
dialogBase.onPushButton1 = delegate
|
||||
{
|
||||
BuildDeckPurchasePage.BuildDeckConfirmDialogShow(productId);
|
||||
UIManager.GetInstance().ChangeViewScene(UIManager.ViewScene.BuildDeckPurchasePage);
|
||||
UIManager.GetInstance()._Footer.UpdateCurrentIndex(5);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupChapterDataListTutorial()
|
||||
{
|
||||
Data.StoryInfo.ChapterDataList = Data.Master.TutorialAreaSelectList.Select((TutorialAreaSelect x) => new StoryChapterData(x)).ToList();
|
||||
@@ -1211,11 +1125,11 @@ public class AreaSelectUI : UIBase
|
||||
{
|
||||
if (isvisible)
|
||||
{
|
||||
GameMgr.GetIns().GetEffectMgr().StartBuff(EffectMgr.EffectType.CMN_MAP_PLAYERICON, PlayerIcon);
|
||||
// Pre-Phase-5b: StartBuff CMN_MAP_PLAYERICON. Dropped headless.
|
||||
}
|
||||
else
|
||||
{
|
||||
GameMgr.GetIns().GetEffectMgr().StopBuff(EffectMgr.EffectType.CMN_MAP_PLAYERICON, PlayerIcon);
|
||||
// Pre-Phase-5b: StopBuff CMN_MAP_PLAYERICON. Dropped headless.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1260,43 +1174,8 @@ public class AreaSelectUI : UIBase
|
||||
SelectedStoryInfo.ClearInfoForChapterSelectionScene();
|
||||
}
|
||||
|
||||
private static IProcessing CreateSelectionProcessings(bool isTutorialCategory)
|
||||
private void ExecuteSelectionProcessings()
|
||||
{
|
||||
IProcessing[] array = ((!isTutorialCategory) ? new IProcessing[8]
|
||||
{
|
||||
new SubChapterSelectionDialogDisplay(),
|
||||
new SummaryDialogDisplay(),
|
||||
new DeckSelectionDialogDisplay(),
|
||||
new ChapterCharaDecider(),
|
||||
new DownloadInfoGetter(),
|
||||
new DownloadConfirmDialogDisplay(),
|
||||
new DeckSelectionConfirmDialogDisplay(),
|
||||
new StoryStarter()
|
||||
} : new IProcessing[3]
|
||||
{
|
||||
new SummaryDialogDisplay(),
|
||||
new ChapterCharaDecider(),
|
||||
new TutorialStoryStarter()
|
||||
});
|
||||
for (int i = 0; i < array.Length - 1; i++)
|
||||
{
|
||||
array[i].NextProcessing = array[i + 1];
|
||||
}
|
||||
return array.FirstOrDefault();
|
||||
}
|
||||
|
||||
private void ExecuteSelectionProcessings()
|
||||
{
|
||||
if (_firstSelectionProcessing != null)
|
||||
{
|
||||
Parameter param = CreateSelectionProcessingParameter();
|
||||
_firstSelectionProcessing.Execute(param);
|
||||
}
|
||||
}
|
||||
|
||||
private Parameter CreateSelectionProcessingParameter()
|
||||
{
|
||||
return new Parameter(this, _commonPrefabContainer, _scenarioSummary, SelectedStoryInfo, _selectChapterData, nowAreaAllNum, null, _selectChapterData.IsPlayedChapter ? new int?(_selectChapterIndex) : ((int?)null));
|
||||
}
|
||||
|
||||
private void InitBGStartMove()
|
||||
|
||||
Reference in New Issue
Block a user