OSDN Git Service

Merge branch 'vgd' of into Split_renderers
authormelchior <melchior@users.osdn.me>
Mon, 30 Mar 2020 15:35:38 +0000 (11:35 -0400)
committermelchior <melchior@users.osdn.me>
Mon, 30 Mar 2020 15:35:38 +0000 (11:35 -0400)
(Pass 1, absent new Json generation, incomplete)

Automap/Automap.csproj
Automap/Data/EntitiesOfInterest.cs
Automap/Data/PointOfInterest.cs
Automap/Designators/DefaultDesignators.cs
Automap/Subsystems/AutomapGUIDialog.cs
Automap/Subsystems/AutomapSystem.cs
Automap/Subsystems/JsonGenerator.cs [new file with mode: 0644]

index 24c5382..68b2350 100644 (file)
@@ -96,6 +96,7 @@
     <Compile Include="Data\CommandType.cs" />
     <Compile Include="Data\PersistedConfiguration.cs" />
     <Compile Include="Data\DisplayNameAttribute.cs" />
+    <Compile Include="Subsystems\JsonGenerator.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="VS_libs\" />
index 1da27e9..e006d3c 100644 (file)
@@ -3,38 +3,44 @@ using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.IO;
 using System.Linq;
+
 using Vintagestory.API.Common.Entities;
 using Vintagestory.API.MathTools;
 using Vintagestory.API.Client;
 
+using ProtoBuf;
+
+using Newtonsoft.Json;
+
 namespace Automap
 {
        /// <summary>
        /// Basically the same as a POI but for an entity
        /// </summary>
+       [ProtoContract]
        public struct EntityOfInterest
        {
+               
+               [ProtoMember(1)]
+               public string Name;
+               
                [DisplayName(1, "Notes")]
+               [ProtoMember(2)]
                public string Notes;
+
                [DisplayName(0, "Loc.")]
+               [ProtoMember(3)]
                public BlockPos Location;
+
                [DisplayName(2, "Time")]
-               public DateTimeOffset Timestamp;
+               [ProtoMember(4)]
+               public DateTime Timestamp;
+
                [DisplayName(3, "ID")]
+               [ProtoMember(5)]
                public long EntityId;
-               public void Write(StreamWriter stream, ICoreClientAPI ClientApi)
-               {
-                       // this is gross i hate this
-                       stream.Write("['{0}_{1}',[",
-                               Location.X,
-                               Location.Y
-                               );
-                       stream.Write("'{0}',", Location.PrettyCoords(ClientApi));
-                       stream.Write("'{0}',", System.Web.HttpUtility.HtmlEncode(Notes));
-                       stream.Write("'{0}',", Timestamp);
-                       stream.Write("'{0}',", EntityId);
-                       stream.Write("]]");
-               }
+
+
        }
 
        /// <summary>
index 4876957..a65c827 100644 (file)
@@ -1,35 +1,39 @@
 using System;
 using System.Collections.ObjectModel;
 using System.IO;
+
 using Vintagestory.API.Client;
 using Vintagestory.API.Common;
 using Vintagestory.API.MathTools;
 
+using ProtoBuf;
+
+using Newtonsoft.Json;
+
 namespace Automap
 {
        /// <summary>
        /// Actual Physical Point in space - that is interesting.
        /// </summary>
+       [ProtoContract]
        public struct PointOfInterest
        {
+               [ProtoMember(1)]
+               public string Name;
+
                [DisplayName(1, "Notes")]
+               [ProtoMember(2)]
                public string Notes;
+
                [DisplayName(0, "Loc.")]
+               [ProtoMember(3)]
                public BlockPos Location;
+
                [DisplayName(2, "Time")]
-               public DateTimeOffset Timestamp;
-               public void Write(StreamWriter stream, ICoreClientAPI ClientApi)
-               {
-                       // this is gross i hate this
-                       stream.Write("['{0}_{1}',[",
-                               Location.X,
-                               Location.Y
-                               );
-                       stream.Write("'{0}',", Location.PrettyCoords(ClientApi));
-                       stream.Write("'{0}',", System.Web.HttpUtility.HtmlEncode(Notes).Replace("\n", "&#13;&#10;").Replace("\\","\\\\"));
-                       stream.Write("'{0}',", Timestamp);
-                       stream.Write("]]");
-               }
+               [ProtoMember(4)]
+               public DateTime Timestamp;
+
+
        }
 
        public class PointsOfInterest : KeyedCollection<BlockPos, PointOfInterest>
index f406d97..929d618 100644 (file)
@@ -97,9 +97,10 @@ namespace Automap
                                poi.AddReplace(
                                                        new PointOfInterest
                                                        {
+                                                               Name = "Sign",
                                                                Location = posn.Copy(),
                                                                Notes = signEntity.text,
-                                                               Timestamp = DateTimeOffset.UtcNow,
+                                                               Timestamp = DateTime.UtcNow,
                                                        }
                                                        );
 
@@ -122,9 +123,10 @@ namespace Automap
                                poi.AddReplace(
                                                        new PointOfInterest
                                                        {
+                                                               Name = "Signpost",
                                                                Location = posn.Copy(),
                                                                Notes = string.Join(",", signEntity.textByCardinalDirection),
-                                                               Timestamp = DateTimeOffset.UtcNow,
+                                                               Timestamp = DateTime.UtcNow,
                                                        }
                                                        );
 
@@ -143,9 +145,10 @@ namespace Automap
                        }
                        poi.AddReplace(new EntityOfInterest
                        {
+                               Name = "Trader",
                                Location = posn.Copy(),
                                Notes = message,
-                               Timestamp = DateTimeOffset.UtcNow,
+                               Timestamp = DateTime.UtcNow,
                                EntityId = entity.EntityId
                        });
                }
