AStarHeightmapGrid / Assets / PlatypusIdeas / AirPath / Editor / AirPathWelcomeWindow.cs
AirPathWelcomeWindow.cs
Raw
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

namespace PlatypusIdeas.AirPath.Editor {
    /// <summary>
    /// Welcome window displayed when the AirPath asset is first imported.
    /// Shows logo, welcome message, dependencies, and documentation link.
    /// </summary>
    public class AirPathWelcomeWindow : EditorWindow {
        
        private const string WINDOW_TITLE = "Welcome to AirPath";
        private const string DOCUMENTATION_URL = "https://your-documentation-url.com";
        private const string LOGO_PATH = "Assets/PlatypusIdeas/AirPath/Samples/Demo/Images/AirPathThumb.jpg";
        
        // Session state key to track if window was shown this session
        private const string SHOWN_THIS_SESSION_KEY = "AirPath_WelcomeShown";
        
        // EditorPrefs key for "Don't show again"
        private const string DONT_SHOW_AGAIN_KEY = "AirPath_DontShowWelcome";
        
        [MenuItem("Tools/AirPath/Welcome Window")]
        public static void ShowWindow() {
            var window = GetWindow<AirPathWelcomeWindow>();
            window.titleContent = new GUIContent(WINDOW_TITLE);
            // 9:16 aspect ratio
            window.minSize = new Vector2(405, 720);
            window.maxSize = new Vector2(450, 800);
            window.Show();
        }
        
        /// <summary>
        /// Called automatically when Unity loads (after domain reload or import)
        /// </summary>
        [InitializeOnLoadMethod]
        private static void OnProjectLoaded() {
            // Delay to ensure Unity is fully loaded
            EditorApplication.delayCall += TryShowWelcomeWindow;
        }
        
        private static void TryShowWelcomeWindow() {
            // Don't show if user checked "Don't show again"
            if (EditorPrefs.GetBool(DONT_SHOW_AGAIN_KEY, false)) {
                return;
            }
            
            // Don't show multiple times per session
            if (SessionState.GetBool(SHOWN_THIS_SESSION_KEY, false)) {
                return;
            }
            
            SessionState.SetBool(SHOWN_THIS_SESSION_KEY, true);
            ShowWindow();
        }
        
        public void CreateGUI() {
            var root = rootVisualElement;
            root.style.paddingBottom = 20;
            root.style.paddingLeft = 25;
            root.style.paddingRight = 25;
            root.style.backgroundColor = new Color(0.18f, 0.18f, 0.18f);
            
            // Main container with vertical layout
            var container = new VisualElement {
                style = {
                    flexDirection = FlexDirection.Column,
                    alignItems = Align.Center,
                    flexGrow = 1
                }
            };
            root.Add(container);
            
            // Logo
            AddLogo(container);
            
            // Welcome text
            AddWelcomeSection(container);
            
            // Dependencies section
            AddDependenciesSection(container);
            
            // Getting started section
            AddGettingStartedSection(container);
            
            // Documentation button
            AddDocumentationButton(container);
            
            // Don't show again toggle
            AddDontShowAgainToggle(container);
        }
        
        private void AddLogo(VisualElement parent) {
            // Logo aspect ratio is 4:3 (1920x1440)
            const float logoWidth = 320f;
            const float logoHeight = 240f; // 320 * (1440/1920) = 240
            
            var logoContainer = new VisualElement {
                style = {
                    width = logoWidth,
                    marginBottom = 20,
                    height = logoHeight,
                    alignItems = Align.Center,
                    justifyContent = Justify.Center
                }
            };
            
            var logo = AssetDatabase.LoadAssetAtPath<Texture2D>(LOGO_PATH);
            
            if (logo != null) {
                var logoImage = new Image {
                    image = logo,
                    scaleMode = ScaleMode.StretchToFill,
                    style = {
                        width = logoWidth,
                        height = logoHeight
                    }
                };
                logoContainer.Add(logoImage);
            } else {
                // Placeholder if logo not found
                var placeholder = new Label("AirPath") {
                    style = {
                        fontSize = 32,
                        unityFontStyleAndWeight = FontStyle.Bold,
                        color = new Color(0.4f, 0.7f, 1f),
                        unityTextAlign = TextAnchor.MiddleCenter
                    }
                };
                logoContainer.Add(placeholder);
                
                Debug.LogWarning($"[AirPath] Logo not found at: {LOGO_PATH}");
            }
            
            parent.Add(logoContainer);
        }
        
