OSDN Git Service

Post-PR4 #2: Heightmap in PNG Metadata, JSON encoding for POI notes
[automap/automap.git] / Automap / Subsystems / AutomapSystem.cs
index 889b65b..4ef549f 100644 (file)
@@ -9,7 +9,7 @@ using System.Threading;
 
 using Hjg.Pngcs;
 using Hjg.Pngcs.Chunks;
-
+using Newtonsoft.Json;
 using Vintagestory.API.Client;
 using Vintagestory.API.Common;
 using Vintagestory.API.Config;
@@ -149,6 +149,7 @@ namespace Automap
                        {
                                uint ejectedItem = 0;
                                uint updatedChunks = 0;
+                               uint updatedPixels = 0;
 
                                //-- Should dodge enumerator changing underfoot....at a cost.
                                if (!columnCounter.IsEmpty)
@@ -167,13 +168,19 @@ namespace Automap
                                                        continue;
                                                }
 
-                                               ColumnMeta chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
-                                               PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
+                                               ColumnMeta chunkMeta;
+                                               if (chunkTopMetadata.Contains(mostActiveCol.Key)) {
+                                               chunkMeta = chunkTopMetadata[mostActiveCol.Key];
+                                               }
+                                               else {
+                                               chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
+                                               }
+
                                                UpdateEntityMetadata();
                                                ProcessChunkBlocks(mostActiveCol.Key, mapChunk, chunkMeta);
 
-
-                                               ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out uint updatedPixels);
+                                               PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
+                                               ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out updatedPixels);
 
                                                if (updatedPixels > 0)
                                                {
@@ -319,7 +326,7 @@ namespace Automap
                                        jsonWriter.Write("airBlocks:'{0}',", shard.AirBlocks);
                                        jsonWriter.Write("nonAirBlocks:'{0}',", shard.NonAirBlocks);
                                        //TODO: Heightmap
-                                       //TODO: Rock-ratio
+                                       //TODO: Rock-ratio, also requires a BlockID => Name lookup table....elsewhere
                                        jsonWriter.Write("}],");
                                }
                                jsonWriter.Write("]);");
@@ -331,7 +338,7 @@ namespace Automap
                                        jsonWriter.Write("['{0}_{1}',", poi.Location.X, poi.Location.Z);
                                        jsonWriter.Write("{");
                                        jsonWriter.Write("prettyCoord:'{0}',", poi.Location.PrettyCoords(ClientAPI));
-                                       jsonWriter.Write("notes:'{0}',", poi.Notes.Replace("'", "\'").Replace("\n","\\n"));
+                                       jsonWriter.Write("notes:{0},", JsonConvert.ToString(poi.Notes, '\'', StringEscapeHandling.EscapeHtml));
                                        jsonWriter.Write("time:new Date('{0}'),", poi.Timestamp.ToString("O"));
                                        jsonWriter.Write("chunkPos:'{0}_{1}',", (poi.Location.X / chunkSize), (poi.Location.Z / chunkSize));
                                        jsonWriter.Write("}],");
@@ -342,7 +349,7 @@ namespace Automap
                                        jsonWriter.Write("['{0}_{1}',", poi.Location.X, poi.Location.Z);
                                        jsonWriter.Write("{");
                                        jsonWriter.Write("prettyCoord:'{0}',", poi.Location.PrettyCoords(ClientAPI));
-                                       jsonWriter.Write("notes:'{0}',", poi.Notes.Replace("'", "\'"));
+                                       jsonWriter.Write("notes:{0},", JsonConvert.ToString(poi.Notes, '\'', StringEscapeHandling.EscapeHtml));
                                        jsonWriter.Write("time:new Date('{0}'),", poi.Timestamp.ToString("O"));
                                        jsonWriter.Write("chunkPos:'{0}_{1}',", (poi.Location.X / chunkSize), (poi.Location.Z / chunkSize));
                                        jsonWriter.Write("}],");
@@ -357,7 +364,7 @@ namespace Automap
 
                private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
                {
-                       ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), chunkSize);
+                       ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), ( byte )chunkSize);
                        BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize,
                                                                                        mapChunk.YMax,
                                                                                        mostActiveCol.Key.Y * chunkSize);
