private static Regex chunkShardRegex = new Regex(@"(?<X>[\d]+)_(?<Z>[\d]+)\.png", RegexOptions.Singleline);
private ConcurrentDictionary<Vec2i, ColumnCounter> columnCounters = new ConcurrentDictionary<Vec2i, ColumnCounter>(3, 150);
+ private Queue<Vec2i> revisitChunkList = new Queue<Vec2i>();
private ColumnsMetadata chunkTopMetadata;
internal PointsOfInterest POIs = new PointsOfInterest();
internal EntitiesOfInterest EOIs = new EntitiesOfInterest();
}
else if (snapshot != null && snapshot.Finished) {
#if DEBUG
- Logger.VerboseDebug("COMPLETED Snapshot: {0} Wx{1} Hx{2}, taking {3}", snapshot.fileName, snapshot.Width, snapshot.Height, snapshot.Timer.Elapsed);
+ Logger.VerboseDebug("COMPLETED Snapshot: {0} Wx{1} Hx{2}, taking {3}", snapshot.fileName, snapshot.Width, snapshot.Height, snapshot.Timer.Elapsed);
#endif
snapshot = null;
CurrentState = CommandType.Run;
uint updatedChunks = 0;
uint updatedPixels = 0;
- //-- Should dodge enumerator changing underfoot....at a cost.
- if (!columnCounters.IsEmpty)
- {
- var tempSet = columnCounters.ToArray().Where(cks => cks.Value.WeightedSum > editThreshold) .OrderByDescending(kvp => kvp.Value.WeightedSum);
+
+ //Revisit failed chunks first;
+ while (revisitChunkList.Count > 0)
+ {
+ var revisitCoord = revisitChunkList.Dequeue( );
+ var rv_mapChunk = ClientAPI.World.BlockAccessor.GetMapChunk(revisitCoord);
+
+ if (rv_mapChunk == null) continue;
+
+ ColumnMeta rv_chunkMeta;
+ if (chunkTopMetadata.Contains(revisitCoord))
+ {
+ rv_chunkMeta = chunkTopMetadata[revisitCoord];
+ #if DEBUG
+ Logger.VerboseDebug("(re)Loaded meta-chunk {0}", revisitCoord);
+ #endif
+ }
+ else
+ {
+ rv_chunkMeta = CreateColumnMetadata(revisitCoord, rv_mapChunk);
+ #if DEBUG
+ Logger.VerboseDebug("(re)Created meta-chunk {0}", revisitCoord);
+ #endif
+ }
+
+ ProcessChunkBlocks(revisitCoord, rv_mapChunk, ref rv_chunkMeta);
+
+ ChunkRenderer.SetupPngImage(revisitCoord, path, _chunkPath, ref rv_chunkMeta);
+ ChunkRenderer.GenerateChunkPngShard(revisitCoord, rv_mapChunk, rv_chunkMeta, ref chunkTopMetadata, out updatedPixels);
+
+ if (updatedPixels > 0)
+ {
+ #if DEBUG
+ Logger.VerboseDebug("(re)Wrote top-chunk shard: ({0}), Pixels#:{2}", revisitCoord, updatedPixels);
+ #endif
+ updatedChunks++;
+ chunkTopMetadata.Update(rv_chunkMeta);
+ }
+ }//*********** REVISIT'd ******************
+
+ if (!columnCounters.IsEmpty)
+ {//-- Should dodge enumerator changing underfoot....at a cost.
+ var tempSet = columnCounters.ToArray().Where(cks => cks.Value.WeightedSum > editThreshold) .OrderByDescending(kvp => kvp.Value.WeightedSum);
+
UpdateEntityMetadata();
foreach (var mostActiveCol in tempSet)
var mapChunk = ClientAPI.World.BlockAccessor.GetMapChunk(mostActiveCol.Key);
if (mapChunk == null)
- {
- //TODO: REVISIT THIS CHUNK!
+ {
#if DEBUG
Logger.Warning("SKIP CHUNK: ({0}) - Map Chunk NULL!", mostActiveCol.Key);
#endif
nullMapCount++;
columnCounters.TryRemove(mostActiveCol.Key, out ejectedItem);
+ revisitChunkList.Enqueue(mostActiveCol.Key);
continue;
}
#if DEBUG
Logger.VerboseDebug("Un-painted chunk shard: ({0}) ", mostActiveCol.Key);
#endif
+ revisitChunkList.Enqueue(mostActiveCol.Key);
}
}
}
columnCounters.Clear( );
//Then sleep until interupted again, and repeat
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Thread '{0}' about to sleep indefinitely.", Thread.CurrentThread.Name);
-#endif
+ #endif
Thread.Sleep(Timeout.Infinite);
}
catch (ThreadInterruptedException)
{
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Thread '{0}' interupted [awoken]", Thread.CurrentThread.Name);
-#endif
+ #endif
goto wake;
}
catch (ThreadAbortException)
{
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Thread '{0}' aborted.", Thread.CurrentThread.Name);
-#endif
+ #endif
}
finally
{
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name);
-#endif
+ #endif
PersistPointsData();
Write_PlainMetadata( );
}
private void Snap()
{
snapshotTake:
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Snapshot started");
-#endif
+ #endif
try
{
snapshot.Take();
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Snapshot sleeping");
-#endif
+ #endif
CurrentState = CommandType.Run;
Thread.Sleep(Timeout.Infinite);
}
catch (ThreadInterruptedException)
{
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Snapshot intertupted");
-#endif
+ #endif
goto snapshotTake;
}
}
return data;
}
+ private ColumnMeta CreateColumnMetadata(Vec2i coords, IMapChunk mapChunk)
+ {
+ ColumnMeta data = new ColumnMeta(coords, ClientAPI, ( byte )chunkSize, (ClientAPI.World.BlockAccessor.MapSizeY / chunkSize));
+ BlockPos equivBP = new BlockPos(coords.X * chunkSize,
+ mapChunk.YMax,
+ coords.Y * chunkSize);
+
+ var climate = ClientAPI.World.BlockAccessor.GetClimateAt(equivBP);
+ data.UpdateFieldsFrom(climate, mapChunk, TimeSpan.FromHours(ClientAPI.World.Calendar.TotalHours));
+
+ return data;
+ }
+
/// <summary>
/// Reload chunk bounds from chunk shards
/// </summary>
if (worldChunk == null || worldChunk.BlockEntities == null)
{
#if DEBUG
- Logger.VerboseDebug("WORLD chunk: null or empty X{0} Y{1} Z{2} !", key.X, targetChunkY, key.Y);
+ Logger.VerboseDebug("WORLD chunk: null, B.E. null X{0} Y{1} Z{2} !", key.X, targetChunkY, key.Y);
#endif
nullChunkCount++;
continue;
#if DEBUG
Logger.VerboseDebug("WORLD chunk: Compressed: X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
#endif
- worldChunk.Unpack( );//RESEARCH: Thread Unsafe?
+ //VALIDATE: check Read-only applicable
+ if (worldChunk.Unpack_ReadOnly( ) == false)
+ {
+ Logger.Warning("Failed to unpack chunk: X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
+ nullChunkCount++;
+ continue;
+ };
}
/*************** Chunk Entities Scanning *********************/
foreach (var blockEnt in worldChunk.BlockEntities)
{
- if (blockEnt.Key != null && blockEnt.Value != null && blockEnt.Value.Block != null && BlockID_Designators.ContainsKey(blockEnt.Value.Block.BlockId))
+ if (blockEnt.Key != null && blockEnt.Value != null && blockEnt.Value.Block != null && blockEnt.Value.Pos != null && BlockID_Designators.ContainsKey(blockEnt.Value.Block.BlockId))
{
var designator = BlockID_Designators[blockEnt.Value.Block.BlockId];
designator?.SpecialAction(ClientAPI, POIs, blockEnt.Value.Pos.Copy(), blockEnt.Value.Block);
int X_index, Y_index, Z_index;
//First Chance fail-safe;
- if (worldChunk.Blocks == null || worldChunk.Blocks.Length <= 0) {
+ if (worldChunk.MaybeBlocks == null || worldChunk.MaybeBlocks.Length <= 0) {
#if DEBUG
Logger.VerboseDebug("WORLD chunk; Missing block DATA⁈ X{0} Y{1} Z{2} ⁈", key.X, targetChunkY, key.Y);
#endif
var indicie = MapUtil.Index3d(X_index, Y_index, Z_index, chunkSize, chunkSize);
//'Last' Chance fail-safe;
- if (worldChunk.Blocks == null || worldChunk.Blocks.Length <= 0) {
+ if (worldChunk.MaybeBlocks == null || worldChunk.MaybeBlocks.Length <= 0) {
#if DEBUG
Logger.VerboseDebug("Processing Block: Missing block DATA⁈ X{0} Y{1} Z{2} ⁈", X_index, Y_index, Z_index);
#endif
goto loop_bustout;
}
- int aBlockId = worldChunk.Blocks[indicie];
+ int aBlockId = worldChunk.MaybeBlocks[indicie];
if (aBlockId == 0 || AiryIdCodes.ContainsKey(aBlockId)) {//Airy blocks,,,
chunkMeta.AirBlocks++;