OSDN Git Service

Removed client command - as GUI handles this.
[automap/automap.git] / Automap / Subsystems / AutomapSystem.cs
index 00692a6..8bbb0c1 100644 (file)
@@ -27,19 +27,21 @@ namespace Automap
        public class AutomapSystem
        {
                private Thread cartographer_thread;
+               private Thread snapshotThread;
+               private Snapshotter snapshot;
                private ICoreClientAPI ClientAPI { get; set; }
                private ILogger Logger { get; set; }
                private IChunkRenderer ChunkRenderer { get; set; }
                private JsonGenerator JsonGenerator { get; set; }
 
-               private const string _mapPath = @"Maps";
-               private const string _chunkPath = @"Chunks";
+               internal const string _mapPath = @"Maps";
+               internal const string _chunkPath = @"Chunks";
                private const string _domain = @"automap";
                private const string chunkFile_filter = @"*_*.png";
                private const string poiFileName = @"poi_binary";
                private const string eoiFileName = @"eoi_binary";
                private const string pointsTsvFileName = @"points_of_interest.tsv";
-               private static Regex chunkShardRegex = new Regex(@"(?<X>[\d]+)_(?<Z>[\d]+).png", RegexOptions.Singleline);
+               private static Regex chunkShardRegex = new Regex(@"(?<X>[\d]+)_(?<Z>[\d]+)\.png", RegexOptions.Singleline);
 
                private ConcurrentDictionary<Vec2i, uint> columnCounter = new ConcurrentDictionary<Vec2i, uint>(3, 150);
                private ColumnsMetadata chunkTopMetadata;
@@ -52,7 +54,7 @@ namespace Automap
 
                internal CommandType CurrentState { get; set; }
                //Run status, Chunks processed, stats, center of map....
-               private uint nullChunkCount, updatedChunksTotal;
+               private uint nullChunkCount, nullMapCount, updatedChunksTotal;
                private Vec2i startChunkColumn;
 
                private readonly int chunkSize;
@@ -72,13 +74,13 @@ namespace Automap
                        ClientAPI.Event.LevelFinalize += EngageAutomap;
                        configuration = config;
 
-
                        //TODO:Choose which one from GUI 
                        this.ChunkRenderer = new StandardRenderer(clientAPI, logger);
 
                        //Listen on bus for commands
                        ClientAPI.Event.RegisterEventBusListener(CommandListener, 1.0, AutomapSystem.AutomapCommandEventKey);
 
+
                        if (configuration.Autostart)
                        {
                                CurrentState = CommandType.Run;
@@ -93,6 +95,8 @@ namespace Automap
                {
                        path = ClientAPI.GetOrCreateDataPath(_mapPath);
                        path = ClientAPI.GetOrCreateDataPath(Path.Combine(path, "World_" + ClientAPI.World.Seed));//Add name of World too...'ServerApi.WorldManager.CurrentWorldName'
+                       ClientAPI.GetOrCreateDataPath(Path.Combine(path, _chunkPath));
+                                                 
                        JsonGenerator = new JsonGenerator(ClientAPI, Logger, path);
 
                        string mapFilename = Path.Combine(path, "automap.html");
@@ -105,7 +109,6 @@ namespace Automap
                        Prefill_POI_Designators();
                        startChunkColumn = new Vec2i((ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.X / chunkSize), (ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Z / chunkSize));
                        chunkTopMetadata = new ColumnsMetadata(startChunkColumn);
-
                        Logger.Notification("AUTOMAP Start {0}", startChunkColumn);
                        Reload_Metadata();
 
@@ -118,6 +121,14 @@ namespace Automap
                                IsBackground = true
                        };
 
+                       snapshot = new Snapshotter(path, chunkTopMetadata, chunkSize,ClientAPI.World.Seed );
+                       snapshotThread = new Thread(Snap)
+                       {
+                               Name = "Snapshot",
+                               Priority = ThreadPriority.Lowest,
+                               IsBackground = true
+                       };
+
                        ClientAPI.Event.RegisterGameTickListener(AwakenCartographer, 6000);
                }
 
@@ -133,9 +144,9 @@ namespace Automap
 
                        if (CurrentState == CommandType.Run && (ClientAPI.IsGamePaused != false || ClientAPI.IsShuttingDown != true))
                        {
-                               #if DEBUG
+#if DEBUG
                                Logger.VerboseDebug("Cartographer re-trigger from [{0}]", cartographer_thread.ThreadState);
-                               #endif
+#endif
 
                                if (cartographer_thread.ThreadState.HasFlag(ThreadState.Unstarted))
                                {
@@ -152,7 +163,13 @@ namespace Automap
                        }
                        else if (CurrentState == CommandType.Snapshot)
                        {
-                               //TODO: Snapshot generator second thread...
+                               if (snapshotThread.ThreadState.HasFlag(ThreadState.Unstarted))
+                               {
+                                       snapshotThread.Start();
+                               } else if (snapshotThread.ThreadState.HasFlag(ThreadState.WaitSleepJoin))
+                               {
+                                       snapshotThread.Interrupt();
+                               }
                        }
 
                }
@@ -182,7 +199,7 @@ namespace Automap
                                                if (mapChunk == null)
                                                {
                                                        Logger.Warning("SKIP CHUNK: ({0}) - Map Chunk NULL!", mostActiveCol.Key);
-                                                       nullChunkCount++;
+                                                       nullMapCount++;
                                                        columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
                                                        continue;
                                                }
@@ -193,7 +210,6 @@ namespace Automap
                                                        chunkMeta = chunkTopMetadata[mostActiveCol.Key];
 #if DEBUG
                                                        Logger.VerboseDebug("Loaded chunk {0}", mostActiveCol.Key);
-                                                       //Console.WriteLine($"Load {mostActiveCol.Key}");
 #endif
                                                }
                                                else