@@ -383,37 +390,43 @@ namespace Automap
 
                                if (files.Length > 0)
                                {
-#if DEBUG
+                                       #if DEBUG
                                        Logger.VerboseDebug("{0} Existing world chunk shards", files.Length);
-#endif
+                                       #endif
+                                        
+                                       foreach (var shardFile in files) {
 
+                                       if (shardFile.Length < 1024) continue;
+                                       var result = chunkShardRegex.Match(shardFile.Name);
+                                       if (result.Success) {
+                                       int X_chunk_pos = int.Parse(result.Groups["X"].Value);
+                                       int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
 
-
-                                       foreach (var shardFile in files)
-                                       {
-
-                                               if (shardFile.Length < 512) continue;
-                                               var result = chunkShardRegex.Match(shardFile.Name);
-                                               if (result.Success)
+                                       try 
                                                {
-                                                       int X_chunk_pos = int.Parse(result.Groups["X"].Value);
-                                                       int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
+                                               using (var fileStream = shardFile.OpenRead( )) {
 
-                                                       //Parse PNG chunks for METADATA in shard
-                                                       using (var fileStream = shardFile.OpenRead( )) {
-                                                       //TODO: Add corrupted PNG Exception handing HERE !
-                                                       PngReader pngRead = new PngReader(fileStream);
-                                                       pngRead.ReadSkippingAllRows( );
-                                                       pngRead.End( );
+                                               PngReader pngRead = new PngReader(fileStream);
+                                               pngRead.ReadSkippingAllRows( );
+                                               pngRead.End( );
+                                               //Parse PNG chunks for METADATA in shard
+                                               PngMetadataChunk metadataFromPng = pngRead.GetChunksList( ).GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
 
-                                                       PngMetadataChunk metadataFromPng = pngRead.GetChunksList( ).GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
+                                               chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
+                                               }
 
-                                                       chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
-                                                       }
+                                               }
+                                               catch (PngjException someEx) 
+                                               {
+                                                       Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
+                                                       continue;
                                                }
                                        }
 
+                                       }
                                }
+
+
                        }
                        else
                        {
@@ -444,12 +457,14 @@ namespace Automap
                                ChunkMetadata = metadata
                        };
                        pngWriter.GetChunksList().Queue(pngChunkMeta);
+                       pngWriter.CompLevel = 9;// 9 is the maximum compression
+                       pngWriter.CompressionStrategy = Hjg.Pngcs.Zlib.EDeflateCompressStrategy.Huffman;
 
                        return pngWriter;
                }
 
                /// <summary>
-               /// Does the heavy lifting of Scanning columns of chunks - creates Heightmap and Processes POIs, Entities, and stats...
+               /// Does the heavy lifting of Scanning columns of chunks - scans for BlockEntity, creates Heightmap and stats...
                /// </summary>
                /// <param name="key">Chunk Coordinate</param>
                /// <param name="mapChunk">Map chunk.</param>
@@ -460,20 +475,21 @@ namespace Automap
                        int targetChunkY = mapChunk.YMax / chunkSize;//Surface ... 
                        for (; targetChunkY > 0; targetChunkY--)
                        {
-                               if (!(ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) is WorldChunk chunkData) || chunkData.BlockEntities == null)
-                               {
-#if DEBUG
-                                       Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
-#endif
-                                       continue;
-                               }
+                       WorldChunk chunkData = ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) as WorldChunk;
+
+                       if (chunkData == null || chunkData.BlockEntities == null) {
+                       #if DEBUG
+                       Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
+                       #endif
+                       continue;
+                       }
 
                                /*************** Chunk Entities Scanning *********************/
                                if (chunkData.BlockEntities != null && chunkData.BlockEntities.Length > 0)
                                {
-#if DEBUG
+                               #if DEBUG
                                        Logger.VerboseDebug("Surface@ {0} = BlockEntities: {1}", key, chunkData.BlockEntities.Length);
-#endif
+                               #endif
 
                                        foreach (var blockEnt in chunkData.BlockEntities)
                                        {