@@ -170,9 +173,10 @@ namespace Automap
                                poi.AddReplace(
                                                        new PointOfInterest
                                                        {
+                                                               Name = "Translocator",
                                                                Location = posn.Copy(),
                                                                Notes = textTarget.ToString(),
-                                                               Timestamp = DateTimeOffset.UtcNow,
+                                                               Timestamp = DateTime.UtcNow,
                                                        }
                                                        );
 
index c1a1f82..a325263 100644 (file)
@@ -125,7 +125,7 @@ namespace Automap
                internal void RunToggle(bool toggle)
                {
                        Logger.VerboseDebug("Dialog Changed; [ Automap Enabled: {0} ]", toggle);
-                       var statusText = this.SingleComposer.GetDynamicText(_statusTextKey);
+
                        UpdateDashDisplay(0f);
                                                 
                        CommandData cmd = new CommandData(toggle ? CommandType.Run : CommandType.Stop);
@@ -169,15 +169,28 @@ namespace Automap
                        var btnRun = this.SingleComposer.GetToggleButton(_btnRunKey);
 
                        if (lastState == CommandType.Run) {
-                       statusText.SetNewText($"State: {lastState}, Total: {totalShards}, Delta: +{changesThisTick} Nulls: {voidShards} ");
-                       btnRun.SetValue(true);
+                       statusText.SetNewText($"State: {lastState}, Total: {totalShards}, Delta: ±{changesThisTick} Nulls: {voidShards} ");
+                       
+                       if (!btnRun.On) btnRun.SetValue(true);
+
+                       LockGUIElements(true);  
                        }
-                       else if (lastState == CommandType.Stop) {
+                       else if (lastState == CommandType.Stop && btnRun.Enabled) {
                        statusText.SetNewText($"State: {lastState}, Total: {totalShards}, Nulls: {voidShards} ");                       
-                       btnRun.SetValue(false);
+                       
+                       if (btnRun.On) btnRun.SetValue(false);
+
+                       LockGUIElements(true);
                        }
                }
 
+               private void LockGUIElements(bool state)
+               {
+               var swAutostart = this.SingleComposer.GetSwitch(_swAutostart);
+
+               swAutostart.Enabled = state;
+
+               }
 
        }
 }
index 53a785f..858a563 100644 (file)
@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Concurrent;
 using System.Collections.Generic;
-using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Reflection;
@@ -14,6 +13,8 @@ using Hjg.Pngcs.Chunks;
 
 using Newtonsoft.Json;
 
+using ProtoBuf;
+
 using Vintagestory.API.Client;
 using Vintagestory.API.Common;
 using Vintagestory.API.Config;
@@ -29,11 +30,15 @@ namespace Automap
                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";
                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 ConcurrentDictionary<Vec2i, uint> columnCounter = new ConcurrentDictionary<Vec2i, uint>(3, 150);
