summaryrefslogtreecommitdiff
path: root/Other/AstarPathfindingDemo/Packages/com.arongranberg.astar/Editor/UI/WelcomeScreen.cs
blob: 424dad2612320f6f51a0db78fba775cc0c6df5b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
using System;
using System.Linq;
using UnityEditor;
using UnityEditor.SceneManagement;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UIElements;
using UnityEditor.Compilation;
using UnityEditor.Scripting.ScriptCompilation;

namespace Pathfinding {
	internal class WelcomeScreen : UnityEditor.EditorWindow {
		[SerializeField]
		private VisualTreeAsset m_VisualTreeAsset = default;

		public bool isImportingSamples;
		private bool askedAboutQuitting;

		[InitializeOnLoadMethod]
		public static void TryCreate () {
			if (!PathfindingEditorSettings.instance.hasShownWelcomeScreen) {
				// Wait a bit before showing the window to avoid stuttering
				// as all the other windows in Unity load.
				// This makes the animation smoother.
				var delay = 0.5f;
				var t0 = Time.realtimeSinceStartup;
				EditorApplication.CallbackFunction create = null;
				create = () => {
					if (Time.realtimeSinceStartup - t0 > delay) {
						EditorApplication.update -= create;
						PathfindingEditorSettings.instance.hasShownWelcomeScreen = true;
						PathfindingEditorSettings.instance.Save();
						Create();
					}
				};
				EditorApplication.update += create;
			}
		}

		public static void Create () {
			var window = GetWindow<WelcomeScreen>(
				true,
				"A* Pathfinding Project",
				true
				);
			window.minSize = window.maxSize = new Vector2(400, 400*1.618f);
			window.ShowUtility();
		}


		public void CreateGUI () {
			VisualElement root = rootVisualElement;

			VisualElement labelFromUXML = m_VisualTreeAsset.Instantiate();
			root.Add(labelFromUXML);

			var sampleButton = root.Query<Button>("importSamples").First();
			var samplesImportedIndicator = root.Query("samplesImported").First();
			samplesImportedIndicator.visible = GetSamples(out var sample) && sample.isImported;

			sampleButton.clicked += ImportSamples;
			root.Query<Button>("documentation").First().clicked += OpenDocumentation;
			root.Query<Button>("getStarted").First().clicked += OpenGetStarted;
			root.Query<Button>("changelog").First().clicked += OpenChangelog;
			root.Query<Label>("version").First().text = "Version " + AstarPath.Version.ToString();
			AnimateLogo(root.Query("logo").First());
		}

		static string FirstSceneToLoad = "Recast3D";

		public void OnEnable () {
			if (isImportingSamples) {
				// This will be after the domain reload that happened after the samples were imported
				OnPostImportedSamples();
			}
		}

		public void OnPostImportedSamples () {
			isImportingSamples = false;
			// Load the example scene
			var sample = UnityEditor.PackageManager.UI.Sample.FindByPackage("com.arongranberg.astar", "").First();
			if (sample.isImported) {
				var relativePath = "Assets/" + System.IO.Path.GetRelativePath(Application.dataPath, sample.importPath);
				Debug.Log(relativePath);
				var scenes = AssetDatabase.FindAssets("t:scene", new string[] { relativePath });
				string bestScene = null;
				for (int i = 0; i < scenes.Length; i++) {
					scenes[i] = AssetDatabase.GUIDToAssetPath(scenes[i]);
					if (scenes[i].Contains(FirstSceneToLoad)) {
						bestScene = scenes[i];
					}
				}
				if (bestScene == null) bestScene = scenes.FirstOrDefault();
				if (bestScene != null) {
					if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) {
						EditorSceneManager.OpenScene(bestScene);
					}
				}
			}
		}

		void AnimateLogo (VisualElement logo) {
			var t0 = Time.realtimeSinceStartup;
			EditorApplication.CallbackFunction introAnimation = null;
			int ticks = 0;
			introAnimation = () => {
				var t = Time.realtimeSinceStartup - t0;
				if (ticks == 1) {
					logo.RemoveFromClassList("largeIconEntry");
				}
				Repaint();
				ticks++;
				if (ticks > 1 && t > 5) {
					EditorApplication.update -= introAnimation;
				}
			};
			EditorApplication.update += introAnimation;
		}

		bool GetSamples (out UnityEditor.PackageManager.UI.Sample sample) {
			sample = default;

			var samples = UnityEditor.PackageManager.UI.Sample.FindByPackage("com.arongranberg.astar", "");
			if (samples == null) {
				return false;
			}
			var samplesArr = samples.ToArray();
			if (samplesArr.Length != 1) {
				Debug.LogError("Expected exactly 1 sample. Found " + samplesArr.Length + ". This should not happen");
				return false;
			}

			sample = samplesArr[0];
			return true;
		}

		private void ImportSamples () {
			if (!GetSamples(out var sample)) {
				Debug.LogError("The A* Pathfinding Project is not installed via the Unity package manager. Cannot import samples.");
				return;
			}

			if (sample.isImported) {
				// Show dialog box
				if (!EditorUtility.DisplayDialog("Import samples", "Samples are already imported. Do you want to reimport them?", "Reimport", "Cancel")) {
					return;
				}
			}

			isImportingSamples = true;

			CompilationPipeline.assemblyCompilationFinished += OnAssemblyCompilationFinished;

			if (!sample.Import(UnityEditor.PackageManager.UI.Sample.ImportOptions.OverridePreviousImports)) {
				Debug.LogError("Failed to import samples");
				return;
			}

			OnPostImportedSamples();
		}

		void OnAssemblyCompilationFinished (string assembly, CompilerMessage[] message) {
			for (int i = 0; i < message.Length; i++) {
				// E.g.
				// error CS0006: Metadata file 'Assets/AstarPathfindingProject/Plugins/Clipper/Pathfinding.ClipperLib.dll' could not be found
				// error CS0006: Metadata file 'Assets/AstarPathfindingProject/Plugins/DotNetZip/Pathfinding.Ionic.Zip.Reduced.dll' could not be found
				// error CS0006: Metadata file 'Assets/AstarPathfindingProject/Plugins/Poly2Tri/Pathfinding.Poly2Tri.dll' could not be found
				// I believe this can happen if the user previously has had the package imported into the Assets folder (e.g. version 4),
				// and then it is imported via the package manager, and the samples imported.
				// Unity seems to miss that the dll files now have new locations, and gets confused.
				if (message[i].type == CompilerMessageType.Error && message[i].message.Contains("CS0006")) {
					Debug.LogError("Compilation failed due to a Unity bug. Asking user to restart Unity.");

					if (!askedAboutQuitting) {
						if (EditorUtility.DisplayDialog("Restart Unity", "Your version of Unity has a bug that, unfortunately, requires the editor to be restarted, after importing the samples.", "Quit Unity", "Cancel")) {
							askedAboutQuitting = true;
							EditorApplication.update += () => {
								if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo()) {
									EditorApplication.Exit(0);
								}
							};
						}
					}
				}
			}
		}

		private void OpenDocumentation () {
			Application.OpenURL(AstarUpdateChecker.GetURL("documentation"));
		}

		private void OpenGetStarted () {
			Application.OpenURL(AstarUpdateChecker.GetURL("documentation") + "getstarted.html");
		}

		private void OpenChangelog () {
			Application.OpenURL(AstarUpdateChecker.GetURL("changelog"));
		}
	}
}