@@ -201,13 +217,11 @@ namespace Automap
                                                        chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
 #if DEBUG
                                                        Logger.VerboseDebug("Created chunk {0}", mostActiveCol.Key);
-                                                       //Console.WriteLine($"Created chunk {mostActiveCol.Key}");
 #endif
                                                }
-
                                                ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta);
 
-                                               PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
+                                               PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, ref chunkMeta);
                                                ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out updatedPixels);
 
                                                if (updatedPixels > 0)
@@ -222,10 +236,13 @@ namespace Automap
                                                else
                                                {
                                                        columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
+#if DEBUG
                                                        Logger.VerboseDebug("Un-painted chunk: ({0}) ", mostActiveCol.Key);
+#endif
                                                }
-
                                        }
+                                       //Cleanup persisted Metadata...
+                                       chunkTopMetadata.ClearMetadata();
                                }
 
                                UpdateStatus(this.updatedChunksTotal, this.nullChunkCount, updatedChunks);
@@ -239,31 +256,60 @@ namespace Automap
                                }
 
                                //Then sleep until interupted again, and repeat
-
+#if DEBUG
                                Logger.VerboseDebug("Thread '{0}' about to sleep indefinitely.", Thread.CurrentThread.Name);
-
+#endif
                                Thread.Sleep(Timeout.Infinite);
 
                        }
                        catch (ThreadInterruptedException)
                        {
 
+#if DEBUG
                                Logger.VerboseDebug("Thread '{0}' interupted [awoken]", Thread.CurrentThread.Name);
+#endif
                                goto wake;
 
                        }
                        catch (ThreadAbortException)
                        {
+#if DEBUG
                                Logger.VerboseDebug("Thread '{0}' aborted.", Thread.CurrentThread.Name);
-
+#endif
                        }
                        finally
                        {
+#if DEBUG
                                Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name);
+#endif
                                PersistPointsData();
                        }
                }
 
+               private void Snap()
+               {
+                       snapshotTake:
+#if DEBUG
+                       Logger.VerboseDebug("Snapshot started");
+#endif
+                       try
+                       {
+                               snapshot.Take();
+#if DEBUG
+                               Logger.VerboseDebug("Snapshot sleeping");
+#endif
+                               CurrentState = CommandType.Run;
+                               Thread.Sleep(Timeout.Infinite);
+                       }
+                       catch (ThreadInterruptedException)
+                       {
+#if DEBUG
+                               Logger.VerboseDebug("Snapshot intertupted");
+#endif
+                               goto snapshotTake;
+                       }
+               }
+
                private void UpdateStatus(uint totalUpdates, uint voidChunks, uint delta)
                {
                        StatusData updateData = new StatusData(totalUpdates, voidChunks, delta, CommandType.Run);
@@ -310,8 +356,6 @@ namespace Automap
                                        this.Entity_Designators.Add(match.Code, designator);
                                }
 
-
-
                                //EntityProperties props = ClientAPI.World.GetEntityType(designator.Pattern);
                        }
 
@@ -323,54 +367,68 @@ namespace Automap
                /// <summary>
                /// Store Points/Entity of Interest
                /// </summary>
