public static NavigationLock Acquire(ISceneArgs args) { if (_lock != null) { throw new NavigationFailureException("前回の遷移が終了する前に新しい遷移が開始されました", args); } return(_lock = new NavigationLock()); }
public void Dispose() { _lock = null; }
private async UniTask <NavigationResult> NavigateCoreAsync(ISceneArgs args, NavigationOption option = NavigationOption.None, IProgress <float> progress = null) { if (this._currentSubScenesByName.ContainsKey(args.SceneName)) { throw new NavigationFailureException($"{args.SceneName}は既にサブシーンとしてロードされています。サブシーンを通常シーンに変更することはできません。", args); } using (var internalProgresses = new NavigationInternalProgressGroup(progress, 6)) using (NavigationLock.Acquire(args)) { var loadingDisplay = default(ILoadingDisplay); if (this._loadingDisplaySelector != null) { if (this._loadingDisplaysByOption.ContainsKey((int)option)) { loadingDisplay = this._loadingDisplaysByOption[(int)option]; } else { loadingDisplay = this._loadingDisplaysByOption[(int)option] = this._loadingDisplaySelector.SelectDisplay(option); } } if (loadingDisplay != null) { loadingDisplay.Show(); } var cancellationToken = this._currentScene?.SceneLifeCancellationToken ?? new CancellationTokenSource().Token; // まずサブシーンを処理する var subSceneTransitions = await NavigateSubScenesCoreAsync(args, cancellationToken, internalProgresses[0]); internalProgresses[0].Report(1f); NavigationResult activationResult; if (this._scenesByName.ContainsKey(args.SceneName)) { // 既にInitialize済みのSceneであればActivateするだけでOK activationResult = this.Activate(args, option); } else { activationResult = await this.LoadAsync(args, cancellationToken, option, internalProgresses[1]); } internalProgresses[1].Report(1f); // ここでダメな場合は既にActivateAsyncでエラーを吐いてるハズ if (activationResult == null || activationResult.NextScene == null) { return(null); } if (option.HasFlag(NavigationOption.Push)) { // 新しいシーンをスタックに積む this._navigateHistoryStack.Push(new NavigationStackElement() { SceneName = args.SceneName, TransitionMode = activationResult.TransitionMode }); } // 新しいシーンをリセットする await activationResult.NextScene.ResetAsync(args, activationResult.TransitionMode, internalProgresses[2]); internalProgresses[2].Report(1f); if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested) { throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken); } // 新規シーンなら初期化する if (activationResult.TransitionMode.HasFlag(TransitionMode.New)) { activationResult.NextScene.Initialize(); } // 新規シーンに入る await activationResult.NextScene.EnterAsync(activationResult.TransitionMode, internalProgresses[3]); internalProgresses[3].Report(1f); if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested) { throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken); } // 古いシーンから出る if (activationResult.PreviousScene != null) { await activationResult.PreviousScene.LeaveAsync(activationResult.TransitionMode, internalProgresses[4]); internalProgresses[4].Report(1f); } // 新規シーンに入ったら外部の遷移処理を呼ぶ async UniTask enterNext() { for (var i = 0; i < activationResult.NextScene.RootCanvases.Count; ++i) { activationResult.NextScene.RootCanvases[i].enabled = false; } activationResult.NextScene.RootObject.SetActive(true); await this._afterTransition.OnEnteredAsync(activationResult, activationResult.NextScene.SceneLifeCancellationToken, new Progress <float>()); if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested) { throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken); } for (var i = 0; i < activationResult.NextScene.RootCanvases.Count; ++i) { activationResult.NextScene.RootCanvases[i].enabled = true; } } // 古いシーンの遷移処理を呼ぶ async UniTask leavePrevious() { if (activationResult.PreviousScene != null) { await this._afterTransition.OnLeftAsync(activationResult, activationResult.NextScene.SceneLifeCancellationToken, new Progress <float>()); if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested) { throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken); } // 上に乗せるフラグが無ければ非アクティブ化 if (!option.HasFlag(NavigationOption.Override)) { activationResult.PreviousScene.RootObject.SetActive(false); } // Popするならアンロードも行う if (option.HasFlag(NavigationOption.Pop)) { // シーンのファイナライズ処理 activationResult.PreviousScene.Collapse(); // 古いシーンをスタックから抜いてアンロード var popObject = this._navigateHistoryStack.Pop(); await UnloadAsync(activationResult.PreviousScene.SceneArgs, activationResult.NextScene.SceneLifeCancellationToken, internalProgresses[5]); if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested) { throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken); } } } internalProgresses[5].Report(1f); } // 遷移処理は同時に進行 await UniTask.WhenAll( enterNext(), leavePrevious(), subSceneTransitions.OnEnteredAsync(activationResult.NextScene.SceneLifeCancellationToken), subSceneTransitions.OnLeftAsync(activationResult.NextScene.SceneLifeCancellationToken)); if (activationResult.NextScene.SceneLifeCancellationToken.IsCancellationRequested) { throw new OperationCanceledException("遷移処理がキャンセルされました", new NavigationFailureException("遷移処理がキャンセルされました", args), activationResult.NextScene.SceneLifeCancellationToken); } if (loadingDisplay != null) { loadingDisplay.Hide(); } return(activationResult); } }