using System; using System.Collections; using System.Collections.Generic; using AibisDream.Framework; using AibisDream.UI; using UnityEngine; using UnityEngine.Rendering; using VolFx; using Yarn.Unity; namespace AibisDream { public static class BaseYarnCommand { private static readonly Dictionary ActiveVolumeWeightTweens = new(); private static readonly Dictionary ActiveVolumeBrightnessTweens = new(); private static long _nextVolumeTweenToken; #region 命令名 [YarnCommand("OpenEndMenu")] public static void OpenEndMenu() { UIManager.Instance.ShowPanel(); } [YarnCommand("NextYarn")] public static void NextYarn(string exitName = null) { if (!GameManager.Instance.TryAdvanceChapterFromYarn(exitName)) { return; } EnumEventSystem.Global.Send(EventEnum.NextYarn); YarnVariableStorage.Instance.ClearLocal(); } [YarnCommand("load_scene")] public static IEnumerator LoadScene(string sceneName, float _unusedFadeDuration = 0f) { yield return GameManager.Instance.LoadSceneFromYarn(sceneName); } [YarnCommand("unload_scene")] public static IEnumerator UnloadScene() { yield return GameManager.Instance.UnloadSceneFromYarn(); } [YarnCommand("set_volume_weight")] public static void SetVolumeWeight(string volumeName, float weight) { var volumeObject = GameObject.Find(volumeName); var volume = volumeObject != null ? volumeObject.GetComponent() : null; if (volume == null) { Debug.LogWarning($"[BaseYarnCommand] 未找到 Volume: {volumeName}"); return; } CancelVolumeTween(volume, ActiveVolumeWeightTweens); volume.weight = Mathf.Clamp01(weight); } [YarnCommand("tween_volume_weight")] public static IEnumerator TweenVolumeWeight(string volumeName, float targetWeight, float duration) { var volumeObject = GameObject.Find(volumeName); var volume = volumeObject != null ? volumeObject.GetComponent() : null; if (volume == null) { Debug.LogWarning($"[BaseYarnCommand] 未找到 Volume: {volumeName}"); yield break; } targetWeight = Mathf.Clamp01(targetWeight); yield return TweenVolumeFloat( volume, ActiveVolumeWeightTweens, () => volume.weight, value => volume.weight = value, targetWeight, duration, EaseInOutSine); } [YarnCommand("tween_volume_weight_async")] public static void TweenVolumeWeightAsync(string volumeName, float targetWeight, float duration) { if (DialogController.Instance == null) { Debug.LogWarning("[BaseYarnCommand] DialogController 未初始化,无法启动异步 Volume tween"); return; } DialogController.Instance.StartCoroutine(TweenVolumeWeight(volumeName, targetWeight, duration)); } [YarnCommand("set_volume_brightness")] public static void SetVolumeBrightness(string volumeName, float brightness) { if (!TryGetVolumeAdjustments(volumeName, out var volume, out var adjustments)) { return; } CancelVolumeTween(volume, ActiveVolumeBrightnessTweens); adjustments.m_Brightness.value = Mathf.Clamp(brightness, -1f, 1f); } [YarnCommand("tween_volume_brightness")] public static IEnumerator TweenVolumeBrightness(string volumeName, float targetBrightness, float duration) { if (!TryGetVolumeAdjustments(volumeName, out var volume, out var adjustments)) { yield break; } targetBrightness = Mathf.Clamp(targetBrightness, -1f, 1f); yield return TweenVolumeFloat( volume, ActiveVolumeBrightnessTweens, () => adjustments.m_Brightness.value, value => adjustments.m_Brightness.value = value, targetBrightness, duration, SmootherStep); } [YarnCommand("tween_volume_brightness_async")] public static void TweenVolumeBrightnessAsync(string volumeName, float targetBrightness, float duration) { if (DialogController.Instance == null) { Debug.LogWarning("[BaseYarnCommand] DialogController 未初始化,无法启动异步曝光 tween"); return; } DialogController.Instance.StartCoroutine( TweenVolumeBrightness(volumeName, targetBrightness, duration)); } [YarnCommand("bloom_exposure_in")] public static IEnumerator BloomExposureIn( string volumeName, float bloomDuration = 2f, float exposureDuration = 0.8f) { if (!TryGetVolumeAdjustments(volumeName, out var volume, out var adjustments)) { yield break; } // Bloom 先扩散;等 Bloom 完全起来后,才用曝光把剩余暗部推到纯白。 adjustments.m_Brightness.value = 0f; yield return TweenFloat( () => volume.weight, value => volume.weight = value, 1f, bloomDuration); yield return TweenFloat( () => adjustments.m_Brightness.value, value => adjustments.m_Brightness.value = value, 1f, exposureDuration); } [YarnCommand("bloom_exposure_out")] public static IEnumerator BloomExposureOut( string volumeName, float bloomDuration = 2f, float exposureDuration = 0.8f) { if (!TryGetVolumeAdjustments(volumeName, out var volume, out var adjustments)) { yield break; } // 先从纯白恢复画面层次,再逐渐收掉仍然存在的 Bloom。 yield return TweenFloat( () => adjustments.m_Brightness.value, value => adjustments.m_Brightness.value = value, 0f, exposureDuration); yield return TweenFloat( () => volume.weight, value => volume.weight = value, 0f, bloomDuration); } private static bool TryGetVolumeAdjustments( string volumeName, out Volume volume, out AdjustmentsVol adjustments) { var volumeObject = GameObject.Find(volumeName); volume = volumeObject != null ? volumeObject.GetComponent() : null; adjustments = null; if (volume == null) { Debug.LogWarning($"[BaseYarnCommand] 未找到 Volume: {volumeName}"); return false; } // 使用实例化 profile,避免运行时调参污染共享的 VolumeProfile 资源。 var profile = volume.profile; if (profile == null || !profile.TryGet(out adjustments)) { Debug.LogWarning($"[BaseYarnCommand] Volume {volumeName} 缺少 AdjustmentsVol"); return false; } adjustments.active = true; adjustments.m_Brightness.overrideState = true; return true; } private static IEnumerator TweenFloat( Func getter, Action setter, float target, float duration) { if (duration <= 0f) { setter(target); yield break; } var start = getter(); var elapsed = 0f; while (elapsed < duration) { // 与 Yarn 的 <> 使用同一时间域,让快进同步加速后处理演出。 elapsed += Time.deltaTime; var progress = Mathf.Clamp01(elapsed / duration); setter(Mathf.Lerp(start, target, SmootherStep(progress))); yield return null; } setter(target); } private static IEnumerator TweenVolumeFloat( Volume volume, Dictionary activeTweens, Func getter, Action setter, float target, float duration, Func easing) { var volumeId = volume.GetInstanceID(); var token = ++_nextVolumeTweenToken; activeTweens[volumeId] = token; if (duration <= 0f) { if (IsCurrentVolumeTween(activeTweens, volumeId, token)) setter(target); CompleteVolumeTween(activeTweens, volumeId, token); yield break; } var start = getter(); var elapsed = 0f; while (elapsed < duration) { if (volume == null || !IsCurrentVolumeTween(activeTweens, volumeId, token)) yield break; // 与 Yarn 的 <> 使用同一时间域,让快进同步加速后处理演出。 elapsed += Time.deltaTime; var progress = Mathf.Clamp01(elapsed / duration); setter(Mathf.Lerp(start, target, easing(progress))); yield return null; } if (volume != null && IsCurrentVolumeTween(activeTweens, volumeId, token)) setter(target); CompleteVolumeTween(activeTweens, volumeId, token); } private static void CancelVolumeTween(Volume volume, Dictionary activeTweens) { if (volume != null) activeTweens.Remove(volume.GetInstanceID()); } private static bool IsCurrentVolumeTween( Dictionary activeTweens, int volumeId, long token) { return activeTweens.TryGetValue(volumeId, out var activeToken) && activeToken == token; } private static void CompleteVolumeTween( Dictionary activeTweens, int volumeId, long token) { if (IsCurrentVolumeTween(activeTweens, volumeId, token)) activeTweens.Remove(volumeId); } private static float EaseInOutSine(float progress) { progress = Mathf.Clamp01(progress); return 0.5f - 0.5f * Mathf.Cos(progress * Mathf.PI); } private static float SmootherStep(float progress) { progress = Mathf.Clamp01(progress); return progress * progress * progress * (progress * (progress * 6f - 15f) + 10f); } [YarnCommand("hide_dialog")] public static void HideDialog() { DialogUIManager.Instance.HideDialog(); } [YarnCommand("fade_in")] public static IEnumerator FadeIn(float duration = 1) { var panel = UIManager.Instance.GetPanel(); return panel.FadeInAsync(duration); } [YarnCommand("fade_out")] public static IEnumerator FadeOut(float duration = 1) { var panel = UIManager.Instance.GetPanel(); return panel.FadeOutAsync(duration); } [YarnCommand("fade_in_sync")] public static void FadeInSync(float duration = 1) { var panel = UIManager.Instance.GetPanel(); panel.FadeInSync(duration); } [YarnCommand("fade_out_sync")] public static void FadeOutSync(float duration = 1) { var panel = UIManager.Instance.GetPanel(); panel.FadeOutSync(duration); } [YarnCommand("fade_in_white")] public static IEnumerator FadeInWhite(float duration = 1) { var panel = UIManager.Instance.GetPanel(); return panel.FadeInWhiteAsync(duration); } [YarnCommand("flash_white")] public static IEnumerator FlashWhite(float duration = 0.2f) { var panel = UIManager.Instance.GetPanel(); return panel.FlashWhite(duration); } [YarnCommand("wipe_in")] public static IEnumerator WipeIn(float duration = 0.6f) { var panel = UIManager.Instance.GetPanel(); return panel.WipeInAsync(duration); } [YarnCommand("wipe_out")] public static IEnumerator WipeOut(float duration = 0.6f) { var panel = UIManager.Instance.GetPanel(); return panel.WipeOutAsync(duration); } [YarnCommand("shutter_in")] public static IEnumerator ShutterIn(float duration = 0.6f) { var panel = UIManager.Instance.GetPanel(); return panel.ShutterInAsync(duration); } [YarnCommand("shutter_out")] public static IEnumerator ShutterOut(float duration = 0.6f) { var panel = UIManager.Instance.GetPanel(); return panel.ShutterOutAsync(duration); } [YarnCommand("show_obj")] public static IEnumerator ShowObj(string picName, float duration = 1) { var panel = UIManager.Instance.GetPanel(); return panel.ShowObj(picName, duration); } [YarnCommand("hide_obj")] public static IEnumerator HideObj(float duration = 1) { var panel = UIManager.Instance.GetPanel(); return panel.HideObj(duration); } [YarnCommand("show_sprite")] public static IEnumerator ShowSprite(string picName, float duration = 1) { yield return SpriteShowcase.Instance.ShowObj(picName, duration); } [YarnCommand("hide_sprite")] public static IEnumerator HideSprite(float duration = 1) { yield return SpriteShowcase.Instance.HideObj(duration); } [YarnCommand("showcase_fade_in")] public static IEnumerator ShowcaseFadeIn(float duration = 1) { yield return SpriteShowcase.Instance.FadeInAsync(duration); } [YarnCommand("showcase_fade_out")] public static IEnumerator ShowcaseFadeOut(float duration = 1) { yield return SpriteShowcase.Instance.FadeOutAsync(duration); } [YarnCommand("showcase_fade_in_sync")] public static void ShowcaseFadeInSync(float duration = 1) { SpriteShowcase.Instance.FadeInSync(duration); } [YarnCommand("showcase_fade_out_sync")] public static void ShowcaseFadeOutSync(float duration = 1) { SpriteShowcase.Instance.FadeOutSync(duration); } [YarnCommand("show_large_sprite")] public static IEnumerator ShowLargeSprite(string picName, float duration = 1) { yield return SpriteShowcase.Instance.ShowLargeObj(picName, duration); } [YarnCommand("hide_large_sprite")] public static IEnumerator HideLargeSprite(float duration = 1) { yield return SpriteShowcase.Instance.HideLargeObj(duration); } [YarnCommand("hide_all_sprites")] public static IEnumerator HideAllSprites(float duration = 1) { yield return SpriteShowcase.Instance.HideAll(duration); } [YarnCommand("show_full_screen")] public static IEnumerator ShowFullScreen(string picName, float duration = 1) { var panel = UIManager.Instance.GetPanel(); return panel.ShowFullScreen(picName, duration); } [YarnCommand("hide_full_screen")] public static IEnumerator HideFullScreen(float duration = 1) { var panel = UIManager.Instance.GetPanel(); return panel.HideFullScreen(duration); } [YarnCommand("open_progress_window")] public static IEnumerator OpenProgressWindow(string title, string description, float duration) { var panel = UIManager.Instance.GetPanel(); return panel.OpenProgressWindow(title, description, duration); } [YarnCommand("open_warning_window")] public static IEnumerator OpenWarningWindow(string description) { var panel = UIManager.Instance.GetPanel(); return panel.OpenWarningWindow(description); } [YarnCommand("flash_red")] public static IEnumerator FlashRed(float duration = 0.2f) { var panel = UIManager.Instance.GetPanel(); return panel.FlashRed(duration); } [YarnCommand("show_sign_board")] public static void ShowSignBoard(bool enable = true) { var panel = UIManager.Instance.GetPanel(); panel.ShowSignBoard(); if (enable) { panel.EnableSignBoard(); } } [YarnCommand("enable_sign_board")] public static void EnableSignBoard() { var panel = UIManager.Instance.GetPanel(); panel.EnableSignBoard(); } [YarnCommand("close_sign_board")] public static void CloseSignBoard() { var panel = UIManager.Instance.GetPanel(); panel.CloseSignBoard(); } [YarnCommand("time_flows_on")] public static IEnumerator TimeFlowsOn(string originState, string targetState) { var panel = UIManager.Instance.GetPanel(); return panel.TimeFlowsOn(originState, targetState); } #endregion } }