public void ReplaceTile (int x, int z, int w, int d, Int3[] verts, int[] tris, bool worldSpace) {

			if(x + w > tileXCount || z+d > tileZCount || x < 0 || z < 0) {
				throw new System.ArgumentException ("Tile is placed at an out of bounds position or extends out of the graph bounds ("+x+", " + z + " [" + w + ", " + d+ "] " + tileXCount + " " + tileZCount + ")");
			}

			if (w < 1 || d < 1) throw new System.ArgumentException ("width and depth must be greater or equal to 1. Was " + w + ", " + d);

			//Remove previous tiles
			for (int cz=z; cz < z+d;cz++) {
				for (int cx=x; cx < x+w;cx++) {

					NavmeshTile otile = tiles[cx + cz*tileXCount];
					if (otile == null) continue;

					//Remove old tile connections
					RemoveConnectionsFromTile (otile);

					for (int i=0;i<otile.nodes.Length;i++) {
						otile.nodes[i].Destroy();
					}

					for (int qz=otile.z; qz < otile.z+otile.d;qz++) {
						for (int qx=otile.x; qx < otile.x+otile.w;qx++) {
							NavmeshTile qtile = tiles[qx + qz*tileXCount];
							if (qtile == null || qtile != otile) throw new System.Exception("This should not happen");

							if (qz < z || qz >= z+d || qx < x || qx >= x+w) {
								//if out of this tile's bounds, replace with empty tile
								tiles[qx + qz*tileXCount] = NewEmptyTile(qx,qz);

								if (batchTileUpdate) {
									batchUpdatedTiles.Add (qx + qz*tileXCount);
								}
							} else {
								//Will be replaced by the new tile
								tiles[qx + qz*tileXCount] = null;
							}
						}
					}
				}
			}

			//Create a new navmesh tile and assign its settings
			var tile = new NavmeshTile();

			tile.x = x;
			tile.z = z;
			tile.w = w;
			tile.d = d;
			tile.tris = tris;
			tile.verts = verts;
			tile.bbTree = new BBTree();

			if (tile.tris.Length % 3 != 0) throw new System.ArgumentException ("Triangle array's length must be a multiple of 3 (tris)");

			if (tile.verts.Length > 0xFFFF) throw new System.ArgumentException ("Too many vertices per tile (more than 65535)");

			if (!worldSpace) {
				if (!Mathf.Approximately (x*tileSizeX*cellSize*Int3.FloatPrecision, (float)Math.Round(x*tileSizeX*cellSize*Int3.FloatPrecision))) Debug.LogWarning ("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");
				if (!Mathf.Approximately (z*tileSizeZ*cellSize*Int3.FloatPrecision, (float)Math.Round(z*tileSizeZ*cellSize*Int3.FloatPrecision))) Debug.LogWarning ("Possible numerical imprecision. Consider adjusting tileSize and/or cellSize");

				var offset = (Int3)(new Vector3((x * tileSizeX * cellSize),0,(z * tileSizeZ * cellSize)) + forcedBounds.min);

				for (int i=0;i<verts.Length;i++) {
					verts[i] += offset;
				}

			}

			var nodes = new TriangleMeshNode[tile.tris.Length/3];
			tile.nodes = nodes;

			//Here we are faking a new graph
			//The tile is not added to any graphs yet, but to get the position querys from the nodes
			//to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
			//and direct the position queries directly to the tile
			int graphIndex = AstarPath.active.astarData.graphs.Length;

			TriangleMeshNode.SetNavmeshHolder (graphIndex, tile);

			//This index will be ORed to the triangle indices
			int tileIndex = x + z*tileXCount;
			tileIndex <<= TileIndexOffset;

			//Create nodes and assign triangle indices
			for (int i=0;i<nodes.Length;i++) {
				var node = new TriangleMeshNode(active);
				nodes[i] = node;
				node.GraphIndex = (uint)graphIndex;
				node.v0 = tile.tris[i*3+0] | tileIndex;
				node.v1 = tile.tris[i*3+1] | tileIndex;
				node.v2 = tile.tris[i*3+2] | tileIndex;

				//Degenerate triangles might occur, but they will not cause any large troubles anymore
				//if (Polygon.IsColinear (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
				//	Debug.Log ("COLINEAR!!!!!!");
				//}

				//Make sure the triangle is clockwise
				if (!Polygon.IsClockwise (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}

				node.Walkable = true;
				node.Penalty = initialPenalty;
				node.UpdatePositionFromVertices();
			}

			tile.bbTree.RebuildFrom(nodes);

			CreateNodeConnections (tile.nodes);

			//Set tile
			for (int cz=z; cz < z+d;cz++) {
				for (int cx=x; cx < x+w;cx++) {
					tiles[cx + cz*tileXCount] = tile;
				}
			}

			if (batchTileUpdate) {
				batchUpdatedTiles.Add (x + z*tileXCount);
			} else {
				ConnectTileWithNeighbours(tile);
				/*if (x > 0) ConnectTiles (tiles[(x-1) + z*tileXCount], tile);
				if (z > 0) ConnectTiles (tiles[x + (z-1)*tileXCount], tile);
				if (x < tileXCount-1) ConnectTiles (tiles[(x+1) + z*tileXCount], tile);
				if (z < tileZCount-1) ConnectTiles (tiles[x + (z+1)*tileXCount], tile);*/
			}

			//Remove the fake graph
			TriangleMeshNode.SetNavmeshHolder (graphIndex, null);

			//Real graph index
			//TODO, could this step be changed for this function, is a fake index required?
			graphIndex = AstarPath.active.astarData.GetGraphIndex (this);

			for (int i=0;i<nodes.Length;i++) nodes[i].GraphIndex = (uint)graphIndex;

		}
		/** Create a tile at tile index \a x , \a z from the mesh.
		 * \warning This implementation is not thread safe. It uses cached variables to improve performance
		 */
		NavmeshTile CreateTile (Voxelize vox, VoxelMesh mesh, int x, int z) {

			if (mesh.tris == null) throw new System.ArgumentNullException ("mesh.tris");
			if (mesh.verts == null) throw new System.ArgumentNullException ("mesh.verts");

			//Create a new navmesh tile and assign its settings
			var tile = new NavmeshTile();

			tile.x = x;
			tile.z = z;
			tile.w = 1;
			tile.d = 1;
			tile.tris = mesh.tris;
			tile.verts = mesh.verts;
			tile.bbTree = new BBTree();

			if (tile.tris.Length % 3 != 0) throw new System.ArgumentException ("Indices array's length must be a multiple of 3 (mesh.tris)");

			if (tile.verts.Length >= VertexIndexMask) throw new System.ArgumentException ("Too many vertices per tile (more than "+VertexIndexMask+")." +
				"\nTry enabling ASTAR_RECAST_LARGER_TILES under the 'Optimizations' tab in the A* Inspector");

			//Dictionary<Int3, int> firstVerts = new Dictionary<Int3, int> ();
			Dictionary<Int3, int> firstVerts = cachedInt3_int_dict;
			firstVerts.Clear();

			var compressedPointers = new int[tile.verts.Length];

			int count = 0;
			for (int i=0;i<tile.verts.Length;i++) {
				if (!firstVerts.ContainsKey(tile.verts[i])) {
					firstVerts.Add (tile.verts[i], count);
					compressedPointers[i] = count;
					tile.verts[count] = tile.verts[i];
					count++;
				} else {
					// There are some cases, rare but still there, that vertices are identical
					compressedPointers[i] = firstVerts[tile.verts[i]];
				}
			}

			for (int i=0;i<tile.tris.Length;i++) {
				tile.tris[i] = compressedPointers[tile.tris[i]];
			}

			var compressed = new Int3[count];
			for (int i=0;i<count;i++) compressed[i] = tile.verts[i];

			tile.verts = compressed;

			var nodes = new TriangleMeshNode[tile.tris.Length/3];
			tile.nodes = nodes;

			//Here we are faking a new graph
			//The tile is not added to any graphs yet, but to get the position querys from the nodes
			//to work correctly (not throw exceptions because the tile is not calculated) we fake a new graph
			//and direct the position queries directly to the tile
			int graphIndex = AstarPath.active.astarData.graphs.Length;

			TriangleMeshNode.SetNavmeshHolder (graphIndex, tile);

			//This index will be ORed to the triangle indices
			int tileIndex = x + z*tileXCount;
			tileIndex <<= TileIndexOffset;

			//Create nodes and assign triangle indices
			for (int i=0;i<nodes.Length;i++) {
				var node = new TriangleMeshNode(active);
				nodes[i] = node;
				node.GraphIndex = (uint)graphIndex;
				node.v0 = tile.tris[i*3+0] | tileIndex;
				node.v1 = tile.tris[i*3+1] | tileIndex;
				node.v2 = tile.tris[i*3+2] | tileIndex;

				//Degenerate triangles might occur, but they will not cause any large troubles anymore
				//if (Polygon.IsColinear (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
				//	Debug.Log ("COLINEAR!!!!!!");
				//}

				//Make sure the triangle is clockwise
				if (!Polygon.IsClockwise (node.GetVertex(0), node.GetVertex(1), node.GetVertex(2))) {
					int tmp = node.v0;
					node.v0 = node.v2;
					node.v2 = tmp;
				}

				node.Walkable = true;
				node.Penalty = initialPenalty;
				node.UpdatePositionFromVertices();
			}

			tile.bbTree.RebuildFrom(nodes);
			CreateNodeConnections (tile.nodes);

			//Remove the fake graph
			TriangleMeshNode.SetNavmeshHolder (graphIndex, null);

			return tile;
		}