-               private void PersistPointsData( )
+               private void PersistPointsData()
                {
-               //POI and EOI raw dump files ~ WRITE em!
-               //var poiRawFile = File.
-               string poiPath = Path.Combine(path, poiFileName);
-               string eoiPath = Path.Combine(path, eoiFileName);
-
-               if (this.POIs.Count > 0) {
-               using (var poiFile = File.OpenWrite(poiPath)) {
-                       Serializer.Serialize<PointsOfInterest>(poiFile, this.POIs);
-               }
-               }
+                       //POI and EOI raw dump files ~ WRITE em!
+                       //var poiRawFile = File.
+                       string poiPath = Path.Combine(path, poiFileName);
+                       string eoiPath = Path.Combine(path, eoiFileName);
 
-               if (this.EOIs.Count > 0) {
-               using (var eoiFile = File.OpenWrite(eoiPath)) {
-                       Serializer.Serialize<EntitiesOfInterest>(eoiFile, this.EOIs);
-               }
-               }
+                       if (this.POIs.Count > 0)
+                       {
+                               using (var poiFile = File.OpenWrite(poiPath))
+                               {
+                                       Serializer.Serialize<PointsOfInterest>(poiFile, this.POIs);
+                               }
+                       }
 
-               //Create Easy to Parse TSV file for tool/human use....
-               string pointsTsvPath = Path.Combine(path, pointsTsvFileName);
+                       if (this.EOIs.Count > 0)
+                       {
+                               using (var eoiFile = File.OpenWrite(eoiPath))
+                               {
+                                       Serializer.Serialize<EntitiesOfInterest>(eoiFile, this.EOIs);
+                               }
+                       }
 
-               using (var tsvWriter = new StreamWriter(pointsTsvPath, false, Encoding.UTF8))
-               {
-               tsvWriter.WriteLine("Name\tDescription\tLocation\tTime\t");
-                       foreach (var point in this.POIs) {
+                       //Create Easy to Parse TSV file for tool/human use....
+                       string pointsTsvPath = Path.Combine(path, pointsTsvFileName);
+
+                       using (var tsvWriter = new StreamWriter(pointsTsvPath, false, Encoding.UTF8))
+                       {
+                               tsvWriter.WriteLine("Name\tDescription\tLocation\tTime\t");
+                               foreach (var point in this.POIs)
+                               {
                                        tsvWriter.Write(point.Name + "\t");
-                                       tsvWriter.Write(point.Notes + "\t");
+                                       var notes = point.Notes
+                                               .Replace("\n", "\\n")
+                                               .Replace("\t", "\\t")
+                                               .Replace("\\", "\\\\");
+                                       tsvWriter.Write(notes + "\t");
                                        tsvWriter.Write(point.Location.PrettyCoords(ClientAPI) + "\t");
-                                       tsvWriter.Write(point.Timestamp.ToString("u")+"\t");
+                                       tsvWriter.Write(point.Timestamp.ToString("u") + "\t");
                                        tsvWriter.WriteLine();
-                       }
-                       foreach (var entity in this.EOIs) {
+                               }
+                               foreach (var entity in this.EOIs)
+                               {
                                        tsvWriter.Write(entity.Name + "\t");
-                                       tsvWriter.Write(entity.Notes + "\t");
+                                       var notes = entity.Notes
+                                               .Replace("\n", "\\n")
+                                               .Replace("\t", "\\t")
+                                               .Replace("\\", "\\\\");
+                                       tsvWriter.Write(notes + "\t");
                                        tsvWriter.Write(entity.Location.PrettyCoords(ClientAPI) + "\t");
                                        tsvWriter.Write(entity.Timestamp.ToString("u") + "\t");
-                                       tsvWriter.WriteLine( );
+                                       tsvWriter.WriteLine();
+                               }
+                               tsvWriter.WriteLine();
+                               tsvWriter.Flush();
                        }
-               tsvWriter.WriteLine();
-               tsvWriter.Flush( );
-               }
 
                }
 
                private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
                {
-                       ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), (byte) chunkSize);
+                       ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), ClientAPI, (byte) chunkSize);
                        BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize,
                                                                                        mapChunk.YMax,
                                                                                        mostActiveCol.Key.Y * chunkSize);
