public void SaveDataToFileCaches(int bitMask, VFTile tile, double[][] nData, float[][] hData, float[][] gData, RandomMapType[][] tData)
    {
        if (_voxelTileCachesFS == null)
        {
            return;
        }

        IntVector4 xzlh = new IntVector4(tile.tileX, tile.tileZ, tile.tileL, tile.tileH);

        if (_voxelTileCacheDescsList.ContainsKey(xzlh))
        {
            Debug.LogWarning("[VFDataRTGen]:Try to append a existing voxel tile to cache file." + xzlh);
            return;
        }
        try
        {
            _voxelTileCachesFS.Seek(0, SeekOrigin.End); //Append
            VFTerTileCacheDesc desc = VFTerTileCacheDesc.WriteDataToCache(_bw, bitMask, tile, nData, hData, gData, tData);
            _voxelTileCacheDescsList.Add(xzlh, desc);
        }
        catch (Exception e)
        {
            string strE = e.ToString();
            Debug.LogWarning("[VFDataRTGen]:Failed to append voxel tile to cache file" + xzlh + e);
            if (strE.Contains("IOException: Win32 IO returned 112."))
            {
                GameLog.HandleExceptionInThread(e);
            }
        }
    }
    void LoadVoxelTileCacheDescs()
    {
        if (_voxelTileCachesFS != null)
        {
            _voxelTileCachesFS.Close();
        }

        try
        {
            // Open or create
            if (!Directory.Exists(GameConfig.VoxelCacheDataPath))
            {
                Directory.CreateDirectory(GameConfig.VoxelCacheDataPath);
            }
            _voxelTileCachesFS = new FileStream(_cacheFilePathName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);
            _br = new BinaryReader(_voxelTileCachesFS);
            _bw = new BinaryWriter(_voxelTileCachesFS);
            long endPos = _voxelTileCachesFS.Length;
            //Test magic code
            if (endPos < MagicCodeLen || _br.ReadInt32() != MagicCode)
            {
                _voxelTileCachesFS.SetLength(0);
                _bw.Write(MagicCode);
                _bw.Flush();
                ClearInvalidCache();
                endPos = _voxelTileCachesFS.Length;
            }

            long curPos = _voxelTileCachesFS.Position;
            while (curPos < endPos)
            {
                _voxelTileCachesFS.Seek(curPos, SeekOrigin.Begin);
                VFTerTileCacheDesc desc = VFTerTileCacheDesc.ReadDescFromCache(_br);
                if (desc.xzlh.w == VFDataRTGen.s_noiseHeight && desc.dataLen > 0)
                {
                    _voxelTileCacheDescsList.Add(desc.xzlh, desc);
                }
                else
                {
                    Debug.LogWarning("[VFDataRTGen]Error: Unrecognized voxel tile,discard the following data." + desc.xzlh + ":" + desc.dataLen);
                    _voxelTileCachesFS.SetLength(curPos);
                    endPos = _voxelTileCachesFS.Length;
                }
                curPos += desc.dataLen + VFTerTileCacheDesc.DataOfs;
            }
        }
        catch (Exception e)
        {
            Debug.LogWarning("[VFDataRTGen]Error:Failed to open/create voxel cache file:" + e);
            Close();
        }
    }
    public VFTerTileCacheDesc FillTileDataWithFileCache(IntVector4 xzlh, VFTile tile, double[][] nData, float[][] hData, float[][] gData, RandomMapType[][] tData)
    {
        VFTerTileCacheDesc desc = null;

        if (_voxelTileCacheDescsList.TryGetValue(xzlh, out desc))
        {
            try
            {
                desc.ReadDataFromCache(_br, tile, nData, hData, gData, tData);
            }
            catch
            {
                Debug.LogWarning("[VFDataRTGen]Error:Failed to read data from cache " + xzlh);
                return(null);
            }
        }
        return(desc);
    }