@@ -59,7 +64,7 @@ namespace Automap
 
                public static string AutomapStatusEventKey = @"AutomapStatus";
                public static string AutomapCommandEventKey = @"AutomapCommand";
-               //PersistedConfiguration cachedConfiguration;
+               PersistedConfiguration cachedConfiguration;
 
                public AutomapSystem(ICoreClientAPI clientAPI, ILogger logger, PersistedConfiguration config)
                {
@@ -70,7 +75,6 @@ namespace Automap
                        configuration = config;
 
 
-
                        //TODO:Choose which one from GUI 
                        this.ChunkRenderer = new StandardRenderer(clientAPI, logger);
 
@@ -91,7 +95,7 @@ namespace Automap
                {
                        path = ClientAPI.GetOrCreateDataPath(_mapPath);
                        path = ClientAPI.GetOrCreateDataPath(Path.Combine(path, "World_" + ClientAPI.World.Seed));//Add name of World too...'ServerApi.WorldManager.CurrentWorldName'
-
+                       JsonGenerator = new JsonGenerator(ClientAPI, Logger, path);
 
                        string mapFilename = Path.Combine(path, "automap.html");
                        StreamWriter outputText = new StreamWriter(File.Open(mapFilename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite));
@@ -100,7 +104,7 @@ namespace Automap
                        outputText.Write(staticMap.ToText());
                        outputText.Flush();
 
-                       MakePreBuiltJSON();
+                       jsonPreBuilt = JsonGenerator.MakePreBuiltJSON();
 
                        Prefill_POI_Designators();
                        startChunkColumn = new Vec2i((ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.X / chunkSize), (ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Z / chunkSize));
@@ -133,15 +137,15 @@ 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(System.Threading.ThreadState.Unstarted))
+                               if (cartographer_thread.ThreadState.HasFlag(ThreadState.Unstarted))
                                {
                                        cartographer_thread.Start();
                                }
-                               else if (cartographer_thread.ThreadState.HasFlag(System.Threading.ThreadState.WaitSleepJoin))
+                               else if (cartographer_thread.ThreadState.HasFlag(ThreadState.WaitSleepJoin))
                                {
                                        //Time to (re)write chunk shards
                                        cartographer_thread.Interrupt();
@@ -205,9 +209,9 @@ namespace Automap
                                                if (updatedPixels > 0)
                                                {
 
-#if DEBUG
+                                                       #if DEBUG
                                                        Logger.VerboseDebug("Wrote chunk shard: ({0}) - Edits#:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, updatedPixels);
-#endif
+                                                       #endif
                                                        updatedChunks++;
                                                        chunkTopMetadata.Update(chunkMeta);
                                                        columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
@@ -227,7 +231,7 @@ namespace Automap
                                {
                                        //What about chunk updates themselves; a update bitmap isn't kept...
                                        updatedChunksTotal += updatedChunks;
-                                       GenerateJSONMetadata();
+                                       JsonGenerator.GenerateJSONMetadata(chunkTopMetadata, startChunkColumn, POIs, EOIs, RockIdCodes);
                                        updatedChunks = 0;
                                }
 
@@ -253,6 +257,7 @@ namespace Automap
                        finally
                        {
                                Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name);
+                               PersistPointsData( );
                        }
                }
 
@@ -310,97 +315,55 @@ namespace Automap
 
                }
 
+
+
                /// <summary>
-               /// Generates the JSON Metadata. (in Map object format )
+               /// Store Points/Entity of Interest
                /// </summary>
-               private void GenerateJSONMetadata()
+               private void PersistPointsData( )
                {
-                       string jsonFilename = Path.Combine(path, "Metadata.js");
-
-                       StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
-
-                       using (stream)
-                       {
-                               Stopwatch stopWatch = new Stopwatch();
-                               stopWatch.Start();
-
-                               stream.Write(jsonPreBuilt);
-
-                               stream.Write("ViewFrame.chunks.genTime='{0}';",
-                                       DateTimeOffset.UtcNow
-                                       );
-
-                               stream.Write("ViewFrame.chunks.startCoords=[{0},{1}];",
-                                       startChunkColumn.X, startChunkColumn.Y
-                                       );
-
-                               stream.Write("ViewFrame.chunks.bounds=[{0},{1},{2},{3}];",
-                                       chunkTopMetadata.North_mostChunk,
-                                       chunkTopMetadata.South_mostChunk,
-                                       chunkTopMetadata.West_mostChunk,
-                                       chunkTopMetadata.East_mostChunk
-                                       );
-
-
-                               //MAP object format - [key, value]: key is "x_y"
-                               stream.Write("ViewFrame.chunks.chunkMetadata=new Map([");
-
-                               foreach (var shard in chunkTopMetadata)
-                               {
-                                       shard.Write(stream, ClientAPI);
-                                       stream.Write(",");
-                               }
-                               stream.Write("]);");// Close constructor of Map (chunkMetadata)
-
-
-                               stream.Write("ViewFrame.chunks.pointsOfInterest=new Map([");
-
-                               foreach (var poi in POIs)
-                               {
-                                       poi.Write(stream, ClientAPI);
-                                       stream.Write(",");
-                               }
-
-                               stream.Write("]);");
-
-                               stream.Write("ViewFrame.chunks.entitiesOfInterest=new Map([");
-                               foreach (var eoi in EOIs)
-                               {
-                                       eoi.Write(stream, ClientAPI);
-                                       stream.Write(",");
-                               }
-                               stream.Write("]);\n");
-
-                               //stream.Write("//============= BlockID's for Rockmap / Rock-ratios ===============");
-
-                               //stream.Write("ViewFrame.chunks.rockLookup=new Map([");
-
-                               //foreach (var entry in RockIdCodes)
-                               //{
-                               //      var block = ClientAPI.World.GetBlock(entry.Key);
-
-                               //      stream.Write("[");
-                               //      stream.Write("'{0},", block.Code.Path);
-
-                               //      stream.Write("[");
-                               //      stream.Write("'{0}',", entry.Value);
-
-                               //      stream.Write("{0},", Lang.GetUnformatted(block.Code.Path));
-                               //      //Color?
-
-                               //      stream.Write("]],");
-                               //}
+               //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);
+               }
+               }
 
-                               //stream.Write("]);\n");
+               if (this.EOIs.Count > 0) {
+               using (var eoiFile = File.OpenWrite(eoiPath)) {
+                       Serializer.Serialize<EntitiesOfInterest>(eoiFile, this.EOIs);
+               }
+               }
 
-                               stream.Flush();
+               //Create Easy to Parse TSV file for tool/human use....
+               string pointsTsvPath = Path.Combine(path, pointsTsvFileName);
 
-                               stopWatch.Stop();
-                               Logger.Debug("Run time of chunk write {0}", stopWatch.Elapsed);
+               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");
+                                       tsvWriter.Write(point.Location.PrettyCoords(ClientAPI) + "\t");
+                                       tsvWriter.Write(point.Timestamp.ToString("u")+"\t");
+                                       tsvWriter.WriteLine();
                        }