@@ -387,57 +445,55 @@ namespace Automap
                /// <returns>The metadata.</returns>
                private void Reload_Metadata()
                {
-                       var worldmapDir = new DirectoryInfo(path);
+                       var shardsDir = new DirectoryInfo( Path.Combine(path, _chunkPath) );
 
-                       if (!worldmapDir.Exists)
+                       if (!shardsDir.Exists)
                        {
-#if DEBUG
-                               Logger.VerboseDebug("Could not open world map directory");
-#endif
+                               #if DEBUG
+                               Logger.VerboseDebug("Could not open world map (shards) directory");
+                               #endif
                                return;
                        }
-                       var shardFiles = worldmapDir.GetFiles(chunkFile_filter);
+                       var shardFiles = shardsDir.GetFiles(chunkFile_filter);
 
                        if (shardFiles.Length > 0)
                        {
-#if DEBUG
+                               #if DEBUG
                                Logger.VerboseDebug("Metadata reloading from {0} shards", shardFiles.Length);
-#endif
+                               #endif
 
                                foreach (var shardFile in shardFiles)
                                {
 
                                        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);
+                                       if (!result.Success) continue;
 
-                                               try
-                                               {
-                                                       using (var fileStream = shardFile.OpenRead())
-                                                       {
-
-                                                               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;
-                                                               var column = metadataFromPng.ChunkMetadata;
-                                                               if (column.PrettyLocation == null)
-                                                                       column = column.Reload(ClientAPI);
-                                                               chunkTopMetadata.Add(column);
-                                                       }
+                                       int X_chunk_pos = int.Parse(result.Groups["X"].Value);
+                                       int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
 
-                                               }
-                                               catch (PngjException someEx)
+                                       try
+                                       {
+                                               using (var fileStream = shardFile.OpenRead())
                                                {
-                                                       Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
-                                                       continue;
+
+                                                       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;
+                                                       var column = metadataFromPng.ChunkMetadata;
+                                                       if (column.PrettyLocation == null)
+                                                               column = column.Reload(ClientAPI);
+                                                       chunkTopMetadata.Add(column);
                                                }
-                                       }
 
+                                       }
+                                       catch (PngjException someEx)
+                                       {
+                                               Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
+                                               continue;
+                                       }
                                }
                        }
 
@@ -471,7 +527,7 @@ namespace Automap
                        ImageInfo imageInf = new ImageInfo(chunkSize, chunkSize, 8, false);
 
                        string filename = $"{coord.X}_{coord.Y}.png";
-                       filename = Path.Combine(path, filename);
+                       filename = Path.Combine(path, _chunkPath ,filename);
 
                        PngWriter pngWriter = FileHelper.CreatePngWriter(filename, imageInf, true);
                        PngMetadata meta = pngWriter.GetMetadata();
@@ -509,6 +565,7 @@ namespace Automap
 #if DEBUG
                                        Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
 #endif
+                                       nullChunkCount++;
                                        continue;
                                }
 
@@ -521,59 +578,61 @@ namespace Automap
 
                                        foreach (var blockEnt in chunkData.BlockEntities)
                                        {
-
                                                if (blockEnt != null && blockEnt.Block != null && BlockID_Designators.ContainsKey(blockEnt.Block.BlockId))
                                                {
                                                        var designator = BlockID_Designators[blockEnt.Block.BlockId];
                                                        designator.SpecialAction(ClientAPI, POIs, blockEnt.Pos.Copy(), blockEnt.Block);
                                                }
                                        }
-
                                }
                                /********************* Chunk/Column BLOCKs scanning ****************/
                                //Heightmap, Stats, block tally
                                chunkData.Unpack();
 
