Files
ft/Client/Assets/Scripts/Event1v1Battle/Panel/TVPanel/Event1v1BattleSlapTvPopupPanel.Debug.cs
2026-06-29 21:18:33 +08:00

210 lines
8.1 KiB
C#

#if UNITY_EDITOR
using System;
using System.Threading.Tasks;
using Event1v1Battle.Data;
using UnityEngine;
namespace Event1v1Battle.Data
{
/// <summary>
/// TV 调试专用:不访问 <see cref="Activity.IEventDataRepository"/>,避免 <c>Repository.Load</c> 在容器未就绪时 NRE。
/// </summary>
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}");
}
}
/// <summary>无正式 Manager 时使用 <see cref="Event1v1BattleSlapManagerDebugPreview"/>,保证 <see cref="Event1v1BattleSlapManager.LoadData"/> 不碰 Repository。</summary>
private void EnsureManagerForDebugPreview()
{
if (_manager != null)
return;
_manager = new Event1v1BattleSlapManagerDebugPreview();
}
/// <summary>
/// 与正式 TV 一致:先 <see cref="Event1v1BattleSlapPresentationData.SyncFromRealData"/> 再写本段表现字段。
/// </summary>
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;
}
/// <summary>
/// 与正式 TV 一致:先 <see cref="Event1v1BattleSlapPresentationData.SyncFromRealData"/> 再写本段表现字段。
/// </summary>
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<UnityEngine.Playables.PlayableDirector>(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