public void LoadOrCreateChunk(Vector3Int position, Block[] blocks, MappingFunction mappingFunction) { var pagePositionX = position.X / Page.PageSizeInBlocks; var pagePositionY = position.Y / Page.PageSizeInBlocks; var pagePositionZ = position.Z / Page.PageSizeInBlocks; var pageId = CreatePageId(pagePositionX, pagePositionY, pagePositionZ); if (m_pageCache.ContainsPage(pageId)) { var page = m_pageCache.GetPage(pageId); CopyPageToChunk(page, position, blocks, mappingFunction); } else if (m_directory.Pages.Contains(pageId)) { var page = DecompressPage(pageId); CopyPageToChunk(page, position, blocks, mappingFunction); m_pageCache.InsertPage(page); } else if (!m_pagesPendingWrite.Contains(pageId)) { m_pagesPendingWrite.Add(pageId); var page = new Page(position.X, position.Y, position.Z, pageId); var worldPosX = pagePositionX * Page.PageSizeInBlocks; var worldPosY = pagePositionY * Page.PageSizeInBlocks; var worldPosZ = pagePositionZ * Page.PageSizeInBlocks; TerrainGenerator.Instance.GenerateDataForChunk(worldPosX, worldPosY, worldPosZ, Page.PageSizeInBlocks, page.Data, (x, y, z) => Page.BlockIndexFromRelativePosition( x - worldPosX, y - worldPosY, z - worldPosZ)); //BlockDataUtilities.SetupScanDirectedHilbertCurve(Page.PageSizeInBlocks); // ChunkCompressor.GetHilbertCurve(32); var timer = Stopwatch.StartNew(); float compressionRatio; //ChunkCompressor.ScanDirection scanDir; var tree = ChunkCompressor.GetCompressor(Page.PageSizeInBlocks).ConvertArrayToIntervalTree(page.Data, out compressionRatio); Console.WriteLine("tree creation time: " + timer.ElapsedMilliseconds); // Console.WriteLine("h: " + scanDir); // Console.WriteLine("tree compresion ratio: " + compressionRatio); // timer.Restart(); // var tree2 = ChunkCompressor.ConvertArrayToIntervalTreeLinear(page.Data, Page.PageSizeInBlocks, // out compressionRatio, out scanDir); //Console.WriteLine("linear tree creation time: " + timer.ElapsedMilliseconds); // Console.WriteLine("l: " + scanDir); // Console.WriteLine("l: " + compressionRatio); // tree. timer.Restart(); var res = tree[new Interval(17490)]; Console.WriteLine("tree query time: " + timer.ElapsedMilliseconds); using (var fileStream = new FileStream(Path.Combine(m_dataDirectory, page.PageId + "_tree.page"), FileMode.Create)) { using (var compressor = new GZipStream(fileStream, CompressionLevel.Optimal)) { //Serializer.Serialize(compressor, tree); } } Console.WriteLine("tree compressionTime time: " + timer.ElapsedMilliseconds); timer.Restart(); CompressPage(page); Console.WriteLine("normal compressionTime time: " + timer.ElapsedMilliseconds); m_pageCache.InsertPage(page); m_directory.Pages.Add(pageId); CopyPageToChunk(page, position, blocks, mappingFunction); //m_jsonWriter.Write("SaveDirectory", m_directory); /* Task.Run(() => { CompressPage(page); m_pagesPendingWrite.Remove(page.PageId); });*/ } }
public Page DecompressPage(string pageId) { var buffer = CheckOutBuffer(); Page page; using (var fileStream = new FileStream(Path.Combine(m_dataDirectory, pageId + ".page"), FileMode.Open)) { using(var decompressor = new GZipStream(fileStream, CompressionMode.Decompress)) { decompressor.Read(buffer, 0, BufferSize); var pageX = GetInt(buffer, 0); var pageY = GetInt(buffer, 4); var pageZ = GetInt(buffer, 8); page = new Page(pageX, pageY, pageZ, pageId); for (var curveIndex = 0; curveIndex < BlockCount; ++curveIndex) { var offset = HeaderSize + curveIndex * 2; var block = new Block(GetShort(buffer, offset)); offset = HeaderSize + BlockCount * 2 + curveIndex; block.LightSun = buffer[offset]; offset = HeaderSize + BlockCount * 3 + curveIndex; block.LightRed = buffer[offset]; offset = HeaderSize + BlockCount * 4 + curveIndex; block.LightGreen = buffer[offset]; offset = HeaderSize + BlockCount * 5 + curveIndex; block.LightBlue = buffer[offset]; offset = HeaderSize + BlockCount * 6 + curveIndex * 2; block.Color = GetShort(buffer, offset); page.Data[m_hilbertCurve[curveIndex]] = block; } } } CheckInBuffer(buffer); return page; }
public void CompressPage(Page page) { var buffer = CheckOutBuffer(); PutInt(buffer, page.X, 0); PutInt(buffer, page.Y, 4); PutInt(buffer, page.Z, 8); for (var curveIndex = 0; curveIndex < BlockCount; ++curveIndex) { var block = page.Data[m_hilbertCurve[curveIndex]]; var offset = HeaderSize + curveIndex * 2; PutShort(buffer, block.Type, offset); offset = HeaderSize + BlockCount * 2 + curveIndex; buffer[offset] = block.LightSun; offset = HeaderSize + BlockCount * 3 + curveIndex; buffer[offset] = block.LightRed; offset = HeaderSize + BlockCount * 4 + curveIndex; buffer[offset] = block.LightGreen; offset = HeaderSize + BlockCount * 5 + curveIndex; buffer[offset] = block.LightBlue; offset = HeaderSize + BlockCount * 6 + curveIndex * 2; PutShort(buffer, block.Color, offset); } using (var fileStream = new FileStream(Path.Combine(m_dataDirectory, page.PageId + ".page"), FileMode.Create)) { using (var compressor = new GZipStream(fileStream, CompressionLevel.Optimal)) { compressor.Write(buffer, 0, BufferSize); } } CheckInBuffer(buffer); }
public void TestCompression(Page page) { CompressPage(page); var decompPage = DecompressPage(page.PageId); Debug.Assert(page.X == decompPage.X); Debug.Assert(page.Y == decompPage.Y); Debug.Assert(page.Z == decompPage.Z); for (var i = 0; i < page.Data.Length; ++i) { Debug.Assert(page.Data[i].Type == decompPage.Data[i].Type, "Type on block index: " + i); Debug.Assert(page.Data[i].LightRed == decompPage.Data[i].LightRed, "Red on block index: " + i); Debug.Assert(page.Data[i].LightGreen == decompPage.Data[i].LightGreen, "Green on block index: " + i); Debug.Assert(page.Data[i].LightBlue == decompPage.Data[i].LightBlue, "Blue on block index: " + i); Debug.Assert(page.Data[i].LightSun == decompPage.Data[i].LightSun, "Sun on block index: " + i); Debug.Assert(page.Data[i].Color == decompPage.Data[i].Color, "Color on block index: " + i); } }
private static void CopyCunkToPage(Page page, Vector3Int position, Block[] blocks, MappingFunction mappingFunction) { var originX = MathUtilities.Modulo(position.X, Page.PageSizeInBlocks); var originY = MathUtilities.Modulo(position.Y, Page.PageSizeInBlocks); var originZ = MathUtilities.Modulo(position.Z, Page.PageSizeInBlocks); for (var x = originX; x < originX + Chunk.SizeInBlocks; x++) { for (var y = originY; y < originY + Chunk.SizeInBlocks; y++) { for (var z = originZ; z < originZ + Chunk.SizeInBlocks; z++) { page.Data[Page.BlockIndexFromRelativePosition(x, y, z)] = blocks[mappingFunction(position.X + x, position.Y + y, position.Z + z)]; } } } }
public void SaveChunk(Vector3Int position, Block[] blocks, MappingFunction mappingFunction, Action<bool> callback) { var pagePositionX = position.X >> 6; var pagePositionY = position.Y >> 6; var pagePositionZ = position.Z >> 6; var pageId = CreatePageId(pagePositionX, pagePositionY, pagePositionZ); if (m_pagesPendingWrite.Contains(pageId)) { if (callback != null) { callback(false); } } else { Page page; if (m_pageCache.ContainsPage(pageId)) { page = m_pageCache.GetPage(pageId); CopyCunkToPage(page, position, blocks, mappingFunction); } else if (m_directory.Pages.Contains(pageId)) { page = DecompressPage(pageId); CopyCunkToPage(page, position, blocks, mappingFunction); m_pageCache.InsertPage(page); } else { page = new Page(position.X, position.Y, position.Z, pageId); for (var x = 0; x < Page.PageSizeInBlocks; x++) { for (var y = 0; y < Page.PageSizeInBlocks; y++) { for (var z = 0; z < Page.PageSizeInBlocks; z++) { page.Data[Page.BlockIndexFromRelativePosition(x, y, z)] = blocks[mappingFunction(position.X + x, position.Y + y, position.Z + z)]; } } } m_pageCache.InsertPage(page); m_directory.Pages.Add(pageId); // m_jsonWriter.Write("SaveDirectory", m_directory); } m_pagesPendingWrite.Add(pageId); Task.Run(() => { CompressPage(page); if (callback != null) { callback(true); } m_pagesPendingWrite.Remove(page.PageId); }); } }