-
+                       foreach (var entity in this.EOIs) {
+                                       tsvWriter.Write(entity.Name + "\t");
+                                       tsvWriter.Write(entity.Notes + "\t");
+                                       tsvWriter.Write(entity.Location.PrettyCoords(ClientAPI) + "\t");
+                                       tsvWriter.Write(entity.Timestamp.ToString("u") + "\t");
+                                       tsvWriter.WriteLine( );
+                       }
+               tsvWriter.WriteLine();
+               tsvWriter.Flush( );
                }
 
+               }
 
                private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
                {
@@ -426,56 +389,71 @@ namespace Automap
                        if (worldmapDir.Exists)
                        {
 
-                               var files = worldmapDir.GetFiles(chunkFile_filter);
+                               var shardFiles = worldmapDir.GetFiles(chunkFile_filter);
 
-                               if (files.Length > 0)
+                               if (shardFiles.Length > 0)
                                {
-#if DEBUG
-                                       Logger.VerboseDebug("{0} Existing world chunk shards", files.Length);
-#endif
-
-                                       foreach (var shardFile in files)
-                                       {
-
-                                               if (shardFile.Length < 1024) continue;
-                                               var result = chunkShardRegex.Match(shardFile.Name);
-                                               if (result.Success)
+                                       #if DEBUG
+                                       Logger.VerboseDebug("Metadata reloading from {0} shards", shardFiles.Length);
+                                       #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);
+
+                                       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( )) {
 
-                                                       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;
+                                               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;
 
-                                                                       chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
-                                                               }
+                                               chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
+                                               }
 
-                                                       }
-                                                       catch (PngjException someEx)
-                                                       {
-                                                               Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
-                                                               continue;
-                                                       }
+                                               }
+                                               catch (PngjException someEx)
+                                               {
+                                                       Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
+                                                       continue;
+                                               }
                                                }
 
                                        }
                                }
 