        private void AddWelcomeSection(VisualElement parent) {
            var welcomeTitle = new Label("Welcome to AirPath!") {
                style = {
                    fontSize = 24,
                    unityFontStyleAndWeight = FontStyle.Bold,
                    color = Color.white,
                    marginBottom = 10,
                    unityTextAlign = TextAnchor.MiddleCenter
                }
            };
            parent.Add(welcomeTitle);
            
            var welcomeText = new Label(
                "Thank you for choosing AirPath, the advanced aerial pathfinding solution for Unity.\n\n" +
                "AirPath provides high-performance 3D pathfinding optimized for flying agents, " +
                "featuring DOTS integration, terrain-aware navigation, and flexible configuration options."
            ) {
                style = {
                    fontSize = 13,
                    color = new Color(0.8f, 0.8f, 0.8f),
                    marginBottom = 25,
                    unityTextAlign = TextAnchor.MiddleCenter,
                    whiteSpace = WhiteSpace.Normal,
                    maxWidth = 400
                }
            };
            parent.Add(welcomeText);
        }
        
        private void AddDependenciesSection(VisualElement parent) {
            var dependenciesContainer = new VisualElement {
                style = {
                    backgroundColor = new Color(0.22f, 0.22f, 0.22f),
                    borderTopLeftRadius = 8,
                    borderTopRightRadius = 8,
                    borderBottomLeftRadius = 8,
                    borderBottomRightRadius = 8,
                    paddingTop = 15,
                    paddingBottom = 15,
                    paddingLeft = 20,
                    paddingRight = 20,
                    marginBottom = 25,
                    width = 380
                }
            };
            
            var dependenciesTitle = new Label("Required Dependencies") {
                style = {
                    fontSize = 14,
                    unityFontStyleAndWeight = FontStyle.Bold,
                    color = Color.white,
                    marginBottom = 12,
                    unityTextAlign = TextAnchor.MiddleCenter
                }
            };
            dependenciesContainer.Add(dependenciesTitle);
            
            var dependenciesInfo = new Label(
                "These packages are automatically installed via Package Manager:"
            ) {
                style = {
                    fontSize = 11,
                    color = new Color(0.6f, 0.6f, 0.6f),
                    marginBottom = 10,
                    unityTextAlign = TextAnchor.MiddleCenter,
                    whiteSpace = WhiteSpace.Normal
                }
            };
            dependenciesContainer.Add(dependenciesInfo);
            
            // Dependency list
            var dependencies = new (string name, string version, string status)[] {
                ("com.unity.burst", "1.8.0+", GetPackageStatus("com.unity.burst")),
                ("com.unity.collections", "2.1.0+", GetPackageStatus("com.unity.collections")),
                ("com.unity.mathematics", "1.2.0+", GetPackageStatus("com.unity.mathematics")),
                ("com.unity.entities", "1.3.14+", GetPackageStatus("com.unity.entities")),
                ("com.unity.inputsystem", "1.7.0+", GetPackageStatus("com.unity.inputsystem"))
            };
            
            foreach (var dep in dependencies) {
                var depRow = CreateDependencyRow(dep.name, dep.version, dep.status);
                dependenciesContainer.Add(depRow);
            }
            
            parent.Add(dependenciesContainer);
        }
        
        private VisualElement CreateDependencyRow(string packageName, string version, string status) {
            var row = new VisualElement {
                style = {
                    flexDirection = FlexDirection.Row,
                    justifyContent = Justify.SpaceBetween,
                    alignItems = Align.Center,
                    marginTop = 4,
                    marginBottom = 4
                }
            };
            
            var nameLabel = new Label($"• {packageName}") {
                style = {
                    fontSize = 12,
                    color = new Color(0.75f, 0.75f, 0.75f),
                    flexGrow = 1
                }
            };
            row.Add(nameLabel);
            
            var versionLabel = new Label(version) {
                style = {
                    fontSize = 11,
                    color = new Color(0.5f, 0.5f, 0.5f),
                    marginRight = 10
                }
            };
            row.Add(versionLabel);
            
            var isInstalled = status == "Installed";
            var statusLabel = new Label(status) {
                style = {
                    fontSize = 11,
                    color = isInstalled ? new Color(0.4f, 0.8f, 0.4f) : new Color(0.9f, 0.6f, 0.2f),
                    unityFontStyleAndWeight = FontStyle.Bold,
                    width = 70,
                    unityTextAlign = TextAnchor.MiddleRight
                }
            };
            row.Add(statusLabel);
            
            return row;
        }
        
        private string GetPackageStatus(string packageName) {
            // Check if package is installed via Package Manager
            var listRequest = UnityEditor.PackageManager.Client.List(true);
            
            // Since this is synchronous and we can't easily await, 
            // we'll do a simple check using the packages cache
            var packagePath = $"Packages/{packageName}";
            
            if (System.IO.Directory.Exists(packagePath) || 
                AssetDatabase.IsValidFolder(packagePath)) {
                return "Installed";
            }
            
            // Fallback check via assembly presence
            return IsPackageAssemblyLoaded(packageName) ? "Installed" : "Pending";
        }
        
