context: using System;
  using System.IO;
  using System.Collections.Generic;
  using UnityEngine;
  using Pathfinding;
  using Pathfinding.Util;
  #if NETFX_CORE && !UNITY_EDITOR
  #if !ASTAR_NO_ZIP
  using Pathfinding.Ionic.Zip;
  #else
  using Pathfinding.Serialization.Zip;
  #endif
  
  #else
  using CompatFileStream = System.IO.FileStream;
  
  #if !ASTAR_NO_ZIP
  using Pathfinding.Ionic.Zip;
  #else
  using Pathfinding.Serialization.Zip;
  #endif
  #endif
  
  
  namespace Pathfinding.Serialization {
  	/** Holds information passed to custom graph serializers */
  	public class GraphSerializationContext {
  		private readonly GraphNode[] id2NodeMapping;
  
  		/** Deserialization stream.
  		 * Will only be set when deserializing
  		 */
  		public readonly BinaryReader reader;
  
  		/** Serialization stream.
  		 * Will only be set when serializing
  		 */
  		public readonly BinaryWriter writer;
  
  		/** Index of the graph which is currently being processed.
  		 * \version uint instead of int after 3.7.5
  		 */
  		public readonly uint graphIndex;
  
  		/** Metadata about graphs being deserialized */
  		public readonly GraphMeta meta;
  
  		public GraphSerializationContext (BinaryReader reader, GraphNode[] id2NodeMapping, uint graphIndex, GraphMeta meta) {
  			this.reader = reader;
  			this.id2NodeMapping = id2NodeMapping;
  			this.graphIndex = graphIndex;
  			this.meta = meta;
  		}
  
  		public GraphSerializationContext (BinaryWriter writer) {
  			this.writer = writer;
  		}
  
  		public void SerializeNodeReference (GraphNode node) {
  			writer.Write(node == null ? -1 : node.NodeIndex);
  		}
  
  		public GraphNode DeserializeNodeReference () {
  			var id = reader.ReadInt32();
  
  			if (id2NodeMapping == null) throw new Exception("Calling DeserializeNodeReference when serializing");
  
  			if (id == -1) return null;
  			GraphNode node = id2NodeMapping[id];
  			if (node == null) throw new Exception("Invalid id ("+id+")");
  			return node;
  		}
  
  		/** Write a Vector3 */
  		public void SerializeVector3 (Vector3 v) {
  			writer.Write(v.x);
  			writer.Write(v.y);
  			writer.Write(v.z);
  		}
  
  		/** Read a Vector3 */
  		public Vector3 DeserializeVector3 () {
  			return new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
  		}
  
  		/** Write an Int3 */
  		public void SerializeInt3 (Int3 v) {
  			writer.Write(v.x);
  			writer.Write(v.y);
  			writer.Write(v.z);
  		}
  
  		/** Read an Int3 */
  		public Int3 DeserializeInt3 () {
  			return new Int3(reader.ReadInt32(), reader.ReadInt32(), reader.ReadInt32());
  		}
  
  		public int DeserializeInt (int defaultValue) {
  			if (reader.BaseStream.Position <= reader.BaseStream.Length-4) {
  				return reader.ReadInt32();
  			} else {
  				return defaultValue;
  			}
  		}
  
  		public float DeserializeFloat (float defaultValue) {
  			if (reader.BaseStream.Position <= reader.BaseStream.Length-4) {
  				return reader.ReadSingle();
  			} else {
  				return defaultValue;
  			}
  		}
  
  		/** Read a UnityEngine.Object */
  		public UnityEngine.Object DeserializeUnityObject ( ) {
  			int inst = reader.ReadInt32();
  
  			if (inst == int.MaxValue) {
  				return null;
  			}
  
  			string name = reader.ReadString();
  			string typename = reader.ReadString();
  			string guid = reader.ReadString();
  
  			System.Type type = System.Type.GetType(typename);
  
  			if (type == null) {
  				Debug.LogError("Could not find type '"+typename+"'. Cannot deserialize Unity reference");
  				return null;
  			}
  
  			if (!string.IsNullOrEmpty(guid)) {
  				UnityReferenceHelper[] helpers = UnityEngine.Object.FindObjectsOfType(typeof(UnityReferenceHelper)) as UnityReferenceHelper[];
  
  				for (int i = 0; i < helpers.Length; i++) {
  					if (helpers[i].GetGUID() == guid) {
  						if (type == typeof(GameObject)) {
  							return helpers[i].gameObject;
  						} else {
  							return helpers[i].GetComponent(type);
  						}
  					}
  				}
  			}
  
  			//Try to load from resources
  			UnityEngine.Object[] objs = Resources.LoadAll(name, type);
  
  			for (int i = 0; i < objs.Length; i++) {
  				if (objs[i].name == name || objs.Length == 1) {
  					return objs[i];
  				}
  			}
  
  			return null;
  		}
  	}
  
  	/** Handles low level serialization and deserialization of graph settings and data.
  	 * Mostly for internal use. You can use the methods in the AstarData class for
  	 * higher level serialization and deserialization.
  	 *
  	 * \see AstarData
  	 */
  	public class AstarSerializer {
  		private AstarData data;
  
  		/** Zip which the data is loaded from */
  		private ZipFile zip;
  
  		/** Memory stream with the zip data */
  		private MemoryStream zipStream;
  
  		/** Graph metadata */
  		private GraphMeta meta;
  
  		/** Settings for serialization */
  		private SerializeSettings settings;
  
  		/** Graphs that are being serialized or deserialized */
  		private NavGraph[] graphs;
  
  		/** Index used for the graph in the file.
  		 * If some graphs were null in the file then graphIndexInZip[graphs[i]] may not equal i.
  		 * Used for deserialization.
  		 */
  		private Dictionary<NavGraph, int> graphIndexInZip;
  
  		private int graphIndexOffset;
  
  		/** Extension to use for binary files */
  		const string binaryExt = ".binary";
  
  		/** Extension to use for json files */
  		const string jsonExt = ".json";
  
  		/** Checksum for the serialized data.
  		 * Used to provide a quick equality check in editor code
  		 */
  		private uint checksum = 0xffffffff;
  
  		System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
  
  		/** Cached StringBuilder to avoid excessive allocations */
  		static System.Text.StringBuilder _stringBuilder = new System.Text.StringBuilder();
  
  		/** Returns a cached StringBuilder.
  		 * This function only has one string builder cached and should
  		 * thus only be called from a single thread and should not be called while using an earlier got string builder.
  		 */
  		static System.Text.StringBuilder GetStringBuilder () { _stringBuilder.Length = 0; return _stringBuilder; }
  
  		static void CloseOrDispose (BinaryWriter writer) {
  #if NETFX_CORE
  			writer.Dispose();
  #else
  			writer.Close();
  #endif
  		}
  
  		public AstarSerializer (AstarData data) {
  			this.data = data;
  			settings = SerializeSettings.Settings;
  		}
  
  		public AstarSerializer (AstarData data, SerializeSettings settings) {
  			this.data = data;
  			this.settings = settings;
  		}
  
  		public void SetGraphIndexOffset (int offset) {
  			graphIndexOffset = offset;
  		}
  
  		void AddChecksum (byte[] bytes) {
  			checksum = Checksum.GetChecksum(bytes, checksum);
  		}
  
  		public uint GetChecksum () { return checksum; }
  
  		#region Serialize
  
  		public void OpenSerialize () {
  			// Create a new zip file, here we will store all the data
  			zip = new ZipFile();
  			zip.AlternateEncoding = System.Text.Encoding.UTF8;
  			zip.AlternateEncodingUsage = ZipOption.Always;
  			meta = new GraphMeta();
  		}
  
  		public byte[] CloseSerialize () {
  			// As the last step, serialize metadata
  			byte[] bytes = SerializeMeta();
  			AddChecksum(bytes);
  			zip.AddEntry("meta"+jsonExt, bytes);
  
  #if !ASTAR_NO_ZIP
  			// Set dummy dates on every file to prevent the binary data to change
  			// for identical settings and graphs.
  			// Prevents the scene from being marked as dirty in the editor
  			// If ASTAR_NO_ZIP is defined this is not relevant since the replacement zip
  			// implementation does not even store dates
  			var dummy = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  			foreach (var entry in zip.Entries) {
  				entry.AccessedTime = dummy;
  				entry.CreationTime = dummy;
  				entry.LastModified = dummy;
  				entry.ModifiedTime = dummy;
  			}
  #endif
  
  			// Save all entries to a single byte array
  			var output = new MemoryStream();
  			zip.Save(output);
  			bytes = output.ToArray();
  			output.Dispose();
  			zip.Dispose();
  
  			zip = null;
  			return bytes;
  		}
  
  		public void SerializeGraphs (NavGraph[] _graphs) {
  			if (graphs != null) throw new InvalidOperationException("Cannot serialize graphs multiple times.");
  			graphs = _graphs;
  
  			if (zip == null) throw new NullReferenceException("You must not call CloseSerialize before a call to this function");
  
  			if (graphs == null) graphs = new NavGraph[0];
  
  			for (int i = 0; i < graphs.Length; i++) {
  				//Ignore graph if null
  				if (graphs[i] == null) continue;
  
  				// Serialize the graph to a byte array
  				byte[] bytes = Serialize(graphs[i]);
  
  				AddChecksum(bytes);
  				zip.AddEntry("graph"+i+jsonExt, bytes);
  			}
  		}
  
  		/** Serialize metadata about all graphs */
  		byte[] SerializeMeta () {
  			if (graphs == null) throw new System.Exception("No call to SerializeGraphs has been done");
  
  			meta.version = AstarPath.Version;
  			meta.graphs = graphs.Length;
  			meta.guids = new List<string>();
  			meta.typeNames = new List<string>();
  
  			// For each graph, save the guid
  			// of the graph and the type of it
  			for (int i = 0; i < graphs.Length; i++) {
  				if (graphs[i] != null) {
  					meta.guids.Add(graphs[i].guid.ToString());
  					meta.typeNames.Add(graphs[i].GetType().FullName);
  				} else {
  					meta.guids.Add(null);
  					meta.typeNames.Add(null);
  				}
  			}
  
  			// Grab a cached string builder to avoid allocations
  			var output = GetStringBuilder();
  			TinyJsonSerializer.Serialize(meta, output);
  			return encoding.GetBytes(output.ToString());
  		}
  
  		/** Serializes the graph settings to JSON and returns the data */
  		public byte[] Serialize (NavGraph graph) {
  			// Grab a cached string builder to avoid allocations
  			var output = GetStringBuilder();
  
  			TinyJsonSerializer.Serialize(graph, output);
  			return encoding.GetBytes(output.ToString());
  		}
  
  		/** Deprecated method to serialize node data.
  		 * \deprecated Not used anymore
  		 */
  		[System.Obsolete("Not used anymore. You can safely remove the call to this function.")]
  		public void SerializeNodes () {
  		}
  
  		static int GetMaxNodeIndexInAllGraphs (NavGraph[] graphs) {
  			int maxIndex = 0;
  
  			for (int i = 0; i < graphs.Length; i++) {
  				if (graphs[i] == null) continue;
  				graphs[i].GetNodes(node => {
  					maxIndex = Math.Max(node.NodeIndex, maxIndex);
  					if (node.NodeIndex == -1) {
  						Debug.LogError("Graph contains destroyed nodes. This is a bug.");
  					}
  					return true;
  				});
  			}
  			return maxIndex;
  		}
  
  		static byte[] SerializeNodeIndices (NavGraph[] graphs) {
  			var stream = new MemoryStream();
  			var wr = new BinaryWriter(stream);
  
  			int maxNodeIndex = GetMaxNodeIndexInAllGraphs(graphs);
  
  			wr.Write(maxNodeIndex);
  
  			// While writing node indices, verify that the max node index is the same
  			// (user written graphs might have gotten it wrong)
  			int maxNodeIndex2 = 0;
  			for (int i = 0; i < graphs.Length; i++) {
  				if (graphs[i] == null) continue;
  				graphs[i].GetNodes(node => {
  					maxNodeIndex2 = Math.Max(node.NodeIndex, maxNodeIndex2);
  					wr.Write(node.NodeIndex);
  					return true;
  				});
  			}
  
  			// Nice to verify if users are writing their own graph types
  			if (maxNodeIndex2 != maxNodeIndex) throw new Exception("Some graphs are not consistent in their GetNodes calls, sequential calls give different results.");
  
  			byte[] bytes = stream.ToArray();
  			CloseOrDispose(wr);
  
  			return bytes;
  		}
  
  		/** Serializes info returned by NavGraph.SerializeExtraInfo */
  		static byte[] SerializeGraphExtraInfo (NavGraph graph) {
  			var stream = new MemoryStream();
  			var wr = new BinaryWriter(stream);
  			var ctx = new GraphSerializationContext(wr);
  
  			graph.SerializeExtraInfo(ctx);
  			byte[] bytes = stream.ToArray();
  			CloseOrDispose(wr);
  
  			return bytes;
  		}
  
  		/** Used to serialize references to other nodes e.g connections.
  		 * Nodes use the GraphSerializationContext.GetNodeIdentifier and
  		 * GraphSerializationContext.GetNodeFromIdentifier methods
  		 * for serialization and deserialization respectively.
  		 */
  		static byte[] SerializeGraphNodeReferences (NavGraph graph) {
  			var stream = new MemoryStream();
  			var wr = new BinaryWriter(stream);
  			var ctx = new GraphSerializationContext(wr);
  
  			graph.GetNodes(node => {
  				node.SerializeReferences(ctx);
  				return true;
  			});
  			CloseOrDispose(wr);
  
  			var bytes = stream.ToArray();
  			return bytes;
  		}
  
  		public void SerializeExtraInfo () {
  			if (!settings.nodes) return;
  			if (graphs == null) throw new InvalidOperationException("Cannot serialize extra info with no serialized graphs (call SerializeGraphs first)");
  
  			var bytes = SerializeNodeIndices(graphs);
  			AddChecksum(bytes);
  			zip.AddEntry("graph_references"+binaryExt, bytes);
  
  
gt: 			for (int i = 0; i < graphs.Length; i++) {