+                               //POI and EOI raw dump files ~ reload em!
+                               //var poiRawFile = File.
+                               string poiPath = Path.Combine(path, poiFileName);
+                               string eoiPath = Path.Combine(path, eoiFileName);
+
+                               if (File.Exists(poiPath)) {
+                                       using (var poiFile = File.OpenRead(poiPath)) {
+                                       this.POIs = Serializer.Deserialize<PointsOfInterest>(poiFile);
+                                       Logger.VerboseDebug("Reloaded {0} POIs from file.", this.POIs.Count);
+                                       }
+                               }
+
+                               if (File.Exists(eoiPath)) {
+                                       using (var eoiFile = File.OpenRead(eoiPath)) {
+                                       this.EOIs = Serializer.Deserialize<EntitiesOfInterest>(eoiFile);
+                                       Logger.VerboseDebug("Reloaded {0} EOIs from file.", this.EOIs.Count);
+                                       }
+                               }
 
                        }
                        else
                        {
-#if DEBUG
+                               #if DEBUG
                                Logger.VerboseDebug("Could not open world map directory");
-#endif
+                               #endif
                        }
 
 
@@ -518,21 +496,21 @@ namespace Automap
                        int targetChunkY = mapChunk.YMax / chunkSize;//Surface ... 
                        for (; targetChunkY > 0; targetChunkY--)
                        {
-                               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;
-                               }
+                       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)
                                        {
@@ -576,6 +554,11 @@ namespace Automap
                                                        }
 
                                                        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;
