AstarData.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732
  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Pathfinding.WindowsStore;
  5. #if UNITY_WINRT && !UNITY_EDITOR
  6. //using MarkerMetro.Unity.WinLegacy.IO;
  7. //using MarkerMetro.Unity.WinLegacy.Reflection;
  8. #endif
  9. namespace Pathfinding {
  10. [System.Serializable]
  11. /// <summary>
  12. /// Stores the navigation graphs for the A* Pathfinding System.
  13. /// \ingroup relevant
  14. ///
  15. /// An instance of this class is assigned to AstarPath.data, from it you can access all graphs loaded through the <see cref="graphs"/> variable.\n
  16. /// This class also handles a lot of the high level serialization.
  17. /// </summary>
  18. public class AstarData {
  19. /// <summary>Shortcut to AstarPath.active</summary>
  20. public static AstarPath active {
  21. get {
  22. return AstarPath.active;
  23. }
  24. }
  25. #region Fields
  26. /// <summary>
  27. /// Shortcut to the first NavMeshGraph.
  28. /// Updated at scanning time
  29. /// </summary>
  30. public NavMeshGraph navmesh { get; private set; }
  31. #if !ASTAR_NO_GRID_GRAPH
  32. /// <summary>
  33. /// Shortcut to the first GridGraph.
  34. /// Updated at scanning time
  35. /// </summary>
  36. public GridGraph gridGraph { get; private set; }
  37. #endif
  38. #if !ASTAR_NO_POINT_GRAPH
  39. /// <summary>
  40. /// Shortcut to the first PointGraph.
  41. /// Updated at scanning time
  42. /// </summary>
  43. public PointGraph pointGraph { get; private set; }
  44. #endif
  45. /// <summary>
  46. /// All supported graph types.
  47. /// Populated through reflection search
  48. /// </summary>
  49. public System.Type[] graphTypes { get; private set; }
  50. #if ASTAR_FAST_NO_EXCEPTIONS || UNITY_WINRT || UNITY_WEBGL
  51. /// <summary>
  52. /// Graph types to use when building with Fast But No Exceptions for iPhone.
  53. /// If you add any custom graph types, you need to add them to this hard-coded list.
  54. /// </summary>
  55. public static readonly System.Type[] DefaultGraphTypes = new System.Type[] {
  56. #if !ASTAR_NO_GRID_GRAPH
  57. typeof(GridGraph),
  58. #endif
  59. #if !ASTAR_NO_POINT_GRAPH
  60. typeof(PointGraph),
  61. #endif
  62. typeof(NavMeshGraph),
  63. };
  64. #endif
  65. /// <summary>
  66. /// All graphs this instance holds.
  67. /// This will be filled only after deserialization has completed.
  68. /// May contain null entries if graph have been removed.
  69. /// </summary>
  70. [System.NonSerialized]
  71. public NavGraph[] graphs = new NavGraph[0];
  72. //Serialization Settings
  73. /// <summary>
  74. /// Serialized data for all graphs and settings.
  75. /// Stored as a base64 encoded string because otherwise Unity's Undo system would sometimes corrupt the byte data (because it only stores deltas).
  76. ///
  77. /// This can be accessed as a byte array from the <see cref="data"/> property.
  78. ///
  79. /// \since 3.6.1
  80. /// </summary>
  81. [SerializeField]
  82. string dataString;
  83. /// <summary>
  84. /// Data from versions from before 3.6.1.
  85. /// Used for handling upgrades
  86. /// \since 3.6.1
  87. /// </summary>
  88. [SerializeField]
  89. [UnityEngine.Serialization.FormerlySerializedAs("data")]
  90. private byte[] upgradeData;
  91. /// <summary>Serialized data for all graphs and settings</summary>
  92. private byte[] data {
  93. get {
  94. // Handle upgrading from earlier versions than 3.6.1
  95. if (upgradeData != null && upgradeData.Length > 0) {
  96. data = upgradeData;
  97. upgradeData = null;
  98. }
  99. return dataString != null ? System.Convert.FromBase64String(dataString) : null;
  100. }
  101. set {
  102. dataString = value != null ? System.Convert.ToBase64String(value) : null;
  103. }
  104. }
  105. /// <summary>
  106. /// Serialized data for cached startup.
  107. /// If set, on start the graphs will be deserialized from this file.
  108. /// </summary>
  109. public TextAsset file_cachedStartup;
  110. /// <summary>
  111. /// Serialized data for cached startup.
  112. ///
  113. /// Deprecated: Deprecated since 3.6, AstarData.file_cachedStartup is now used instead
  114. /// </summary>
  115. public byte[] data_cachedStartup;
  116. /// <summary>
  117. /// Should graph-data be cached.
  118. /// Caching the startup means saving the whole graphs - not only the settings - to a file (<see cref="file_cachedStartup)"/> which can
  119. /// be loaded when the game starts. This is usually much faster than scanning the graphs when the game starts. This is configured from the editor under the "Save & Load" tab.
  120. ///
  121. /// See: save-load-graphs (view in online documentation for working links)
  122. /// </summary>
  123. [SerializeField]
  124. public bool cacheStartup;
  125. //End Serialization Settings
  126. List<bool> graphStructureLocked = new List<bool>();
  127. #endregion
  128. public byte[] GetData () {
  129. return data;
  130. }
  131. public void SetData (byte[] data) {
  132. this.data = data;
  133. }
  134. /// <summary>Loads the graphs from memory, will load cached graphs if any exists</summary>
  135. public void Awake () {
  136. graphs = new NavGraph[0];
  137. if (cacheStartup && file_cachedStartup != null) {
  138. LoadFromCache();
  139. } else {
  140. DeserializeGraphs();
  141. }
  142. }
  143. /// <summary>
  144. /// Prevent the graph structure from changing during the time this lock is held.
  145. /// This prevents graphs from being added or removed and also prevents graphs from being serialized or deserialized.
  146. /// This is used when e.g an async scan is happening to ensure that for example a graph that is being scanned is not destroyed.
  147. ///
  148. /// Each call to this method *must* be paired with exactly one call to <see cref="UnlockGraphStructure"/>.
  149. /// The calls may be nested.
  150. /// </summary>
  151. internal void LockGraphStructure (bool allowAddingGraphs = false) {
  152. graphStructureLocked.Add(allowAddingGraphs);
  153. }
  154. /// <summary>
  155. /// Allows the graph structure to change again.
  156. /// See: <see cref="LockGraphStructure"/>
  157. /// </summary>
  158. internal void UnlockGraphStructure () {
  159. if (graphStructureLocked.Count == 0) throw new System.InvalidOperationException();
  160. graphStructureLocked.RemoveAt(graphStructureLocked.Count - 1);
  161. }
  162. PathProcessor.GraphUpdateLock AssertSafe (bool onlyAddingGraph = false) {
  163. if (graphStructureLocked.Count > 0) {
  164. bool allowAdding = true;
  165. for (int i = 0; i < graphStructureLocked.Count; i++) allowAdding &= graphStructureLocked[i];
  166. if (!(onlyAddingGraph && allowAdding)) throw new System.InvalidOperationException("Graphs cannot be added, removed or serialized while the graph structure is locked. This is the case when a graph is currently being scanned and when executing graph updates and work items.\nHowever as a special case, graphs can be added inside work items.");
  167. }
  168. // Pause the pathfinding threads
  169. var graphLock = active.PausePathfinding();
  170. if (!active.IsInsideWorkItem) {
  171. // Make sure all graph updates and other callbacks are done
  172. // Only do this if this code is not being called from a work item itself as that would cause a recursive wait that could never complete.
  173. // There are some valid cases when this can happen. For example it may be necessary to add a new graph inside a work item.
  174. active.FlushWorkItems();
  175. // Paths that are already calculated and waiting to be returned to the Seeker component need to be
  176. // processed immediately as their results usually depend on graphs that currently exist. If this was
  177. // not done then after destroying a graph one could get a path result with destroyed nodes in it.
  178. active.pathReturnQueue.ReturnPaths(false);
  179. }
  180. return graphLock;
  181. }
  182. /// <summary>
  183. /// Calls the callback with every node in all graphs.
  184. /// This is the easiest way to iterate through every existing node.
  185. ///
  186. /// <code>
  187. /// AstarPath.active.data.GetNodes(node => {
  188. /// Debug.Log("I found a node at position " + (Vector3)node.position);
  189. /// });
  190. /// </code>
  191. ///
  192. /// See: <see cref="Pathfinding.NavGraph.GetNodes"/> for getting the nodes of a single graph instead of all.
  193. /// See: graph-updates (view in online documentation for working links)
  194. /// </summary>
  195. public void GetNodes (System.Action<GraphNode> callback) {
  196. for (int i = 0; i < graphs.Length; i++) {
  197. if (graphs[i] != null) graphs[i].GetNodes(callback);
  198. }
  199. }
  200. /// <summary>
  201. /// Updates shortcuts to the first graph of different types.
  202. /// Hard coding references to some graph types is not really a good thing imo. I want to keep it dynamic and flexible.
  203. /// But these references ease the use of the system, so I decided to keep them.
  204. /// </summary>
  205. public void UpdateShortcuts () {
  206. navmesh = (NavMeshGraph)FindGraphOfType(typeof(NavMeshGraph));
  207. #if !ASTAR_NO_GRID_GRAPH
  208. gridGraph = (GridGraph)FindGraphOfType(typeof(GridGraph));
  209. #endif
  210. #if !ASTAR_NO_POINT_GRAPH
  211. pointGraph = (PointGraph)FindGraphOfType(typeof(PointGraph));
  212. #endif
  213. }
  214. /// <summary>Load from data from <see cref="file_cachedStartup"/></summary>
  215. public void LoadFromCache () {
  216. var graphLock = AssertSafe();
  217. if (file_cachedStartup != null) {
  218. var bytes = file_cachedStartup.bytes;
  219. DeserializeGraphs(bytes);
  220. GraphModifier.TriggerEvent(GraphModifier.EventType.PostCacheLoad);
  221. } else {
  222. Debug.LogError("Can't load from cache since the cache is empty");
  223. }
  224. graphLock.Release();
  225. }
  226. #region Serialization
  227. /// <summary>
  228. /// Serializes all graphs settings to a byte array.
  229. /// See: DeserializeGraphs(byte[])
  230. /// </summary>
  231. public byte[] SerializeGraphs () {
  232. return SerializeGraphs(Pathfinding.Serialization.SerializeSettings.Settings);
  233. }
  234. /// <summary>
  235. /// Serializes all graphs settings and optionally node data to a byte array.
  236. /// See: DeserializeGraphs(byte[])
  237. /// See: Pathfinding.Serialization.SerializeSettings
  238. /// </summary>
  239. public byte[] SerializeGraphs (Pathfinding.Serialization.SerializeSettings settings) {
  240. uint checksum;
  241. return SerializeGraphs(settings, out checksum);
  242. }
  243. /// <summary>
  244. /// Main serializer function.
  245. /// Serializes all graphs to a byte array
  246. /// A similar function exists in the AstarPathEditor.cs script to save additional info
  247. /// </summary>
  248. public byte[] SerializeGraphs (Pathfinding.Serialization.SerializeSettings settings, out uint checksum) {
  249. var graphLock = AssertSafe();
  250. var sr = new Pathfinding.Serialization.AstarSerializer(this, settings);
  251. sr.OpenSerialize();
  252. sr.SerializeGraphs(graphs);
  253. sr.SerializeExtraInfo();
  254. byte[] bytes = sr.CloseSerialize();
  255. checksum = sr.GetChecksum();
  256. #if ASTARDEBUG
  257. Debug.Log("Got a whole bunch of data, "+bytes.Length+" bytes");
  258. #endif
  259. graphLock.Release();
  260. return bytes;
  261. }
  262. /// <summary>Deserializes graphs from <see cref="data"/></summary>
  263. public void DeserializeGraphs () {
  264. if (data != null) {
  265. DeserializeGraphs(data);
  266. }
  267. }
  268. /// <summary>Destroys all graphs and sets graphs to null</summary>
  269. void ClearGraphs () {
  270. if (graphs == null) return;
  271. for (int i = 0; i < graphs.Length; i++) {
  272. if (graphs[i] != null) {
  273. ((IGraphInternals)graphs[i]).OnDestroy();
  274. graphs[i].active = null;
  275. }
  276. }
  277. graphs = null;
  278. UpdateShortcuts();
  279. }
  280. public void OnDestroy () {
  281. ClearGraphs();
  282. }
  283. /// <summary>
  284. /// Deserializes graphs from the specified byte array.
  285. /// An error will be logged if deserialization fails.
  286. /// </summary>
  287. public void DeserializeGraphs (byte[] bytes) {
  288. var graphLock = AssertSafe();
  289. ClearGraphs();
  290. DeserializeGraphsAdditive(bytes);
  291. graphLock.Release();
  292. }
  293. /// <summary>
  294. /// Deserializes graphs from the specified byte array additively.
  295. /// An error will be logged if deserialization fails.
  296. /// This function will add loaded graphs to the current ones.
  297. /// </summary>
  298. public void DeserializeGraphsAdditive (byte[] bytes) {
  299. var graphLock = AssertSafe();
  300. try {
  301. if (bytes != null) {
  302. var sr = new Pathfinding.Serialization.AstarSerializer(this);
  303. if (sr.OpenDeserialize(bytes)) {
  304. DeserializeGraphsPartAdditive(sr);
  305. sr.CloseDeserialize();
  306. } else {
  307. Debug.Log("Invalid data file (cannot read zip).\nThe data is either corrupt or it was saved using a 3.0.x or earlier version of the system");
  308. }
  309. } else {
  310. throw new System.ArgumentNullException("bytes");
  311. }
  312. active.VerifyIntegrity();
  313. } catch (System.Exception e) {
  314. Debug.LogError("Caught exception while deserializing data.\n"+e);
  315. graphs = new NavGraph[0];
  316. }
  317. UpdateShortcuts();
  318. graphLock.Release();
  319. }
  320. /// <summary>Helper function for deserializing graphs</summary>
  321. void DeserializeGraphsPartAdditive (Pathfinding.Serialization.AstarSerializer sr) {
  322. if (graphs == null) graphs = new NavGraph[0];
  323. var gr = new List<NavGraph>(graphs);
  324. // Set an offset so that the deserializer will load
  325. // the graphs with the correct graph indexes
  326. sr.SetGraphIndexOffset(gr.Count);
  327. if (graphTypes == null) FindGraphTypes();
  328. gr.AddRange(sr.DeserializeGraphs(graphTypes));
  329. graphs = gr.ToArray();
  330. sr.DeserializeEditorSettingsCompatibility();
  331. sr.DeserializeExtraInfo();
  332. //Assign correct graph indices.
  333. for (int i = 0; i < graphs.Length; i++) {
  334. if (graphs[i] == null) continue;
  335. graphs[i].GetNodes(node => node.GraphIndex = (uint)i);
  336. }
  337. for (int i = 0; i < graphs.Length; i++) {
  338. for (int j = i+1; j < graphs.Length; j++) {
  339. if (graphs[i] != null && graphs[j] != null && graphs[i].guid == graphs[j].guid) {
  340. Debug.LogWarning("Guid Conflict when importing graphs additively. Imported graph will get a new Guid.\nThis message is (relatively) harmless.");
  341. graphs[i].guid = Pathfinding.Util.Guid.NewGuid();
  342. break;
  343. }
  344. }
  345. }
  346. sr.PostDeserialization();
  347. active.hierarchicalGraph.RecalculateIfNecessary();
  348. }
  349. #endregion
  350. /// <summary>
  351. /// Find all graph types supported in this build.
  352. /// Using reflection, the assembly is searched for types which inherit from NavGraph.
  353. /// </summary>
  354. public void FindGraphTypes () {
  355. #if !ASTAR_FAST_NO_EXCEPTIONS && !UNITY_WINRT && !UNITY_WEBGL
  356. var graphList = new List<System.Type>();
  357. foreach (var assembly in System.AppDomain.CurrentDomain.GetAssemblies()) {
  358. System.Type[] types = null;
  359. try {
  360. types = assembly.GetTypes();
  361. } catch {
  362. // Ignore type load exceptions and things like that.
  363. // We might not be able to read all assemblies for some reason, but hopefully the relevant types exist in the assemblies that we can read
  364. continue;
  365. }
  366. foreach (var type in types) {
  367. #if NETFX_CORE && !UNITY_EDITOR
  368. System.Type baseType = type.GetTypeInfo().BaseType;
  369. #else
  370. var baseType = type.BaseType;
  371. #endif
  372. while (baseType != null) {
  373. if (System.Type.Equals(baseType, typeof(NavGraph))) {
  374. graphList.Add(type);
  375. break;
  376. }
  377. #if NETFX_CORE && !UNITY_EDITOR
  378. baseType = baseType.GetTypeInfo().BaseType;
  379. #else
  380. baseType = baseType.BaseType;
  381. #endif
  382. }
  383. }
  384. }
  385. graphTypes = graphList.ToArray();
  386. #if ASTARDEBUG
  387. Debug.Log("Found "+graphTypes.Length+" graph types");
  388. #endif
  389. #else
  390. graphTypes = DefaultGraphTypes;
  391. #endif
  392. }
  393. #region GraphCreation
  394. /// <summary>
  395. /// Returns: A System.Type which matches the specified type string. If no mathing graph type was found, null is returned
  396. ///
  397. /// Deprecated:
  398. /// </summary>
  399. [System.Obsolete("If really necessary. Use System.Type.GetType instead.")]
  400. public System.Type GetGraphType (string type) {
  401. for (int i = 0; i < graphTypes.Length; i++) {
  402. if (graphTypes[i].Name == type) {
  403. return graphTypes[i];
  404. }
  405. }
  406. return null;
  407. }
  408. /// <summary>
  409. /// Creates a new instance of a graph of type type. If no matching graph type was found, an error is logged and null is returned
  410. /// Returns: The created graph
  411. /// See: <see cref="CreateGraph(System.Type)"/>
  412. ///
  413. /// Deprecated:
  414. /// </summary>
  415. [System.Obsolete("Use CreateGraph(System.Type) instead")]
  416. public NavGraph CreateGraph (string type) {
  417. Debug.Log("Creating Graph of type '"+type+"'");
  418. for (int i = 0; i < graphTypes.Length; i++) {
  419. if (graphTypes[i].Name == type) {
  420. return CreateGraph(graphTypes[i]);
  421. }
  422. }
  423. Debug.LogError("Graph type ("+type+") wasn't found");
  424. return null;
  425. }
  426. /// <summary>
  427. /// Creates a new graph instance of type type
  428. /// See: <see cref="CreateGraph(string)"/>
  429. /// </summary>
  430. internal NavGraph CreateGraph (System.Type type) {
  431. var graph = System.Activator.CreateInstance(type) as NavGraph;
  432. graph.active = active;
  433. return graph;
  434. }
  435. /// <summary>
  436. /// Adds a graph of type type to the <see cref="graphs"/> array
  437. ///
  438. /// Deprecated:
  439. /// </summary>
  440. [System.Obsolete("Use AddGraph(System.Type) instead")]
  441. public NavGraph AddGraph (string type) {
  442. NavGraph graph = null;
  443. for (int i = 0; i < graphTypes.Length; i++) {
  444. if (graphTypes[i].Name == type) {
  445. graph = CreateGraph(graphTypes[i]);
  446. }
  447. }
  448. if (graph == null) {
  449. Debug.LogError("No NavGraph of type '"+type+"' could be found");
  450. return null;
  451. }
  452. AddGraph(graph);
  453. return graph;
  454. }
  455. /// <summary>
  456. /// Adds a graph of type type to the <see cref="graphs"/> array.
  457. /// See: runtime-graphs (view in online documentation for working links)
  458. /// </summary>
  459. public NavGraph AddGraph (System.Type type) {
  460. NavGraph graph = null;
  461. for (int i = 0; i < graphTypes.Length; i++) {
  462. if (System.Type.Equals(graphTypes[i], type)) {
  463. graph = CreateGraph(graphTypes[i]);
  464. }
  465. }
  466. if (graph == null) {
  467. Debug.LogError("No NavGraph of type '"+type+"' could be found, "+graphTypes.Length+" graph types are avaliable");
  468. return null;
  469. }
  470. AddGraph(graph);
  471. return graph;
  472. }
  473. /// <summary>Adds the specified graph to the <see cref="graphs"/> array</summary>
  474. void AddGraph (NavGraph graph) {
  475. // Make sure to not interfere with pathfinding
  476. var graphLock = AssertSafe(true);
  477. // Try to fill in an empty position
  478. bool foundEmpty = false;
  479. for (int i = 0; i < graphs.Length; i++) {
  480. if (graphs[i] == null) {
  481. graphs[i] = graph;
  482. graph.graphIndex = (uint)i;
  483. foundEmpty = true;
  484. break;
  485. }
  486. }
  487. if (!foundEmpty) {
  488. if (graphs != null && graphs.Length >= GraphNode.MaxGraphIndex) {
  489. throw new System.Exception("Graph Count Limit Reached. You cannot have more than " + GraphNode.MaxGraphIndex + " graphs.");
  490. }
  491. // Add a new entry to the list
  492. var graphList = new List<NavGraph>(graphs ?? new NavGraph[0]);
  493. graphList.Add(graph);
  494. graphs = graphList.ToArray();
  495. graph.graphIndex = (uint)(graphs.Length-1);
  496. }
  497. UpdateShortcuts();
  498. graph.active = active;
  499. graphLock.Release();
  500. }
  501. /// <summary>
  502. /// Removes the specified graph from the <see cref="graphs"/> array and Destroys it in a safe manner.
  503. /// To avoid changing graph indices for the other graphs, the graph is simply nulled in the array instead
  504. /// of actually removing it from the array.
  505. /// The empty position will be reused if a new graph is added.
  506. ///
  507. /// Returns: True if the graph was sucessfully removed (i.e it did exist in the <see cref="graphs"/> array). False otherwise.
  508. ///
  509. /// Version: Changed in 3.2.5 to call SafeOnDestroy before removing
  510. /// and nulling it in the array instead of removing the element completely in the <see cref="graphs"/> array.
  511. /// </summary>
  512. public bool RemoveGraph (NavGraph graph) {
  513. // Make sure the pathfinding threads are stopped
  514. // If we don't wait until pathfinding that is potentially running on
  515. // this graph right now we could end up with NullReferenceExceptions
  516. var graphLock = AssertSafe();
  517. ((IGraphInternals)graph).OnDestroy();
  518. graph.active = null;
  519. int i = System.Array.IndexOf(graphs, graph);
  520. if (i != -1) graphs[i] = null;
  521. UpdateShortcuts();
  522. graphLock.Release();
  523. return i != -1;
  524. }
  525. #endregion
  526. #region GraphUtility
  527. /// <summary>
  528. /// Returns the graph which contains the specified node.
  529. /// The graph must be in the <see cref="graphs"/> array.
  530. ///
  531. /// Returns: Returns the graph which contains the node. Null if the graph wasn't found
  532. /// </summary>
  533. public static NavGraph GetGraph (GraphNode node) {
  534. if (node == null) return null;
  535. AstarPath script = AstarPath.active;
  536. if (script == null) return null;
  537. AstarData data = script.data;
  538. if (data == null || data.graphs == null) return null;
  539. uint graphIndex = node.GraphIndex;
  540. if (graphIndex >= data.graphs.Length) {
  541. return null;
  542. }
  543. return data.graphs[(int)graphIndex];
  544. }
  545. /// <summary>Returns the first graph which satisfies the predicate. Returns null if no graph was found.</summary>
  546. public NavGraph FindGraph (System.Func<NavGraph, bool> predicate) {
  547. if (graphs != null) {
  548. for (int i = 0; i < graphs.Length; i++) {
  549. if (graphs[i] != null && predicate(graphs[i])) {
  550. return graphs[i];
  551. }
  552. }
  553. }
  554. return null;
  555. }
  556. /// <summary>Returns the first graph of type type found in the <see cref="graphs"/> array. Returns null if no graph was found.</summary>
  557. public NavGraph FindGraphOfType (System.Type type) {
  558. return FindGraph(graph => System.Type.Equals(graph.GetType(), type));
  559. }
  560. /// <summary>Returns the first graph which inherits from the type type. Returns null if no graph was found.</summary>
  561. public NavGraph FindGraphWhichInheritsFrom (System.Type type) {
  562. return FindGraph(graph => WindowsStoreCompatibility.GetTypeInfo(type).IsAssignableFrom(WindowsStoreCompatibility.GetTypeInfo(graph.GetType())));
  563. }
  564. /// <summary>
  565. /// Loop through this function to get all graphs of type 'type'
  566. /// <code>
  567. /// foreach (GridGraph graph in AstarPath.data.FindGraphsOfType (typeof(GridGraph))) {
  568. /// //Do something with the graph
  569. /// }
  570. /// </code>
  571. /// See: AstarPath.RegisterSafeNodeUpdate
  572. /// </summary>
  573. public IEnumerable FindGraphsOfType (System.Type type) {
  574. if (graphs == null) yield break;
  575. for (int i = 0; i < graphs.Length; i++) {
  576. if (graphs[i] != null && System.Type.Equals(graphs[i].GetType(), type)) {
  577. yield return graphs[i];
  578. }
  579. }
  580. }
  581. /// <summary>
  582. /// All graphs which implements the UpdateableGraph interface
  583. /// <code> foreach (IUpdatableGraph graph in AstarPath.data.GetUpdateableGraphs ()) {
  584. /// //Do something with the graph
  585. /// } </code>
  586. /// See: AstarPath.AddWorkItem
  587. /// See: Pathfinding.IUpdatableGraph
  588. /// </summary>
  589. public IEnumerable GetUpdateableGraphs () {
  590. if (graphs == null) yield break;
  591. for (int i = 0; i < graphs.Length; i++) {
  592. if (graphs[i] is IUpdatableGraph) {
  593. yield return graphs[i];
  594. }
  595. }
  596. }
  597. /// <summary>
  598. /// All graphs which implements the UpdateableGraph interface
  599. /// <code> foreach (IRaycastableGraph graph in AstarPath.data.GetRaycastableGraphs ()) {
  600. /// //Do something with the graph
  601. /// } </code>
  602. /// See: Pathfinding.IRaycastableGraph
  603. /// Deprecated: Deprecated because it is not used by the package internally and the use cases are few. Iterate through the <see cref="graphs"/> array instead.
  604. /// </summary>
  605. [System.Obsolete("Obsolete because it is not used by the package internally and the use cases are few. Iterate through the graphs array instead.")]
  606. public IEnumerable GetRaycastableGraphs () {
  607. if (graphs == null) yield break;
  608. for (int i = 0; i < graphs.Length; i++) {
  609. if (graphs[i] is IRaycastableGraph) {
  610. yield return graphs[i];
  611. }
  612. }
  613. }
  614. /// <summary>Gets the index of the NavGraph in the <see cref="graphs"/> array</summary>
  615. public int GetGraphIndex (NavGraph graph) {
  616. if (graph == null) throw new System.ArgumentNullException("graph");
  617. var index = -1;
  618. if (graphs != null) {
  619. index = System.Array.IndexOf(graphs, graph);
  620. if (index == -1) Debug.LogError("Graph doesn't exist");
  621. }
  622. return index;
  623. }
  624. #endregion
  625. }
  626. }