public static CachedChunk LoadChunk(WorldServer world, Vector3i chunkPos) { var region = ChunkToRegion(chunkPos); var regionFilename = Path.Combine(WorldFolder, RegionsFolder, GetRegionFilename(region)); var indexFile = new FileInfo(regionFilename + RegionIndexExt); var dataFile = new FileInfo(regionFilename + RegionDataExt); if (!indexFile.Exists || !dataFile.Exists) { return(null); } //Get chunk data position and length int chunkDataPosition, chunkDataLength; var chunkIndexPosition = GetChunkIndexPosition(chunkPos); lock (IndexLockObject) { var chunkIndexData = GetIndexData(region, indexFile); chunkDataPosition = BitConverter.ToInt32(chunkIndexData, chunkIndexPosition); chunkDataLength = BitConverter.ToInt32(chunkIndexData, chunkIndexPosition + sizeof(int)); } if (chunkDataPosition == IndexFileNull || chunkDataLength == IndexFileNull) { return(null); } //Read chunk data byte[] chunkData; lock (DataLockObject) { using (var reader = new BinaryReader(dataFile.OpenRead())) { reader.BaseStream.Seek(chunkDataPosition, SeekOrigin.Begin); chunkData = CompressionHelper.DecompressBytes(reader.ReadBytes(chunkDataLength)); } } using (var reader = new BinaryReader(new MemoryStream(chunkData))) { return(new CachedChunk(world, chunkPos, reader)); } }
private static byte[] GetIndexData(Vector3i region, FileInfo indexFile) { foreach (var cachedIndexData in CachedIndexDatas) { if (cachedIndexData.Item1 == region) { return(cachedIndexData.Item2); } } var data = CompressionHelper.DecompressBytes(File.ReadAllBytes(indexFile.FullName)); CachedIndexDatas.Add(new Tuple <Vector3i, byte[]>(region, data)); if (CachedIndexDatas.Count > MaxCachedIndexDatas) { CachedIndexDatas.RemoveAt(0); } return(data); }
public static void SaveChunk(Chunk chunk) { if (!chunk.NeedsSaving) { return; } var region = ChunkToRegion(chunk.Position); var regionFilename = Path.Combine(WorldFolder, RegionsFolder, GetRegionFilename(region)); var indexFile = new FileInfo(regionFilename + RegionIndexExt); var dataFile = new FileInfo(regionFilename + RegionDataExt); // ReSharper disable once PossibleNullReferenceException indexFile.Directory.Create(); lock (IndexLockObject) { if (!indexFile.Exists) { using (var stream = new GZipStream(indexFile.Create(), CompressionMode.Compress)) { var buffer = new byte[1024]; for (var i = 0; i < buffer.Length; i += sizeof(int)) { BitConverter.GetBytes(IndexFileNull).CopyTo(buffer, i); } for (var i = 0; i < IndexFileLength / buffer.Length; i++) { stream.Write(buffer, 0, buffer.Length); } } } } //Compress chunk data byte[] compressedChunkData; using (var memoryStream = new MemoryStream()) { using (var writer = new BinaryWriter(memoryStream)) { chunk.Write(writer); } compressedChunkData = CompressionHelper.CompressBytes(memoryStream.ToArray()); } var chunkDataPosition = dataFile.Exists ? (int)dataFile.Length : 0; var chunkDataLength = compressedChunkData.Length; //Append chunk to data file lock (DataLockObject) { using (var stream = dataFile.Open(FileMode.Append, FileAccess.Write)) { stream.Write(compressedChunkData, 0, compressedChunkData.Length); } } //Update chunk index var chunkIndexPosition = GetChunkIndexPosition(chunk.Position); lock (IndexLockObject) { var chunkIndexData = GetIndexData(region, indexFile); Array.Copy(BitConverter.GetBytes(chunkDataPosition), 0, chunkIndexData, chunkIndexPosition, sizeof(int)); Array.Copy(BitConverter.GetBytes(chunkDataLength), 0, chunkIndexData, chunkIndexPosition + sizeof(int), sizeof(int)); File.WriteAllBytes(indexFile.FullName, CompressionHelper.CompressBytes(chunkIndexData)); } chunk.NeedsSaving = false; }