@@ -595,14 +578,13 @@ namespace Automap
                        foreach (var loadedEntity in ClientAPI.World.LoadedEntities.ToArray())
                        {
 
-#if DEBUG
+                               #if DEBUG
                                //Logger.VerboseDebug($"ENTITY: ({loadedEntity.Value.Code}) = #{loadedEntity.Value.EntityId} {loadedEntity.Value.State} {loadedEntity.Value.LocalPos}    <<<<<<<<<<<<");
-#endif
+                               #endif
 
                                var dMatch = Entity_Designators.SingleOrDefault(se => se.Key.Equals(loadedEntity.Value.Code));
                                if (dMatch.Value != null)
                                {
-                                       Logger.Chat("Entity designator hit!");
                                        dMatch.Value.SpecialAction(ClientAPI, this.EOIs, loadedEntity.Value.LocalPos.AsBlockPos.Copy(), loadedEntity.Value);
                                }
 
@@ -615,9 +597,10 @@ namespace Automap
                {
                        var playerNodePoi = new PointOfInterest()
                        {
+                               Name = "Note",
                                Location = ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Copy(),
                                Notes = notation,
-                               Timestamp = DateTimeOffset.UtcNow,
+                               Timestamp = DateTime.UtcNow,
                        };
 
                        this.POIs.AddReplace(playerNodePoi);
@@ -636,13 +619,12 @@ namespace Automap
                        {
                                switch (cmdData.State)
                                {
-                                       case CommandType.Run:
-                                               CurrentState = cmdData.State;
-                                               AwakenCartographer(0.0f);
-                                               break;
-
+                                       case CommandType.Run:                                                                                           
                                        case CommandType.Stop:
+                                               if (CurrentState != cmdData.State) {
                                                CurrentState = cmdData.State;
+                                               AwakenCartographer(0.0f);
+                                               }
                                                break;
 
                                        case CommandType.Snapshot:
@@ -656,83 +638,21 @@ namespace Automap
                                                AddNote(cmdData.Notation);
                                                break;
                                }
-
                        }
 
-                       if (CurrentState != cmdData.State)
-                       {
-                               CurrentState = cmdData.State;
-                               AwakenCartographer(0.0f);
-                       }
+
 
 #if DEBUG
-                       Logger.VerboseDebug($"Automap commanded to: {cmdData.State} ");
+                       ClientAPI.TriggerChatMessage($"Automap commanded to: {cmdData.State} ");
 #endif
 
                }
 
 
-               private void MakePreBuiltJSON()
-               {
-                       var builder = new StringBuilder(512);
-                       builder.Append("ViewFrame.chunks={};\n");
-                       builder.AppendFormat("ViewFrame.chunks.worldSeedNum='{0}';",
-                                       ClientAPI.World.Seed
-                                       );
-                       builder.AppendFormat("ViewFrame.chunks.chunkSize={0};",
-                                       chunkSize
-                                       );
-
-                       builder.Append("ViewFrame.chunks.chunkMetadataNames=[");
-                       var fields = typeof(ColumnMeta).GetFields();
-                       var attsToSort = new List<DisplayNameAttribute>();
-                       // this is so gross
-                       foreach (var f in fields)
-                       {
-                               var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
-                               if (att != null)
-                               {
-                                       attsToSort.Add((DisplayNameAttribute) att);
-                               }
-
-                       }
-                       foreach (var att in attsToSort.OrderBy(a => a.order))
-                               builder.AppendFormat("'{0}',", att.name);
-                       builder.Append("];\n");
-
-                       builder.Append("ViewFrame.chunks.pointsOfInterestNames=[");
-                       fields = typeof(PointOfInterest).GetFields();
-                       attsToSort = new List<DisplayNameAttribute>();
 
-                       foreach (var f in fields)
-                       {
-                               var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
-                               if (att != null)
-                                       attsToSort.Add((DisplayNameAttribute) att);
-                       }
-                       foreach (var att in attsToSort.OrderBy(a => a.order))
-                               builder.AppendFormat("'{0}',", att.name);
-                       builder.Append("];\n");
-
-                       builder.Append("ViewFrame.chunks.entityOfInterestNames=[");
-                       fields = typeof(EntityOfInterest).GetFields();
-                       attsToSort = new List<DisplayNameAttribute>();
-
-                       foreach (var f in fields)
-                       {
-                               var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
-                               if (att != null)
-                                       attsToSort.Add((DisplayNameAttribute) att);
-                       }
-                       foreach (var att in attsToSort.OrderBy(a => a.order))
-                               builder.AppendFormat("'{0}',", att.name);
-                       builder.Append("];\n");
-
-                       jsonPreBuilt = builder.ToString();
-               }
 
                #endregion
 
        }
 
