public static void Calculate(World level) { var chunks = level.ChunkManager.GetAllChunks().Select(x => x.Value).Cast <ChunkColumn>().OrderBy(column => column.X) .ThenBy(column => column.Z); SkyLightBlockAccess blockAccess = new SkyLightBlockAccess(level.ChunkManager); //var blockAccess = level; _chunkCount = chunks.Count(); if (_chunkCount == 0) { return; } CheckIfSpawnIsMiddle(chunks, level.SpawnPoint); Stopwatch sw = new Stopwatch(); sw.Start(); //Parallel.ForEach(chunks, chunk => chunk.RecalcHeight()); //Log.Debug($"Recalc height level {level.LevelName}({level.LevelId}) for {_chunkCount} chunks, {_chunkCount*16*16*256} blocks. Time {sw.ElapsedMilliseconds}ms"); SkyLightCalculations calculator = new SkyLightCalculations(Config.GetProperty("CalculateLights.MakeMovie", false)); int midX = calculator.GetMidX(chunks.ToArray()); //int width = calculator.GetWidth(chunks.ToArray()); sw.Restart(); HighPrecisionTimer tickerHighPrecisionTimer = null; calculator.StartTimeInMilliseconds = Environment.TickCount; var t0 = Task.Run(() => { var pairs = chunks.OrderBy(pair => pair.X).ThenBy(pair => pair.Z).Where(chunk => chunk.X <= midX).OrderByDescending(pair => pair.X).ThenBy(pair => pair.Z).ToArray(); calculator.CalculateSkyLights(blockAccess, pairs); }); var t5 = Task.Run(() => { var pairs = chunks.OrderByDescending(pair => pair.X).ThenBy(pair => pair.Z).Where(chunk => chunk.X > midX).OrderBy(pair => pair.X).ThenByDescending(pair => pair.Z).ToArray(); calculator.CalculateSkyLights(blockAccess, pairs); }); var t1 = Task.Run(() => { var pairs = chunks.OrderBy(pair => pair.X).ThenBy(pair => pair.Z).ToArray(); calculator.CalculateSkyLights(blockAccess, pairs); }); var t2 = Task.Run(() => { var pairs = chunks.OrderByDescending(pair => pair.X).ThenByDescending(pair => pair.Z).ToArray(); calculator.CalculateSkyLights(blockAccess, pairs); }); var t3 = Task.Run(() => { var pairs = chunks.OrderByDescending(pair => pair.X).ThenBy(pair => pair.Z).ToArray(); calculator.CalculateSkyLights(blockAccess, pairs); }); var t4 = Task.Run(() => { var pairs = chunks.OrderBy(pair => pair.X).ThenByDescending(pair => pair.Z).ToArray(); calculator.CalculateSkyLights(blockAccess, pairs); }); Task.WaitAll(t0, t1, t2, t3, t4, t5); Log.Debug($"Recalc skylight for {_chunkCount:N0} chunks, {_chunkCount * 16 * 16 * 256:N0} blocks. Touches={calculator.visits:N0} Time {sw.ElapsedMilliseconds:N0}ms"); //foreach (var chunk in chunks) //{ // calculator.ShowHeights(chunk); //} //var chunkColumn = chunks.First(column => column.x == -1 && column.z == 0 ); //if (chunkColumn != null) //{ // Log.Debug($"Heights:\n{Package.HexDump(chunkColumn.height)}"); // Log.Debug($"skylight.Data:\n{Package.HexDump(chunkColumn.skyLight.Data, 64)}"); //} }
public void Calculate(World level, BlockCoordinates coordinates) { int currentLight = level.GetSkyLight(coordinates); var cc = new ChunkCoordinates(coordinates); ChunkColumn chunk = (ChunkColumn)level.GetChunkColumn(cc.X, cc.Z); var height = chunk.GetRecalculatedHeight(coordinates.X & 0x0f, coordinates.Z & 0x0f); Queue <BlockCoordinates> sourceQueue = new Queue <BlockCoordinates>(); sourceQueue.Enqueue(coordinates); if (currentLight != 0) { Queue <BlockCoordinates> resetQueue = new Queue <BlockCoordinates>(); HashSet <BlockCoordinates> visits = new HashSet <BlockCoordinates>(); // Reset all lights that potentially derive from this resetQueue.Enqueue(coordinates); Queue <BlockCoordinates> deleteQueue = new Queue <BlockCoordinates>(); while (resetQueue.Count > 0) { var coord = resetQueue.Dequeue(); if (visits.Contains(coord)) { continue; } visits.Add(coord); if (coord.DistanceTo(coordinates) > 16) { continue; } ResetLight(level, resetQueue, sourceQueue, coord); if (!sourceQueue.Contains(coord)) { deleteQueue.Enqueue(coord); } } level.SetSkyLight(coordinates, 0); foreach (var delete in deleteQueue) { level.SetSkyLight(delete, 0); } } else { sourceQueue.Enqueue(coordinates); sourceQueue.Enqueue(coordinates.BlockUp()); sourceQueue.Enqueue(coordinates.BlockDown()); sourceQueue.Enqueue(coordinates.BlockWest()); sourceQueue.Enqueue(coordinates.BlockEast()); sourceQueue.Enqueue(coordinates.BlockNorth()); sourceQueue.Enqueue(coordinates.BlockSouth()); } chunk.SetHeight(coordinates.X & 0x0f, coordinates.Z & 0x0f, (short)height); // Recalc Queue <BlockCoordinates> lightBfQueue = new Queue <BlockCoordinates>(sourceQueue); HashSet <BlockCoordinates> lightBfSet = new HashSet <BlockCoordinates>(sourceQueue); SkyLightBlockAccess blockAccess = new SkyLightBlockAccess(level.ChunkManager); Calculate(blockAccess, lightBfQueue, lightBfSet); }