context: using UnityEngine;
  using System.Collections.Generic;
  using Pathfinding.Serialization;
  
  namespace Pathfinding {
  	public delegate void GraphNodeDelegate (GraphNode node);
  	public delegate bool GraphNodeDelegateCancelable (GraphNode node);
  
  	public abstract class GraphNode {
  		/** Internal unique index */
  		private int nodeIndex;
  
  		/** Bitpacked field holding several pieces of data.
  		 * \see Walkable
  		 * \see Area
  		 * \see GraphIndex
  		 * \see Tag
  		 */
  		protected uint flags;
  
  		/** Penalty cost for walking on this node.
  		 * This can be used to make it harder/slower to walk over certain nodes.
  		 *
  		 * A penalty of 1000 (Int3.Precision) corresponds to the cost of walking one world unit.
  		 */
  		private uint penalty;
  
  		/** Constructor for a graph node. */
  		protected GraphNode (AstarPath astar) {
  			if (!System.Object.ReferenceEquals(astar, null)) {
  				this.nodeIndex = astar.GetNewNodeIndex();
  				astar.InitializeNode(this);
  			} else {
  				throw new System.Exception("No active AstarPath object to bind to");
  			}
  		}
  
  		/** Destroys the node.
  		 * Cleans up any temporary pathfinding data used for this node.
  		 * The graph is responsible for calling this method on nodes when they are destroyed, including when the whole graph is destoyed.
  		 * Otherwise memory leaks might present themselves.
  		 *
  		 * Once called the #Destroyed property will return true and subsequent calls to this method will not do anything.
  		 *
  		 * \note Assumes the current active AstarPath instance is the same one that created this node.
  		 *
  		 * \warning Should only be called by graph classes on their own nodes
  		 */
  		public void Destroy () {
  			//Already destroyed
  			if (Destroyed) return;
  
  			ClearConnections(true);
  
  			if (AstarPath.active != null) {
  				AstarPath.active.DestroyNode(this);
  			}
  			nodeIndex = -1;
  		}
  
  		public bool Destroyed {
  			get {
  				return nodeIndex == -1;
  			}
  		}
  
  		/** Internal unique index.
  		 * Every node will get a unique index.
  		 * This index is not necessarily correlated with e.g the position of the node in the graph.
  		 */
  		public int NodeIndex { get { return nodeIndex; } }
  
  		/** Position of the node in world space.
  		 * \note The position is stored as an Int3, not a Vector3.
  		 * You can convert an Int3 to a Vector3 using an explicit conversion.
  		 * \code var v3 = (Vector3)node.position; \endcode
  		 */
  		public Int3 position;
  
  		#region Constants
  		/** Position of the walkable bit. \see Walkable */
  		const int FlagsWalkableOffset = 0;
  		/** Mask of the walkable bit. \see Walkable */
  		const uint FlagsWalkableMask = 1 << FlagsWalkableOffset;
  
  		/** Start of area bits. \see Area */
  		const int FlagsAreaOffset = 1;
  		/** Mask of area bits. \see Area */
  		const uint FlagsAreaMask = (131072-1) << FlagsAreaOffset;
  
  		/** Start of graph index bits. \see GraphIndex */
  		const int FlagsGraphOffset = 24;
  		/** Mask of graph index bits. \see GraphIndex */
  		const uint FlagsGraphMask = (256u-1) << FlagsGraphOffset;
  
  		public const uint MaxAreaIndex = FlagsAreaMask >> FlagsAreaOffset;
  		/** Max number of graphs-1 */
  		public const uint MaxGraphIndex = FlagsGraphMask >> FlagsGraphOffset;
  
  		/** Start of tag bits. \see Tag */
  		const int FlagsTagOffset = 19;
  		/** Mask of tag bits. \see Tag */
  		const uint FlagsTagMask = (32-1) << FlagsTagOffset;
  
  		#endregion
  
  
  		#region Properties
  
  		/** Holds various bitpacked variables.
  		 */
  		public uint Flags {
  			get {
  				return flags;
  			}
  			set {
  				flags = value;
  			}
  		}
  
  		/** Penalty cost for walking on this node. This can be used to make it harder/slower to walk over certain areas. */
  		public uint Penalty {
  			get {
  				return penalty;
  			}
  			set {
  				if (value > 0xFFFFFF)
  					Debug.LogWarning("Very high penalty applied. Are you sure negative values haven't underflowed?\n" +
  						"Penalty values this high could with long paths cause overflows and in some cases infinity loops because of that.\n" +
  						"Penalty value applied: "+value);
  				penalty = value;
  			}
  		}
  
  		/** True if the node is traversable */
  		public bool Walkable {
  			get {
  				return (flags & FlagsWalkableMask) != 0;
  			}
  			set {
  				flags = flags & ~FlagsWalkableMask | (value ? 1U : 0U) << FlagsWalkableOffset;
  			}
  		}
  
  		public uint Area {
  			get {
  				return (flags & FlagsAreaMask) >> FlagsAreaOffset;
  			}
  			set {
  				flags = (flags & ~FlagsAreaMask) | (value << FlagsAreaOffset);
  			}
  		}
  
  		public uint GraphIndex {
  			get {
  				return (flags & FlagsGraphMask) >> FlagsGraphOffset;
  			}
  			set {
  				flags = flags & ~FlagsGraphMask | value << FlagsGraphOffset;
  			}
  		}
  
  		public uint Tag {
  			get {
  				return (flags & FlagsTagMask) >> FlagsTagOffset;
  			}
  			set {
  				flags = flags & ~FlagsTagMask | value << FlagsTagOffset;
  			}
  		}
  
  		#endregion
  
  		public void UpdateG (Path path, PathNode pathNode) {
  #if ASTAR_NO_TRAVERSAL_COST
  			pathNode.G = pathNode.parent.G + pathNode.cost;
  #else
  			pathNode.G = pathNode.parent.G + pathNode.cost + path.GetTraversalCost(this);
  #endif
  		}
  
  		public virtual void UpdateRecursiveG (Path path, PathNode pathNode, PathHandler handler) {
  			//Simple but slow default implementation
  			UpdateG(path, pathNode);
  
  			handler.PushNode(pathNode);
  
  			GetConnections(delegate(GraphNode other) {
  				PathNode otherPN = handler.GetPathNode(other);
  				if (otherPN.parent == pathNode && otherPN.pathID == handler.PathID) other.UpdateRecursiveG(path, otherPN, handler);
  			});
  		}
  
  		public virtual void FloodFill (Stack<GraphNode> stack, uint region) {
  			//Simple but slow default implementation
  
  			GetConnections(delegate(GraphNode other) {
  				if (other.Area != region) {
  					other.Area = region;
  					stack.Push(other);
  				}
  			});
  		}
  
  		/** Calls the delegate with all connections from this node */
  		public abstract void GetConnections (GraphNodeDelegate del);
  
  		public abstract void AddConnection (GraphNode node, uint cost);
  		public abstract void RemoveConnection (GraphNode node);
  
  		/** Remove all connections from this node.
  		 * \param alsoReverse if true, neighbours will be requested to remove connections to this node.
  		 */
  		public abstract void ClearConnections (bool alsoReverse);
  
  		/** Checks if this node has a connection to the specified node */
  		public virtual bool ContainsConnection (GraphNode node) {
  			// Simple but slow default implementation
  			bool contains = false;
  
  			GetConnections(neighbour => {
  				contains |= neighbour == node;
  			});
  			return contains;
  		}
  
  		/** Recalculates all connection costs from this node.
  		 * Depending on the node type, this may or may not be supported.
  		 * Nothing will be done if the operation is not supported
  		 * \todo Use interface?
  		 */
  		public virtual void RecalculateConnectionCosts () {
  		}
  
  		/** Add a portal from this node to the specified node.
  		 * This function should add a portal to the left and right lists which is connecting the two nodes (\a this and \a other).
  		 *
  		 * \param other The node which is on the other side of the portal (strictly speaking it does not actually have to be on the other side of the portal though).
  		 * \param left List of portal points on the left side of the funnel
  		 * \param right List of portal points on the right side of the funnel
  		 * \param backwards If this is true, the call was made on a node with the \a other node as the node before this one in the path.
  		 * In this case you may choose to do nothing since a similar call will be made to the \a other node with this node referenced as \a other (but then with backwards = true).
  		 * You do not have to care about switching the left and right lists, that is done for you already.
  		 *
  		 * \returns True if the call was deemed successful. False if some unknown case was encountered and no portal could be added.
  		 * If both calls to node1.GetPortal (node2,...) and node2.GetPortal (node1,...) return false, the funnel modifier will fall back to adding to the path
  		 * the positions of the node.
  		 *
  		 * The default implementation simply returns false.
  		 *
  		 * This function may add more than one portal if necessary.
  		 *
  		 * \see http://digestingduck.blogspot.se/2010/03/simple-stupid-funnel-algorithm.html
  		 */
  		public virtual bool GetPortal (GraphNode other, List<Vector3> left, List<Vector3> right, bool backwards) {
  			return false;
  		}
  
  		/** Open the node */
  		public abstract void Open (Path path, PathNode pathNode, PathHandler handler);
  
  
  
  		public virtual void SerializeNode (GraphSerializationContext ctx) {
  			//Write basic node data.
  			ctx.writer.Write(Penalty);
  			ctx.writer.Write(Flags);
  		}
  
  		public virtual void DeserializeNode (GraphSerializationContext ctx) {
  			Penalty = ctx.reader.ReadUInt32();
  			Flags = ctx.reader.ReadUInt32();
  
  			// Set the correct graph index (which might have changed, e.g if loading additively)
  			GraphIndex = ctx.graphIndex;
  		}
  
  		/** Used to serialize references to other nodes e.g connections.
  		 * Use the GraphSerializationContext.GetNodeIdentifier and
  		 * GraphSerializationContext.GetNodeFromIdentifier methods
  		 * for serialization and deserialization respectively.
  		 *
  		 * Nodes must override this method and serialize their connections.
  		 * Graph generators do not need to call this method, it will be called automatically on all
  		 * nodes at the correct time by the serializer.
  		 */
  		public virtual void SerializeReferences (GraphSerializationContext ctx) {
  		}
  
  		/** Used to deserialize references to other nodes e.g connections.
  		 * Use the GraphSerializationContext.GetNodeIdentifier and
  		 * GraphSerializationContext.GetNodeFromIdentifier methods
  		 * for serialization and deserialization respectively.
  		 *
  		 * Nodes must override this method and serialize their connections.
  		 * Graph generators do not need to call this method, it will be called automatically on all
  		 * nodes at the correct time by the serializer.
  		 */
  		public virtual void DeserializeReferences (GraphSerializationContext ctx) {
  		}
  	}
  
  	public abstract class MeshNode : GraphNode {
  		protected MeshNode (AstarPath astar) : base(astar) {
  		}
  
  		public GraphNode[] connections;
  		public uint[] connectionCosts;
  
  		public abstract Int3 GetVertex (int i);
  		public abstract int GetVertexCount ();
  		public abstract Vector3 ClosestPointOnNode (Vector3 p);
  		public abstract Vector3 ClosestPointOnNodeXZ (Vector3 p);
  
  		public override void ClearConnections (bool alsoReverse) {
  			// Remove all connections to this node from our neighbours
  			if (alsoReverse && connections != null) {
  				for (int i = 0; i < connections.Length; i++) {
  					connections[i].RemoveConnection(this);
  				}
  			}
  
  			connections = null;
  			connectionCosts = null;
  		}
  
  		public override void GetConnections (GraphNodeDelegate del) {
  			if (connections == null) return;
  			for (int i = 0; i < connections.Length; i++) del(connections[i]);
  		}
  
  		public override void FloodFill (Stack<GraphNode> stack, uint region) {
  			//Faster, more specialized implementation to override the slow default implementation
  			if (connections == null) return;
  
  			// Iterate through all connections, set the area and push the neighbour to the stack
  			// This is a simple DFS (https://en.wikipedia.org/wiki/Depth-first_search)
  			for (int i = 0; i < connections.Length; i++) {
  				GraphNode other = connections[i];
  
gt: 				if (other.Area != region) {