-}
\ No newline at end of file
+}
diff --git a/Automap/Subsystems/JsonGenerator.cs b/Automap/Subsystems/JsonGenerator.cs
new file mode 100644 (file)
index 0000000..b74689f
--- /dev/null
@@ -0,0 +1,318 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using Newtonsoft.Json;
+
+using Vintagestory.API.Client;
+using Vintagestory.API.Common;
+using Vintagestory.API.Config;
+using Vintagestory.API.Datastructures;
+using Vintagestory.API.MathTools;
+using Vintagestory.Common;
+
+
+
+namespace Automap
+{
+       public class JsonGenerator
+       {
+               private ICoreClientAPI ClientAPI { get; set; }
+               private ILogger Logger { get; set; }
+               private string path { get; set; }
+               private readonly int chunkSize;
+
+
+               public JsonGenerator(ICoreClientAPI _ClientAPI,  ILogger _Logger, string _path )
+               {
+               this.ClientAPI = _ClientAPI;
+               this.Logger = _Logger;
+               this.path = _path;
+               this.chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
+               }
+
+
+               /// <summary>
+               /// Generates the JSON Metadata. (in Map object format )
+               /// </summary>
+               public void GenerateJSONMetadata(ColumnsMetadata chunkTopMetadata, Vec2i startChunkColumn, PointsOfInterest POIs, EntitiesOfInterest EOIs, Dictionary<int, string> RockIdCodes )
+               {
+               string jsonFilename = Path.Combine(path, "Metadata.js");
+
+               StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
+
+               using (stream) {
+               JsonTextWriter jsonWriter = new JsonTextWriter(stream);
+
+               jsonWriter.Formatting = Formatting.None;
+               jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
+               jsonWriter.Indentation = 0;
+               //jsonWriter.AutoCompleteOnClose = true;
+               jsonWriter.QuoteChar = '\'';
+               jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
+               jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
+
+               using (jsonWriter) {
+               jsonWriter.WriteRaw("ViewFrame.chunks={};\n");
+               jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum=");
+               jsonWriter.WriteValue(ClientAPI.World.Seed);
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.genTime=");
+               jsonWriter.WriteValue(DateTimeOffset.UtcNow);
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.startCoords=");
+               jsonWriter.WriteStartArray( );
+               jsonWriter.WriteValue(startChunkColumn.X);
+               jsonWriter.WriteValue(startChunkColumn.Y);
+               jsonWriter.WriteEndArray( );
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize=");
+               jsonWriter.WriteValue(chunkSize);
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk=");
+               jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk);
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk=");
+               jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk);
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.westMostChunk=");
+               jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk);
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.eastMostChunk=");
+               jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk);
+               jsonWriter.WriteRaw(";\n");
+
+
+               //MAP object format - [key, value]: key is "x_y"
+               jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata=");
+               jsonWriter.WriteStartConstructor("Map");
+               jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+
+               foreach (var shard in chunkTopMetadata) {
+               jsonWriter.WriteStartArray( );//Start tuple
+               jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple
+
+               jsonWriter.WriteStartObject( );
+               jsonWriter.WritePropertyName("prettyCoord");
+               jsonWriter.WriteValue(shard.Location.PrettyCoords(ClientAPI));
+
+               jsonWriter.WritePropertyName("chunkAge");
+               jsonWriter.WriteValue(shard.ChunkAge);
+
+               jsonWriter.WritePropertyName("temp");
+               jsonWriter.WriteValue(shard.Temperature);
+
+               jsonWriter.WritePropertyName("YMax");
+               jsonWriter.WriteValue(shard.YMax);
+
+               jsonWriter.WritePropertyName("fert");
+               jsonWriter.WriteValue(shard.Fertility);
+
+               jsonWriter.WritePropertyName("forestDens");
+               jsonWriter.WriteValue(shard.ForestDensity);
+
+               jsonWriter.WritePropertyName("rain");
+               jsonWriter.WriteValue(shard.Rainfall);
+
+               jsonWriter.WritePropertyName("shrubDens");
+               jsonWriter.WriteValue(shard.ShrubDensity);
+
+               jsonWriter.WritePropertyName("airBlocks");
+               jsonWriter.WriteValue(shard.AirBlocks);
+
+               jsonWriter.WritePropertyName("nonAirBlocks");
+               jsonWriter.WriteValue(shard.NonAirBlocks);
+
+               //TODO: Heightmap ?
+               //Start rockMap ; FOR a Ratio....on tooltip GUI
+               jsonWriter.WritePropertyName("rockRatio");
+               jsonWriter.WriteStartConstructor("Map");
+               jsonWriter.WriteStartArray( );
+               foreach (var rockEntry in shard.RockRatio) {
+               var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key);
+               jsonWriter.WriteStartArray( );
+               jsonWriter.WriteValue(rockBlock.Code.Path);
+               jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column
+               jsonWriter.WriteEndArray( );
+               }
+               jsonWriter.WriteEndArray( );
+               jsonWriter.WriteEndConstructor( );//end rock-map
+
+               jsonWriter.WriteEndObject( );//end Map value: {Object}
+               jsonWriter.WriteEndArray( );//end Tuple
+               }
+
+               jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata
+               jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata)
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest=");
+               jsonWriter.WriteStartConstructor("Map");
+               jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+               foreach (var poi in POIs) {
+               EmitJsonMap(poi, jsonWriter);
+               }
+
+               foreach (var poi in EOIs) {
+               EmitJsonMap(poi, jsonWriter);
+               }
+
+               jsonWriter.WriteEndArray( );
+               jsonWriter.WriteEndConstructor( );
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.WriteWhitespace("\n");
+               jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
+               jsonWriter.WriteWhitespace("\n");
+
+               jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup =");
+               jsonWriter.WriteStartConstructor("Map");
+               jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+               foreach (var entry in RockIdCodes) {
+               var block = ClientAPI.World.GetBlock(entry.Key);
+               //      stream.Write("{0},", Lang.GetUnformatted(block.Code.Path));
+               jsonWriter.WriteStartArray( );
+               jsonWriter.WriteValue(block.Code.Path);
+
+               jsonWriter.WriteStartObject( );
+               jsonWriter.WritePropertyName("assetCode");
+               jsonWriter.WriteValue(entry.Value);
+
+               jsonWriter.WritePropertyName("name");
+               jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path));
+               //}
+
+               jsonWriter.WriteEndObject( );
+               jsonWriter.WriteEndArray( );
+               }
+               jsonWriter.WriteEndArray( );
+               jsonWriter.WriteEndConstructor( );
+               //stream.Write("]);\n");
+               jsonWriter.WriteRaw(";\n");
+
+               jsonWriter.Flush( );
+               }
+               }
+
+               }
+
+               public void EmitJsonMap(PointOfInterest @this, JsonTextWriter jsonWriter)
+               {
+               jsonWriter.WriteStartArray( );
+               jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}");
+
+               jsonWriter.WriteStartArray( );
+               //jsonWriter.WriteValue(@this.Name);
+
+               jsonWriter.WriteValue(@this.Location.X);
+               jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world
+
+               jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI));
+
+               jsonWriter.WriteValue(@this.Notes);//put more escaping in Java-script if needed
+
+               jsonWriter.WriteValue(@this.Timestamp);
+
+               jsonWriter.WriteEndArray( );
+               jsonWriter.WriteEndArray( );
+               }
+
+               public void EmitJsonMap(EntityOfInterest @this, JsonTextWriter jsonWriter)
+               {
+               jsonWriter.WriteStartArray( );
+               jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}");
+
+
+               jsonWriter.WriteStartArray( );
+               //jsonWriter.WriteValue(@this.Name);
+
+               jsonWriter.WriteValue(@this.Location.X);
+               jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world
+
+               jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI));
+
+               jsonWriter.WriteValue(@this.Notes);//put more escaping in Java-script if needed
+
+               jsonWriter.WriteValue(@this.Timestamp);
+
+               jsonWriter.WriteValue(@this.EntityId);          
+
+               jsonWriter.WriteEndArray( );
+               jsonWriter.WriteEndArray( );
+               }
+
+               /// <summary>
+               /// Dynamically reflect Points-of-Something fields for metadata descriptors
+               /// </summary>
+               /// <returns>Json-array  names of fields for use in map display.</returns>
+               public string MakePreBuiltJSON( )
+               {
+               var builder = new StringBuilder(512);
+               builder.Append("ViewFrame.chunks={};\n");
+               builder.AppendFormat("ViewFrame.chunks.worldSeedNum='{0}';",
+                               ClientAPI.World.Seed
+                               );
+               builder.AppendFormat("ViewFrame.chunks.chunkSize={0};",
+                               chunkSize
+                               );
+
+               builder.Append("ViewFrame.chunks.chunkMetadataNames=[");
+               var fields = typeof(ColumnMeta).GetFields( );
+               var attsToSort = new List<DisplayNameAttribute>( );
+               // this is so gross
+               foreach (var f in fields) {
+               var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
+               if (att != null) {
+               attsToSort.Add(( DisplayNameAttribute )att);
+               }
+
+               }
+               foreach (var att in attsToSort.OrderBy(a => a.order))
+                       builder.AppendFormat("'{0}',", att.name);
+               builder.Append("];\n");
+
+               builder.Append("ViewFrame.chunks.pointsOfInterestNames=[");
+               fields = typeof(PointOfInterest).GetFields( );
+               attsToSort = new List<DisplayNameAttribute>( );
+
+               foreach (var f in fields) {
+               var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
+               if (att != null)
+                       attsToSort.Add(( DisplayNameAttribute )att);
+               }
+               foreach (var att in attsToSort.OrderBy(a => a.order))
+                       builder.AppendFormat("'{0}',", att.name);
+               builder.Append("];\n");
+
+               builder.Append("ViewFrame.chunks.entityOfInterestNames=[");
+               fields = typeof(EntityOfInterest).GetFields( );
+               attsToSort = new List<DisplayNameAttribute>( );
+
+               foreach (var f in fields) {
+               var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
+               if (att != null)
+                       attsToSort.Add(( DisplayNameAttribute )att);
+               }
+               foreach (var att in attsToSort.OrderBy(a => a.order))
+                       builder.AppendFormat("'{0}',", att.name);
+               builder.Append("];\n");
+
+               return builder.ToString( );
+               }
+       }
+}
+