AStarHeightmapGrid / Assets / PlatypusIdeas / AirPath / Runtime / UI / PathfindingUIManager.cs
PathfindingUIManager.cs
Raw
using PlatypusIdeas.AirPath.Runtime.Events;
using PlatypusIdeas.AirPath.Runtime.Modes;
using TMPro;
using UnityEngine;

namespace PlatypusIdeas.AirPath.Runtime.UI {
    /// <summary>
    /// Manages all UI elements for the pathfinding system
    /// Subscribes to events and updates UI accordingly
    /// </summary>
    public class PathfindingUIManager : MonoBehaviour {
        [Header("UI Elements")]
        [SerializeField] private TextMeshProUGUI timeText;
        [SerializeField] private TextMeshProUGUI instructionText;
        [SerializeField] private TextMeshProUGUI modeText;
        [SerializeField] private TextMeshProUGUI statusText;
        
        [Header("UI Settings")]
        [SerializeField] private bool showDetailedStatus = true;
        [SerializeField] private string defaultInstructionText = "Select a pathfinding mode to begin";
        
        private IPathfindingMode _currentMode;
        private PathfindingModeType _currentModeType;
        
        private void Start() {
            InitializeUI();
            SubscribeToEvents();
        }
        
        private void OnDestroy() {
            UnsubscribeFromEvents();
        }
        
        private void InitializeUI() {
            UpdateInstructionText(defaultInstructionText);
            UpdateModeDisplay(PathfindingModeType.MouseClick, null);
            
            if (timeText != null) {
                timeText.text = "Ready";
            }
        }
        
        private void SubscribeToEvents() {
            this.Subscribe<PathfindingModeChangedEvent>(OnModeChanged);
            this.Subscribe<PathCalculatedEvent>(OnPathCalculated);
            this.Subscribe<PathRequestedEvent>(OnPathRequested);
            this.Subscribe<BoundaryViolationEvent>(OnBoundaryViolation);
            this.Subscribe<PathfindingErrorEvent>(OnPathfindingError);
        }
        
        private void UnsubscribeFromEvents() {
            EventBusExtensions.Unsubscribe<PathfindingModeChangedEvent>(OnModeChanged);
            EventBusExtensions.Unsubscribe<PathCalculatedEvent>(OnPathCalculated);
            EventBusExtensions.Unsubscribe<PathRequestedEvent>(OnPathRequested);
            EventBusExtensions.Unsubscribe<BoundaryViolationEvent>(OnBoundaryViolation);
            EventBusExtensions.Unsubscribe<PathfindingErrorEvent>(OnPathfindingError);
        }
        
        private void OnModeChanged(PathfindingModeChangedEvent evt) {
            _currentMode = evt.ModeInstance;
            _currentModeType = evt.NewMode;
            UpdateModeDisplay(evt.NewMode, evt.ModeInstance);
            
            // Let the mode set its own instruction through the context callback
            Debug.Log($"[UI] Pathfinding mode changed to: {evt.NewMode}");
        }
        
        private void OnPathRequested(PathRequestedEvent evt) {
            if (timeText != null) {
                timeText.text = "Calculating...";
            }
        }
        
        private void OnPathCalculated(PathCalculatedEvent evt) {
            if (timeText != null) {
                timeText.text = $"Path found in: {evt.CalculationTime:F0} ms";
            }
            
            if (!evt.Success && instructionText != null) {
                instructionText.text = "No path found! Try different points.";
            }
        }
        
        private void OnBoundaryViolation(BoundaryViolationEvent evt) {
            if (evt.WasAutoClamped && instructionText != null) {
                string warning = $"Warning: {evt.ViolationType} was outside grid bounds and was clamped!";
                instructionText.text = warning;
                
                // Reset instruction text after delay
                Invoke(nameof(ResetInstructionText), 3f);
            }
        }
        
        private void OnPathfindingError(PathfindingErrorEvent evt) {
            if (evt.IsCritical) {
                if (instructionText != null) {
                    instructionText.text = $"Error: {evt.ErrorMessage}";
                }
                
                if (timeText != null) {
                    timeText.text = "Error";
                }
            }
            
            Debug.LogError($"[UI] Pathfinding error: {evt.ErrorMessage}", this);
        }
        
        private void Update() {
            // Update mode status display
            if (showDetailedStatus && _currentMode != null && statusText != null) {
                statusText.text = _currentMode.GetStatusInfo();
            }
        }
        
        public void UpdateInstructionText(string text) {
            if (instructionText) {
                instructionText.text = text;
            }
        }
        
        private void UpdateModeDisplay(PathfindingModeType modeType, IPathfindingMode modeInstance) {
            if (modeText != null) {
                string modeName = modeInstance?.ModeName ?? modeType.ToString();
                modeText.text = $"Mode: {modeName}";
            }
        }
        
        private void ResetInstructionText() {
            if (_currentMode != null) {
                // This will be called by the mode through the context callback
                // For now, set a default
                UpdateInstructionText($"{_currentMode.ModeName} mode active");
            }
        }
        
        /// <summary>
        /// Public method for modes to update instruction text through context callback
        /// </summary>
        public static void UpdateInstruction(string text) {
            var instance = FindFirstObjectByType<PathfindingUIManager>();
            instance?.UpdateInstructionText(text);
        }
    }
}