/// <summary>
        /// Generates a terrain patch from an array of bytes; returns null if the data is invalid.
        /// </summary>
        /// <param name="data">The array of bytes to generate the patch from.</param>
        /// <returns>See summary.</returns>
        public static TerrainPatch FromByteArray(byte[] data)
        {
            if (data == null)
            {
                return null;
            }
            else
            {
                ReadOnlyCollection<Season> seasons = SeasonExtensions.GetSeasons();

                BinaryReader reader = new BinaryReader(new MemoryStream(data));

                try
                {
                    // Read the patch ID
                    int x = reader.ReadInt32();
                    int y = reader.ReadInt32();
                    int z = reader.ReadInt32();

                    // Create a patch object
                    TerrainPatch patch = new TerrainPatch(new Point3D(x, y, z));

                    // Read the array of heights
                    for (int i = 0; i < patch.vertexHeightsArray.Length; i++)
                    {
                        patch.vertexHeightsArray[i] = reader.ReadSingle();
                    }

                    // Read terrain types for all seasons
                    for (int j = 0; j < seasons.Count; j++)
                    {
                        // Read the array of textures
                        for (int i = 0; i < patch.vertexTexturesArray[j].Length; i++)
                        {
                            patch.vertexTexturesArray[(int)seasons[j]][i] = (TerrainType)reader.ReadInt16();
                        }
                    }

                    // Read the number of fluids
                    short countFluids = reader.ReadInt16();

                    // Read all the fluids
                    for (int i = 0; i < countFluids; i++)
                    {
                        // Create a new fluid object to store on the patch
                        Fluid fluid = new Fluid(patch.PatchId);

                        // Read fluid properties for all seasons
                        for (int j = 0; j < seasons.Count; j++)
                        {
                            // Read the vertices
                            Vector3 southWest = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                            Vector3 southEast = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                            Vector3 northWest = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());
                            Vector3 northEast = new Vector3(reader.ReadSingle(), reader.ReadSingle(), reader.ReadSingle());

                            // Read the fluid type
                            short fluidType = reader.ReadInt16();

                            // Read the fluid flow direction
                            short flowDirection = reader.ReadInt16();

                            // Read the fluid flow speed
                            float flowSpeed = reader.ReadSingle();

                            // Copy the read variables into the properties of the fluid object
                            fluid.SetPoint(seasons[j], FluidVertex.Southwest, southWest);
                            fluid.SetPoint(seasons[j], FluidVertex.Southeast, southEast);
                            fluid.SetPoint(seasons[j], FluidVertex.Northwest, northWest);
                            fluid.SetPoint(seasons[j], FluidVertex.Northeast, northEast);
                            fluid.SetFluidType(seasons[j], (FluidType)fluidType);
                            fluid.SetFlowDirection(seasons[j], (FluidFlowDirection)flowDirection);
                            fluid.SetFlowSpeed(seasons[j], flowSpeed);
                        }

                        // Add the fluid to the patch
                        patch.Fluids.Add(fluid);
                    }

                    return patch;
                }
                catch (EndOfStreamException)
                {
                    return null;
                }
                catch (IOException)
                {
                    return null;
                }
                finally
                {
                    reader.Close();
                }
            }
        }