-                               int X_index, Y_index, Z_index;
-                               X_index = Y_index = Z_index = 0;
-
-                               do
-                               {
-                                       do
-                                       {
-                                               do
-                                               {
-                                                       /* Encode packed indicie
-                                                       (y * chunksize + z) * chunksize + x
-                                                       */
-                                                       var indicie = Helpers.ChunkBlockIndicie16(X_index, Y_index, Z_index);
-                                                       int aBlockId = chunkData.Blocks[indicie];
-
-                                                       if (aBlockId == 0)
-                                                       {//Air
-                                                               chunkMeta.AirBlocks++;
-                                                               continue;
-                                                       }
-
-                                                       if (RockIdCodes.ContainsKey(aBlockId))
-                                                       {
-                                                               if (chunkMeta.RockRatio.ContainsKey(aBlockId)) { chunkMeta.RockRatio[aBlockId]++; } else { chunkMeta.RockRatio.Add(aBlockId, 1); }
-                                                       }
-
-                                                       chunkMeta.NonAirBlocks++;
-
-                                                       //Heightmap 
-                                                       if (chunkMeta.HeightMap[X_index, Z_index] == 0)
-                                                       { chunkMeta.HeightMap[X_index, Z_index] = (ushort) (Y_index + (targetChunkY * chunkSize)); }
-
-                                               }
-                                               while (X_index++ < (chunkSize - 1));
-                                               X_index = 0;
-                                       }
-                                       while (Z_index++ < (chunkSize - 1));
-                                       Z_index = 0;
-                               }
-                               while (Y_index++ < (chunkSize - 1));
+                               //int X_index, Y_index, Z_index;
+
+                               //Ensure ChunkData Metadata fields arn't null...due to being tossed out
+                               //if (chunkMeta.HeightMap == null) { chunkMeta.HeightMap = new ushort[chunkSize, chunkSize]; }
+                               //if (chunkMeta.RockRatio == null) { chunkMeta.RockRatio = new Dictionary<int, uint>(10); }
+
+                               //for (Y_index = 0; Y_index < chunkSize - 1; Y_index++)
+                               //{
+                               //      for (Z_index = 0; Z_index < chunkSize - 1; Z_index++)
+                               //      {
+                               //              for (X_index = 0; X_index < chunkSize - 1; X_index++)
+                               //              {
+                               //                      /* Encode packed indicie
+                               //                      (y * chunksize + z) * chunksize + x
+                               //                      */
+                               //                      var indicie = Helpers.ChunkBlockIndicie16(X_index, Y_index, Z_index);
+                               //                      int aBlockId = chunkData.Blocks[indicie];
+
+                               //                      if (aBlockId == 0)
+                               //                      {//Air
+                               //                              chunkMeta.AirBlocks++;
+                               //                              continue;
+                               //                      }
+
+                               //                      if (RockIdCodes.ContainsKey(aBlockId))
+                               //                      {
+                               //                              if (chunkMeta.RockRatio.ContainsKey(aBlockId))
+                               //                                      chunkMeta.RockRatio[aBlockId]++;
+                               //                              else
+                               //                                      chunkMeta.RockRatio.Add(aBlockId, 1);
+                               //                      }
+
+                               //                      chunkMeta.NonAirBlocks++;
+
+                               //                      //Heightmap 
+                               //                      //if (chunkMeta.HeightMap[X_index, Z_index] == 0)
+                               //                      //{
+
+                               //                      //      chunkMeta.HeightMap[X_index, Z_index] = (ushort) (Y_index + (targetChunkY * chunkSize));
+                               //                      //}
+                               //              }
+                               //      }
+
+                               //}
 
                        }
                }
@@ -617,48 +676,31 @@ namespace Automap
 
                private void CommandListener(string eventName, ref EnumHandling handling, IAttribute data)
                {
-                       Logger.VerboseDebug("MsgBus RX: AutomapCommandMsg: {0}", data.ToJsonToken());
+                       //Logger.VerboseDebug("MsgBus RX: AutomapCommandMsg: {0}", data.ToJsonToken());
 
                        CommandData cmdData = data as CommandData;
 
-
-                       if (CurrentState != CommandType.Snapshot)
+                       switch (cmdData.State)
                        {
-                               switch (cmdData.State)
-                               {
-                                       case CommandType.Run:
-                                       case CommandType.Stop:
-                                               if (CurrentState != cmdData.State)
-                                               {
-                                                       CurrentState = cmdData.State;
-                                                       AwakenCartographer(0.0f);
-                                               }
-                                               break;
-
-                                       case CommandType.Snapshot:
-                                               CurrentState = CommandType.Stop;
-                                               //Snapshot starts a second thread/process...
-
-                                               break;
+                               case CommandType.Run:
+                               case CommandType.Stop:
+                               case CommandType.Snapshot:
+                                       if (CurrentState != cmdData.State)
+                                       {
+                                               CurrentState = cmdData.State;
+                                               AwakenCartographer(0.0f);
+                                       }
+                                       break;
 
-                                       case CommandType.Notation:
-                                               //Add to POI list where player location
-                                               AddNote(cmdData.Notation);
-                                               break;
-                               }
+                               case CommandType.Notation:
+                                       //Add to POI list where player location
+                                       AddNote(cmdData.Notation);
+                                       break;
                        }
-
-
-
 #if DEBUG
                        ClientAPI.TriggerChatMessage($"Automap commanded to: {cmdData.State} ");
 #endif
-
                }
-
-
-
-
                #endregion
 
        }