public static void AddReadRequest(VFVoxelChunkData chunkData)
    {
        IntVector4 chunkPos = chunkData.ChunkPosLod;

        // Req to chunks out of range will return, these chunks will be null and can not be write according to WriteVoxelAtIdx's code
        if (chunkPos.x < 0 || chunkPos.x >= VoxelTerrainConstants._worldMaxCX)
        {
            return;
        }
        if (chunkPos.y < 0 || chunkPos.y >= VoxelTerrainConstants.WorldMaxCY(chunkPos.w))
        {
            return;
        }
        if (chunkPos.z < 0 || chunkPos.z >= VoxelTerrainConstants._worldMaxCZ)
        {
            return;
        }

        // no caching
        IntVector4 piecePos;

        VFFileDataClone.WorldChunkPosToPiecePos(chunkPos, out piecePos);

        IntVector4 fileIndex;

        VFFileDataClone.PiecePos2FileIndex(piecePos, out fileIndex);

        VFPieceDataClone pieceData = GetPieceDataSub(piecePos, GetFileSetSub(fileIndex));

        pieceData.Decompress();
        pieceData.SetChunkData(chunkData);
        pieceData._data = null;
        pieceData       = null;
    }
    public static bool GetPieceData(out VFPieceDataClone pieceData, IntVector4 piecePos)        // ret if cache hit
    {
        IntVector4 fileIndex;

        VFFileDataClone.PiecePos2FileIndex(piecePos, out fileIndex);
        VFFileDataClone fileSet = null;        //fileSetCache.Find(iter=>VFFileDataClone.Match(iter, fileIndex));

        //if(fileSet == null)
        {
            fileSet = GetFileSetSub(fileIndex);
            //fileSetCache.Add(fileSet);
        }

        pieceData = GetPieceDataSub(piecePos, fileSet);
        fileSet   = null;
        //fileDataCache.Add(fileData);
        return(false);
    }
    //const int fileLoadPerFrame = 2;
    //const int fileSetCacheW = 3;
    //const int fileDataCacheW = 3;
    //private static List<VFFileDataClone> fileSetCache = new List<VFFileDataClone>();
    //private static List<VFPieceDataClone> pieceDataCache = new List<VFPieceDataClone>();

    public static VFFileDataClone GetFileSetSub(IntVector4 fileIndex)
    {
        int             lod      = fileIndex.w;
        VFFileDataClone fileData = new VFFileDataClone();

        fileData._pos.x = fileIndex.x;
        fileData._pos.y = fileIndex.y;
        fileData._pos.z = fileIndex.z;
        fileData._lod   = lod;
        if (string.IsNullOrEmpty(VFVoxelTerrain.MapDataPath_Zip))
        {
            fileData.fs = null;
        }
        else
        {
#if USE_ZIPPED_DATA
            string fileName = VFVoxelTerrain.MapDataPath_Zip + "/map_x" + fileIndex.x + "_y" + fileIndex.z + (lod != 0 ? ("_" + lod + ".voxelform") : ".voxelform");
            try
            {
                int fSetOfsDataLenLod = (VFFileDataClone.FSetDataCountXZ >> lod) * (VFFileDataClone.FSetDataCountXZ >> lod) * (VFFileDataClone.FSetDataCountY >> lod) * 4;
                fileData.fs  = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
                fileData.len = (int)fileData.fs.Length;
                fileData.fs.Read(VFFileDataClone.ofsData, 0, fSetOfsDataLenLod);
            }
            catch (Exception)
            {
                Debug.LogError("[VFDataReader] Failed to read " + fileName);
                fileData.fs = null;
            }
#else
            string fileName = GameConfig.MapDataPath_Raw + "/map_x" + fileIndex.x + "y" + fileIndex.z + "h" + fileIndex.y + "l0.voxelform";
            fileData.fs  = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
            fileData.len = (int)fileSet.fs.Length;
#endif
        }
        return(fileData);
    }
    public static VFPieceDataClone GetPieceDataSub(IntVector4 piecePos, VFFileDataClone fileSet)
    {
        VFPieceDataClone pieceData = new VFPieceDataClone();

        pieceData._pos.x = piecePos.x;
        pieceData._pos.y = piecePos.y;
        pieceData._pos.z = piecePos.z;
        pieceData._lod   = fileSet._lod;

        if (fileSet.fs == null)
        {
            pieceData._data = new byte[VFVoxel.c_VTSize];
        }
        else
        {
            int ofs, len;
            fileSet.GetOfs(piecePos, out ofs, out len);
            pieceData._data = new byte[len];
            fileSet.fs.Seek(ofs, SeekOrigin.Begin);
            fileSet.fs.Read(pieceData._data, 0, len);
            fileSet.fs.Close();
        }
        return(pieceData);
    }
 public static bool Match(VFFileDataClone fileData, IntVector4 fileIndex)
 {
     return(fileData._pos.Equals(fileIndex.XYZ) && fileData._lod == fileIndex.w);
 }