public TerrainData DeserializeTerrainData(byte[] bytes, ref int index)
    {
        TerrainData terrainData = new TerrainData();

        terrainData.name = R_SerializationHelper.DeserializeString(bytes, ref index);
        // Debug.Log(terrainData.name);

        int heightmapResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);

        terrainData.heightmapResolution = heightmapResolution;
        terrainData.baseMapResolution   = R_SerializationHelper.DeserializeInt(bytes, ref index);
        terrainData.alphamapResolution  = R_SerializationHelper.DeserializeInt(bytes, ref index);
        int detailResolution = R_SerializationHelper.DeserializeInt(bytes, ref index);

        terrainData.SetDetailResolution(detailResolution, 16);

        terrainData.size = R_SerializationHelper.DeserializeVector3(bytes, ref index);

        terrainData.thickness           = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassAmount   = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassSpeed    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassStrength = R_SerializationHelper.DeserializeFloat(bytes, ref index);
        terrainData.wavingGrassTint     = R_SerializationHelper.DeserializeColor(bytes, ref index);

        // Splat Textures
        int splatLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        SplatPrototype[] splatPrototypes = new SplatPrototype[splatLength];
        for (int i = 0; i < splatLength; i++)
        {
            SplatPrototype splat = new SplatPrototype();
            splat.metallic = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            if (bytes[index++] == 1)
            {
                string normalName = R_SerializationHelper.DeserializeString(bytes, ref index);
                splat.normalMap = (Texture2D)Resources.Load(normalName);
            }
            splat.smoothness = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            string splatName = R_SerializationHelper.DeserializeString(bytes, ref index);
            splat.texture      = (Texture2D)Resources.Load(splatName);
            splat.tileOffset   = R_SerializationHelper.DeserializeVector2(bytes, ref index);
            splat.tileSize     = R_SerializationHelper.DeserializeVector2(bytes, ref index);
            splatPrototypes[i] = splat;
        }
        terrainData.splatPrototypes = splatPrototypes;

        // Tree Prototypes
        int treeLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        TreePrototype[] treePrototypes = new TreePrototype[treeLength];
        for (int i = 0; i < treeLength; i++)
        {
            TreePrototype tree = new TreePrototype();
            tree.bendFactor = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            string prefabName = R_SerializationHelper.DeserializeString(bytes, ref index);
            tree.prefab       = (GameObject)Resources.Load(prefabName);
            treePrototypes[i] = tree;
        }
        terrainData.treePrototypes = treePrototypes;

        // Grass Prototypes
        int grassLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        DetailPrototype[] detailPrototypes = new DetailPrototype[grassLength];
        for (int i = 0; i < grassLength; i++)
        {
            DetailPrototype grass = new DetailPrototype();
            grass.bendFactor   = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.dryColor     = R_SerializationHelper.DeserializeColor(bytes, ref index);
            grass.healthyColor = R_SerializationHelper.DeserializeColor(bytes, ref index);
            grass.maxHeight    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.maxWidth     = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.minHeight    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.minWidth     = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            grass.noiseSpread  = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            if (bytes[index++] == 1)
            {
                R_SerializationHelper.DeserializeString(bytes, ref index);
            }
            if (bytes[index++] == 1)
            {
                string textureName = R_SerializationHelper.DeserializeString(bytes, ref index);
                grass.prototypeTexture = (Texture2D)Resources.Load(textureName);
            }
            grass.renderMode    = (DetailRenderMode)R_SerializationHelper.DeserializeInt(bytes, ref index);
            detailPrototypes[i] = grass;
        }
        terrainData.detailPrototypes = detailPrototypes;

        float[,] heights = R_SerializationHelper.Deserialize2DFloatArray(bytes, ref index);
        terrainData.SetHeights(0, 0, heights);

        int splatmapLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        Texture2D[] alphamapTextures = terrainData.alphamapTextures;

        for (int i = 0; i < splatmapLength; i++)
        {
            int    length   = R_SerializationHelper.DeserializeInt(bytes, ref index);
            byte[] texBytes = new byte[length];
            Array.Copy(bytes, index, texBytes, 0, length);
            index += length;
            alphamapTextures[i].LoadImage(texBytes);
            alphamapTextures[i].Apply();
        }

        int treeInstancesLength = R_SerializationHelper.DeserializeInt(bytes, ref index);

        TreeInstance[] trees = new TreeInstance[treeInstancesLength];

        for (int i = 0; i < trees.Length; i++)
        {
            TreeInstance tree = new TreeInstance();
            tree.color          = R_SerializationHelper.DeserializeColor(bytes, ref index);
            tree.heightScale    = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            tree.lightmapColor  = R_SerializationHelper.DeserializeColor(bytes, ref index);
            tree.position       = R_SerializationHelper.DeserializeVector3(bytes, ref index);
            tree.prototypeIndex = R_SerializationHelper.DeserializeInt(bytes, ref index);
            tree.rotation       = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            tree.widthScale     = R_SerializationHelper.DeserializeFloat(bytes, ref index);
            trees[i]            = tree;
        }
        terrainData.treeInstances = trees;

        for (int i = 0; i < grassLength; i++)
        {
            int[,] grassMap = R_SerializationHelper.Deserialize2DByteArrayToInt(bytes, ref index);
            terrainData.SetDetailLayer(0, 0, i, grassMap);
        }

        return(terrainData);
    }