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
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
|
using UnityEngine;
using UnityEditor;
using Pathfinding.Util;
using UnityEngine.Networking;
using System.Collections.Generic;
using System.Linq;
namespace Pathfinding {
/// <summary>Handles update checking for the A* Pathfinding Project</summary>
[InitializeOnLoad]
public static class AstarUpdateChecker {
/// <summary>Used for downloading new version information</summary>
static UnityWebRequest updateCheckDownload;
static System.DateTime _lastUpdateCheck;
static bool _lastUpdateCheckRead;
static System.Version _latestVersion;
static System.Version _latestBetaVersion;
/// <summary>Description of the latest update of the A* Pathfinding Project</summary>
static string _latestVersionDescription;
static bool hasParsedServerMessage;
/// <summary>Number of days between update checks</summary>
const double updateCheckRate = 1F;
/// <summary>URL to the version file containing the latest version number.</summary>
const string updateURL = "https://www.arongranberg.com/astar/version.php";
/// <summary>Last time an update check was made</summary>
public static System.DateTime lastUpdateCheck {
get {
try {
// Reading from EditorPrefs is relatively slow, avoid it
if (_lastUpdateCheckRead) return _lastUpdateCheck;
_lastUpdateCheck = System.DateTime.Parse(EditorPrefs.GetString("AstarLastUpdateCheck", "1/1/1971 00:00:01"), System.Globalization.CultureInfo.InvariantCulture);
_lastUpdateCheckRead = true;
}
catch (System.FormatException) {
lastUpdateCheck = System.DateTime.UtcNow;
Debug.LogWarning("Invalid DateTime string encountered when loading from preferences");
}
return _lastUpdateCheck;
}
private set {
_lastUpdateCheck = value;
EditorPrefs.SetString("AstarLastUpdateCheck", _lastUpdateCheck.ToString(System.Globalization.CultureInfo.InvariantCulture));
}
}
/// <summary>Latest version of the A* Pathfinding Project</summary>
public static System.Version latestVersion {
get {
RefreshServerMessage();
return _latestVersion ?? AstarPath.Version;
}
private set {
_latestVersion = value;
}
}
/// <summary>Latest beta version of the A* Pathfinding Project</summary>
public static System.Version latestBetaVersion {
get {
RefreshServerMessage();
return _latestBetaVersion ?? AstarPath.Version;
}
private set {
_latestBetaVersion = value;
}
}
/// <summary>Summary of the latest update</summary>
public static string latestVersionDescription {
get {
RefreshServerMessage();
return _latestVersionDescription ?? "";
}
private set {
_latestVersionDescription = value;
}
}
/// <summary>
/// Holds various URLs and text for the editor.
/// This info can be updated when a check for new versions is done to ensure that there are no invalid links.
/// </summary>
static Dictionary<string, string> astarServerData = new Dictionary<string, string> {
{ "URL:modifiers", "https://www.arongranberg.com/astar/docs/modifiers.html" },
{ "URL:astarpro", "https://arongranberg.com/unity/a-pathfinding/astarpro/" },
{ "URL:documentation", "https://arongranberg.com/astar/docs/" },
{ "URL:findoutmore", "https://arongranberg.com/astar" },
{ "URL:download", "https://arongranberg.com/unity/a-pathfinding/download" },
{ "URL:changelog", "https://arongranberg.com/astar/docs/changelog.html" },
{ "URL:tags", "https://arongranberg.com/astar/docs/tags.html" },
{ "URL:homepage", "https://arongranberg.com/astar/" }
};
static AstarUpdateChecker() {
// Add a callback so that we can parse the message when it has been downloaded
EditorApplication.update += UpdateCheckLoop;
EditorBase.getDocumentationURL = () => GetURL("documentation");
}
static void RefreshServerMessage () {
if (!hasParsedServerMessage) {
var serverMessage = EditorPrefs.GetString("AstarServerMessage");
if (!string.IsNullOrEmpty(serverMessage)) {
ParseServerMessage(serverMessage);
ShowUpdateWindowIfRelevant();
}
}
}
public static string GetURL (string tag) {
RefreshServerMessage();
string url;
astarServerData.TryGetValue("URL:"+tag, out url);
return url ?? "";
}
/// <summary>Initiate a check for updates now, regardless of when the last check was done</summary>
public static void CheckForUpdatesNow () {
lastUpdateCheck = System.DateTime.UtcNow.AddDays(-5);
// Remove the callback if it already exists
EditorApplication.update -= UpdateCheckLoop;
// Add a callback so that we can parse the message when it has been downloaded
EditorApplication.update += UpdateCheckLoop;
}
/// <summary>
/// Checking for updates...
/// Should be called from EditorApplication.update
/// </summary>
static void UpdateCheckLoop () {
// Go on until the update check has been completed
if (!CheckForUpdates()) {
EditorApplication.update -= UpdateCheckLoop;
}
}
/// <summary>
/// Checks for updates if there was some time since last check.
/// It must be called repeatedly to ensure that the result is processed.
/// Returns: True if an update check is progressing (WWW request)
/// </summary>
static bool CheckForUpdates () {
if (updateCheckDownload != null && updateCheckDownload.isDone) {
if (!string.IsNullOrEmpty(updateCheckDownload.error)) {
Debug.LogWarning("There was an error checking for updates to the A* Pathfinding Project\n" +
"The error might disappear if you switch build target from Webplayer to Standalone because of the webplayer security emulation\nError: " +
updateCheckDownload.error);
updateCheckDownload = null;
return false;
}
UpdateCheckCompleted(updateCheckDownload.downloadHandler.text);
updateCheckDownload.Dispose();
updateCheckDownload = null;
}
// Check if it is time to check for updates
// Check for updates a bit earlier if we are in play mode or have the AstarPath object in the scene
// as then the collected statistics will be a bit more accurate
var offsetMinutes = (Application.isPlaying && Time.time > 60) || AstarPath.active != null ? -20 : 20;
var minutesUntilUpdate = lastUpdateCheck.AddDays(updateCheckRate).AddMinutes(offsetMinutes).Subtract(System.DateTime.UtcNow).TotalMinutes;
if (minutesUntilUpdate < 0) {
DownloadVersionInfo();
}
return updateCheckDownload != null || minutesUntilUpdate < 10;
}
static void DownloadVersionInfo () {
if (!Application.isPlaying) AstarPath.FindAstarPath();
var script = AstarPath.active != null ? AstarPath.active : UnityCompatibility.FindAnyObjectByType<AstarPath>();
bool mecanim = UnityCompatibility.FindAnyObjectByType<Animator>() != null;
string query = updateURL+
"?v="+AstarPath.Version+
"&pro=1"+
"&check="+updateCheckRate+"&distr="+AstarPath.Distribution+
"&unitypro="+(Application.HasProLicense() ? "1" : "0")+
"&inscene="+(script != null ? "1" : "0")+
"&targetplatform="+EditorUserBuildSettings.activeBuildTarget+
"&devplatform="+Application.platform+
"&mecanim="+(mecanim ? "1" : "0")+
"&hasNavmesh=" + (script != null && script.data.graphs.Any(g => g.GetType().Name == "NavMeshGraph") ? 1 : 0) +
"&hasPoint=" + (script != null && script.data.graphs.Any(g => g.GetType().Name == "PointGraph") ? 1 : 0) +
"&hasGrid=" + (script != null && script.data.graphs.Any(g => g.GetType().Name == "GridGraph") ? 1 : 0) +
"&hasLayered=" + (script != null && script.data.graphs.Any(g => g.GetType().Name == "LayerGridGraph") ? 1 : 0) +
"&hasRecast=" + (script != null && script.data.graphs.Any(g => g.GetType().Name == "RecastGraph") ? 1 : 0) +
"&hasGrid=" + (script != null && script.data.graphs.Any(g => g.GetType().Name == "GridGraph") ? 1 : 0) +
"&hasCustom=" + (script != null && script.data.graphs.Any(g => g != null && !g.GetType().FullName.Contains("Pathfinding.")) ? 1 : 0) +
"&graphCount=" + (script != null ? script.data.graphs.Count(g => g != null) : 0) +
"&unityversion="+Application.unityVersion +
"&branch="+AstarPath.Branch;
updateCheckDownload = UnityWebRequest.Get(query);
updateCheckDownload.SendWebRequest();
lastUpdateCheck = System.DateTime.UtcNow;
}
/// <summary>Handles the data from the update page</summary>
static void UpdateCheckCompleted (string result) {
EditorPrefs.SetString("AstarServerMessage", result);
ParseServerMessage(result);
ShowUpdateWindowIfRelevant();
}
static void ParseServerMessage (string result) {
if (string.IsNullOrEmpty(result)) {
return;
}
hasParsedServerMessage = true;
#if ASTARDEBUG
Debug.Log("Result from update check:\n"+result);
#endif
string[] splits = result.Split('|');
latestVersionDescription = splits.Length > 1 ? splits[1] : "";
if (splits.Length > 4) {
// First 4 are just compatibility fields
var fields = splits.Skip(4).ToArray();
// Take all pairs of fields
for (int i = 0; i < (fields.Length/2)*2; i += 2) {
string key = fields[i];
string val = fields[i+1];
astarServerData[key] = val;
}
}
try {
latestVersion = new System.Version(astarServerData["VERSION:branch"]);
} catch (System.Exception ex) {
Debug.LogWarning("Could not parse version\n"+ex);
}
try {
latestBetaVersion = new System.Version(astarServerData["VERSION:beta"]);
} catch (System.Exception ex) {
Debug.LogWarning("Could not parse version\n"+ex);
}
}
static void ShowUpdateWindowIfRelevant () {
#if !ASTAR_ATAVISM
try {
System.DateTime remindDate;
var remindVersion = new System.Version(EditorPrefs.GetString("AstarRemindUpdateVersion", "0.0.0.0"));
if (latestVersion == remindVersion && System.DateTime.TryParse(EditorPrefs.GetString("AstarRemindUpdateDate", "1/1/1971 00:00:01"), out remindDate)) {
if (System.DateTime.UtcNow < remindDate) {
// Don't remind yet
return;
}
} else {
EditorPrefs.DeleteKey("AstarRemindUpdateDate");
EditorPrefs.DeleteKey("AstarRemindUpdateVersion");
}
} catch {
Debug.LogError("Invalid AstarRemindUpdateVersion or AstarRemindUpdateDate");
}
var skipVersion = new System.Version(EditorPrefs.GetString("AstarSkipUpToVersion", AstarPath.Version.ToString()));
if (AstarPathEditor.FullyDefinedVersion(latestVersion) != AstarPathEditor.FullyDefinedVersion(skipVersion) && AstarPathEditor.FullyDefinedVersion(latestVersion) > AstarPathEditor.FullyDefinedVersion(AstarPath.Version)) {
EditorPrefs.DeleteKey("AstarSkipUpToVersion");
EditorPrefs.DeleteKey("AstarRemindUpdateDate");
EditorPrefs.DeleteKey("AstarRemindUpdateVersion");
AstarUpdateWindow.Init(latestVersion, latestVersionDescription);
}
#endif
}
}
}
|