        private bool IsPackageAssemblyLoaded(string packageName) {
            return packageName switch {
                "com.unity.burst" => IsTypeAvailable("Unity.Burst.BurstCompiler"),
                "com.unity.collections" => IsTypeAvailable("Unity.Collections.NativeArray`1"),
                "com.unity.mathematics" => IsTypeAvailable("Unity.Mathematics.float3"),
                "com.unity.inputsystem" => IsTypeAvailable("UnityEngine.InputSystem.InputSystem"),
                _ => false
            };
        }
        
        private bool IsTypeAvailable(string typeName) {
            foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies()) {
                if (assembly.GetType(typeName) != null) {
                    return true;
                }
            }
            return false;
        }
        
        private void AddGettingStartedSection(VisualElement parent) {
            var gettingStartedContainer = new VisualElement {
                style = {
                    alignItems = Align.Center,
                    marginBottom = 15
                }
            };
            
            var gettingStartedTitle = new Label("Getting Started") {
                style = {
                    fontSize = 16,
                    unityFontStyleAndWeight = FontStyle.Bold,
                    color = new Color(0.4f, 0.75f, 1f),
                    marginBottom = 8,
                    unityTextAlign = TextAnchor.MiddleCenter
                }
            };
            gettingStartedContainer.Add(gettingStartedTitle);
            
            var gettingStartedText = new Label(
                "New to AirPath? I recommend reading the documentation first to get familiar with the setup and core concepts."
            ) {
                style = {
                    fontSize = 12,
                    color = new Color(0.7f, 0.7f, 0.7f),
                    unityTextAlign = TextAnchor.MiddleCenter,
                    whiteSpace = WhiteSpace.Normal,
                    maxWidth = 350
                }
            };
            gettingStartedContainer.Add(gettingStartedText);
            
            parent.Add(gettingStartedContainer);
        }
        
        private void AddDocumentationButton(VisualElement parent) {
            var button = new Button(() => Application.OpenURL(DOCUMENTATION_URL)) {
                text = "Open Documentation",
                style = {
                    height = 40,
                    width = 200,
                    fontSize = 14,
                    unityFontStyleAndWeight = FontStyle.Bold,
                    backgroundColor = new Color(0.2f, 0.5f, 0.8f),
                    color = Color.white,
                    borderTopLeftRadius = 6,
                    borderTopRightRadius = 6,
                    borderBottomLeftRadius = 6,
                    borderBottomRightRadius = 6,
                    marginBottom = 20,
                    borderTopWidth = 0,
                    borderBottomWidth = 0,
                    borderLeftWidth = 0,
                    borderRightWidth = 0
                }
            };
            
            // Hover effect
            button.RegisterCallback<MouseEnterEvent>(evt => {
                button.style.backgroundColor = new Color(0.25f, 0.55f, 0.85f);
            });
            button.RegisterCallback<MouseLeaveEvent>(evt => {
                button.style.backgroundColor = new Color(0.2f, 0.5f, 0.8f);
            });
            
            parent.Add(button);
        }
        
        private void AddDontShowAgainToggle(VisualElement parent) {
            var toggleContainer = new VisualElement {
                style = {
                    flexDirection = FlexDirection.Row,
                    alignItems = Align.Center,
                    justifyContent = Justify.Center
                }
            };
            
            var toggle = new Toggle {
                value = EditorPrefs.GetBool(DONT_SHOW_AGAIN_KEY, false),
                style = {
                    marginRight = 5
                }
            };
            toggle.RegisterValueChangedCallback(evt => {
                EditorPrefs.SetBool(DONT_SHOW_AGAIN_KEY, evt.newValue);
            });
            toggleContainer.Add(toggle);
            
            var toggleLabel = new Label("Don't show this window on startup") {
                style = {
                    fontSize = 11,
                    color = new Color(0.5f, 0.5f, 0.5f)
                }
            };
            toggleContainer.Add(toggleLabel);
            
            parent.Add(toggleContainer);
        }
        
        /// <summary>
        /// Resets the "Don't show again" preference (useful for testing)
        /// </summary>
        [MenuItem("Tools/AirPath/Reset Welcome Window Preference")]
        public static void ResetWelcomePreference() {
            EditorPrefs.DeleteKey(DONT_SHOW_AGAIN_KEY);
            SessionState.SetBool(SHOWN_THIS_SESSION_KEY, false);
            Debug.Log("[AirPath] Welcome window preference reset. It will show on next domain reload.");
        }
    }
}