#if UNITY_EDITOR using System; using System.Threading.Tasks; using Event1v1Battle.Data; using UnityEngine; namespace Event1v1Battle.Data { /// /// TV 调试专用:不访问 ,避免 Repository.Load 在容器未就绪时 NRE。 /// internal sealed class Event1v1BattleSlapManagerDebugPreview : Event1v1BattleSlapManager { readonly Event1v1BattleSlapData _stubData; public Event1v1BattleSlapManagerDebugPreview() { _stubData = new Event1v1BattleSlapData { MaxHp = 100, NpcHp = 100, PlayerHp = 100, PlayerLifeCount = 3, CurrentStageID = 1, CurrentRoundForm1 = 1, NpcName = string.Empty, NpcIcon = string.Empty, IsOnGoing = true, }; } public override Event1v1BattleSlapData LoadData() => _stubData; } } namespace game { public partial class Event1v1BattleSlapTvPopupPanel { [Header("Editor Preview")] [SerializeField] private bool debugSkipAutoPlayOnStart = false; [SerializeField][Min(0)] private int debugPlayerAttackQuality = 0; [SerializeField] private bool debugPlayerAttackKillNpc = false; [SerializeField][Min(0)] private int debugNpcAttackQuality = 0; [SerializeField] private bool debugNpcAttackKillPlayer = false; partial void OnStartDebugHook(ref bool shouldAutoPlay) { if (!debugSkipAutoPlayOnStart) return; shouldAutoPlay = false; EnsureDebugPreviewRuntimeReferences(); PlayDirectorClipLoopingNoWait(_playerDirector, idle_player, 0); PlayDirectorClipLoopingNoWait(_enemyDirector, idle_enemy, 0); } [ContextMenu("Debug/Preview Player Attack")] private async void DebugPreviewPlayerAttack() { if (!Application.isPlaying) { Debug.LogWarning($"[{nameof(Event1v1BattleSlapTvPopupPanel)}] Debug preview only works in Play Mode."); return; } EnsureManagerForDebugPreview(); EnsureDebugPreviewRuntimeReferences(); ApplyDebugPresentationForPlayerAttackPreview(); LogDebugPreviewState( "PlayerAttack (TryPlayPlayerAttack)", debugPlayerAttackQuality, debugPlayerAttackKillNpc, GetPlayerAttackAsset(debugPlayerAttackQuality), GetEnemyHitAsset(debugPlayerAttackQuality)); try { await TryPlayPlayerAttack(); } catch (Exception e) { Debug.LogError($"[{nameof(Event1v1BattleSlapTvPopupPanel)}] Debug preview PlayerAttack error, {e}"); } } [ContextMenu("Debug/Preview NPC Attack")] private async void DebugPreviewNpcAttack() { if (!Application.isPlaying) { Debug.LogWarning($"[{nameof(Event1v1BattleSlapTvPopupPanel)}] Debug preview only works in Play Mode."); return; } EnsureManagerForDebugPreview(); EnsureDebugPreviewRuntimeReferences(); ApplyDebugPresentationForNpcAttackPreview(); LogDebugPreviewState( "NpcAttack (TryPlayNpcAttack)", debugNpcAttackQuality, debugNpcAttackKillPlayer, GetEnemyAttackAsset(debugNpcAttackQuality), GetPlayerHitAsset(debugNpcAttackQuality)); try { await TryPlayNpcAttack(); } catch (Exception e) { Debug.LogError($"[{nameof(Event1v1BattleSlapTvPopupPanel)}] Debug preview NpcAttack error, {e}"); } } /// 无正式 Manager 时使用 ,保证 不碰 Repository。 private void EnsureManagerForDebugPreview() { if (_manager != null) return; _manager = new Event1v1BattleSlapManagerDebugPreview(); } /// /// 与正式 TV 一致:先 再写本段表现字段。 /// private void ApplyDebugPresentationForPlayerAttackPreview() { var pd = _manager.PresentationData; pd.Clear(); var data = _manager.LoadData(); pd.SyncFromRealData(data); pd.IsPlayAttacking = true; pd.CanQuality = debugPlayerAttackQuality; pd.KilledNpc = debugPlayerAttackKillNpc; } /// /// 与正式 TV 一致:先 再写本段表现字段。 /// private void ApplyDebugPresentationForNpcAttackPreview() { var pd = _manager.PresentationData; pd.Clear(); var data = _manager.LoadData(); pd.SyncFromRealData(data); pd.IsNpcAttacking = true; pd.NpcAttackCanQuality = debugNpcAttackQuality; pd.KilledPlayer = debugNpcAttackKillPlayer; } private void EnsureDebugPreviewRuntimeReferences() { if (_playerDirector == null || _enemyDirector == null) { var spineRoot = gameObject.FindChildGameObject("spine_root"); if (spineRoot != null) { var directors = spineRoot.GetComponentsInChildren(true); if (_playerDirector == null && directors.Length > 0) _playerDirector = directors[0]; if (_enemyDirector == null && directors.Length > 1) _enemyDirector = directors[1]; } } _playerDirector?.Stop(); _enemyDirector?.Stop(); _resDirector?.Stop(); } private void LogDebugPreviewState(string previewName, int quality, bool killedTarget, UnityEngine.Playables.PlayableAsset attackAsset, UnityEngine.Playables.PlayableAsset hitAsset) { float attackDuration = _playerDirector != null ? GetPlayableDuration(_playerDirector, attackAsset) : 0f; float hitDuration = _enemyDirector != null ? GetPlayableDuration(_enemyDirector, hitAsset) : 0f; Debug.Log( $"[{nameof(Event1v1BattleSlapTvPopupPanel)}] Debug preview {previewName} " + $"quality={quality} killed={killedTarget} " + $"playerDirector={_playerDirector?.name ?? "null"} enemyDirector={_enemyDirector?.name ?? "null"} " + $"attackAsset={attackAsset?.name ?? "null"} attackDuration={attackDuration:F3} " + $"hitAsset={hitAsset?.name ?? "null"} hitDuration={hitDuration:F3}"); } private UnityEngine.Playables.PlayableAsset GetPlayerAttackAsset(int quality) { bool heavy = IsHeavyFromQuality(quality); return heavy ? attack_player_2 ?? attack_player_1 : attack_player_1 ?? attack_player_2; } private UnityEngine.Playables.PlayableAsset GetEnemyHitAsset(int quality) { bool heavy = IsHeavyFromQuality(quality); return heavy ? hit_enemy_2 ?? hit_enemy_1 : hit_enemy_1 ?? hit_enemy_2; } private UnityEngine.Playables.PlayableAsset GetEnemyAttackAsset(int quality) { bool heavy = IsHeavyFromQuality(quality); return heavy ? attack_enemy_2 ?? attack_enemy_1 : attack_enemy_1 ?? attack_enemy_2; } private UnityEngine.Playables.PlayableAsset GetPlayerHitAsset(int quality) { bool heavy = IsHeavyFromQuality(quality); return heavy ? hit_player_2 ?? hit_player_1 : hit_player_1 ?? hit_player_2; } } } #endif