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)

17 files changed:
Automap/Automap.csproj
Automap/Data/BlockDesignator.cs
Automap/Data/ColumnMeta.cs
Automap/Data/DisplayNameAttribute.cs [new file with mode: 0644]
Automap/Data/EntitiesOfInterest.cs
Automap/Data/EntityDesignator.cs
Automap/Data/PointOfInterest.cs
Automap/Designators/DefaultDesignators.cs
Automap/MapSRC/build.js [new file with mode: 0755]
Automap/MapSRC/src/Automap.css [new file with mode: 0644]
Automap/MapSRC/src/Automap.html [new file with mode: 0644]
Automap/MapSRC/src/ViewFrame.js [new file with mode: 0644]
Automap/MapSRC/src/ViewFrameUtils.js [new file with mode: 0644]
Automap/MapSRC/src/index.js [new file with mode: 0644]
Automap/Renderers/StandardRenderer.cs [moved from Automap/Renderers/StandardRenerer.cs with 100% similarity]
Automap/Subsystems/AutomapSystem.cs
Automap/Subsystems/JsonGenerator.cs [new file with mode: 0644]

index cc48c10..68b2350 100644 (file)
     <Compile Include="AutomapMod.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Helpers.cs" />
-    <Compile Include="Data\PointOfInterest.cs" />
-    <Compile Include="Data\BlockDesignator.cs" />
-    <Compile Include="Designators\DefaultDesignators.cs" />
-    <Compile Include="Data\ColumnMeta.cs" />
+               <Compile Include="Data\PointOfInterest.cs" />
+               <Compile Include="Data\BlockDesignator.cs" />
+               <Compile Include="Data\EntitiesOfInterest.cs" />
+               <Compile Include="Data\EntityDesignator.cs" />
+               <Compile Include="Data\ColumnMeta.cs" />
     <Compile Include="Data\PngMetadataChunk.cs" />
+               <Compile Include="Designators\DefaultDesignators.cs" />
     <Compile Include="Subsystems\AutomapSystem.cs" />
     <Compile Include="Subsystems\AutomapGUIDialog.cs" />
     <Compile Include="Renderers\IChunkRenderer.cs" />
-    <Compile Include="Renderers\StandardRenerer.cs" />
+    <Compile Include="Renderers\StandardRenderer.cs" />
     <Compile Include="Renderers\AlternateRenderer.cs" />
-    <Compile Include="Data\EntitiesOfInterest.cs" />
-    <Compile Include="Data\EntityDesignator.cs" />
     <Compile Include="Data\StatusData.cs" />
     <Compile Include="Data\CommandData.cs" />
     <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 f7ef845..8511308 100644 (file)
@@ -12,7 +12,7 @@ using Vintagestory.API.MathTools;
 
 namespace Automap
 {
-       public delegate void BlockDesignatonAction(ICoreClientAPI clientAPI, PointsOfInterest poi, BlockPos posn, Block block);
+       public delegate void BlockDesignatorAction(ICoreClientAPI clientAPI, PointsOfInterest poi, BlockPos posn, Block block);
 
        /// <summary>
        /// Point of Interest Rule Designator
@@ -24,7 +24,7 @@ namespace Automap
                public Color OverwriteColor;
 
                [JsonIgnore]
-               public BlockDesignatonAction SpecialAction;
+               public BlockDesignatorAction SpecialAction;
 
                [JsonProperty]
                public string SpecialActionName;
@@ -51,7 +51,7 @@ namespace Automap
                        this.Enabled = true;
                }
 
-               public BlockDesignator(AssetLocation pattern, Color overwriteColor, EnumBlockMaterial? material, BlockDesignatonAction specialAct)
+               public BlockDesignator(AssetLocation pattern, Color overwriteColor, EnumBlockMaterial? material, BlockDesignatorAction specialAct)
                {
                        this.Pattern = pattern;
                        this.OverwriteColor = overwriteColor;
index 102fa2d..9fd9aef 100644 (file)
@@ -1,6 +1,5 @@
 using System;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.Collections.Specialized;
 
 
@@ -8,7 +7,10 @@ using Vintagestory.API.MathTools;
 using Vintagestory.API.Common;
 
 using ProtoBuf;
-
+using System.IO;
+using System.Collections.ObjectModel;
+using System.Text;
+using Vintagestory.API.Client;
 
 namespace Automap
 {
@@ -16,36 +18,47 @@ namespace Automap
        public struct ColumnMeta
        {
                [ProtoMember(1)]
+               [DisplayName(0, "Coords.")]
                public Vec2i Location;
 
                [ProtoMember(2)]
+               [DisplayName(1, "Age")]
                public TimeSpan ChunkAge;//OLDEST CHUNK. from chunk last edit
 
                [ProtoMember(3)]
+               [DisplayName(2, "Temp.")]
                public float Temperature;// Temperature - surface
 
                [ProtoMember(4)]
+               [DisplayName(3, "Y Max.")]
                public ushort YMax;// Y feature height
 
                [ProtoMember(5)]
+               //[DisplayName(10, "Rocks")]
                public Dictionary<int, uint> RockRatio;//[Column] Geographic region (rock) Ratio. [BlockID * count]
 
                [ProtoMember(6)]
+               [DisplayName(4, "Fert.")]
                public float Fertility;
 
                [ProtoMember(7)]
+               [DisplayName(5, "Forest")]
                public float ForestDensity;
 
                [ProtoMember(8)]
+               [DisplayName(6, "Rain")]
                public float Rainfall;
 
                [ProtoMember(9)]
+               [DisplayName(7, "Shrub")]
                public float ShrubDensity;
 
                [ProtoMember(10)]
+               [DisplayName(8, "Air blocks")]
                public uint AirBlocks;
 
                [ProtoMember(11)]
+               [DisplayName(9, "Non-air")]
                public uint NonAirBlocks;
 
                [ProtoMember(12)]
@@ -56,7 +69,7 @@ namespace Automap
                public ushort[,] HeightMap;//Needs to be 'flattened' for Protocol-Buffer serialization
 
                [ProtoMember(13)]
-               private ushort[ ] _flattened_HeightMap;
+               private ushort[] _flattened_HeightMap;
 
 
                public ColumnMeta(Vec2i loc, byte chunkSize = 32)
@@ -89,48 +102,70 @@ namespace Automap
                        this.YMax = mapChunk.YMax;
                }
 
-
+               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}',", ChunkAge);
+                       stream.Write("'{0}',", Temperature.ToString("F3"));
+                       stream.Write("'{0}',", YMax);
+                       stream.Write("'{0}',", Fertility.ToString("F3"));
+                       stream.Write("'{0}',", ForestDensity.ToString("F3"));
+                       stream.Write("'{0}',", Rainfall.ToString("F3"));
+                       stream.Write("'{0}',", ShrubDensity.ToString("F3"));
+                       stream.Write("'{0}',", AirBlocks);
+                       stream.Write("'{0}',", NonAirBlocks);
+                       stream.Write("]]");
+               }
 
                [ProtoBeforeSerialization]
-               private void PrepareData( )
+               private void PrepareData()
                {
 
-               if (HeightMap != null) {
-                       _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
-               int flatIndex = 0;
+                       if (HeightMap != null)
+                       {
+                               _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
+                               int flatIndex = 0;
+
+                               for (byte col = 0; col < ChunkSize; col++)
+                               {
+                                       for (byte row = 0; row < ChunkSize; row++)
+                                       {
+                                               _flattened_HeightMap[flatIndex] = HeightMap[col, row];
+                                               flatIndex++;
+                                       }
+                               }
 
-               for (byte col = 0; col < ChunkSize; col++) {
-                       for (byte row = 0; row < ChunkSize; row++) {
-                       _flattened_HeightMap[flatIndex] = HeightMap[col, row];
-                       flatIndex++;
                        }
-               }
-
-               }
 
                }
 
 
                [ProtoAfterDeserialization]
-               private void PostProcess( )
+               private void PostProcess()
                {
-               if (this.HeightMap == null)     this.HeightMap = new ushort[ChunkSize, ChunkSize];
-
-               if (_flattened_HeightMap != null) {
-               int col, row;
+                       if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize];
 
-               BitVector32 bitMasker = new BitVector32(0);
-               var rowSection = BitVector32.CreateSection(( short )(ChunkSize - 1));
-               var colSection = BitVector32.CreateSection(( short )(ChunkSize - 1), rowSection);
-
-               for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++) {
-               bitMasker = new BitVector32(data: ( int )rowcol);
-               row = bitMasker[rowSection];
-               col = bitMasker[colSection];
-               HeightMap[col, row] = _flattened_HeightMap[rowcol];
-               }
+                       if (_flattened_HeightMap != null)
+                       {
+                               int col, row;
+                               _ = new BitVector32(0);
+                               var rowSection = BitVector32.CreateSection((short) (ChunkSize - 1));
+                               var colSection = BitVector32.CreateSection((short) (ChunkSize - 1), rowSection);
+
+                               for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++)
+                               {
+                                       BitVector32 bitMasker = new BitVector32(data: (int) rowcol);
+                                       row = bitMasker[rowSection];
+                                       col = bitMasker[colSection];
+                                       HeightMap[col, row] = _flattened_HeightMap[rowcol];
+                               }
 
-               }
+                       }
 
                }
 
@@ -217,5 +252,4 @@ namespace Automap
                }
 
        }
-}
-
+}
\ No newline at end of file
diff --git a/Automap/Data/DisplayNameAttribute.cs b/Automap/Data/DisplayNameAttribute.cs
new file mode 100644 (file)
index 0000000..c767fb3
--- /dev/null
@@ -0,0 +1,17 @@
+using System;
+using System.Reflection;
+
+namespace Automap
+{
+       [AttributeUsage(AttributeTargets.Field)]
+       public class DisplayNameAttribute : Attribute
+       {
+               public string name;
+               public byte order;
+               public DisplayNameAttribute(byte order, string name)
+               {
+                       this.order = order;
+                       this.name = name;
+               }
+       }
+}
\ No newline at end of file
index 3d5042d..e006d3c 100644 (file)
@@ -1,36 +1,46 @@
 using System;
 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>
-       /// Actual Physical Point in space - that is interesting.
+       /// 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")]
                [ProtoMember(4)]
                public DateTime Timestamp;
 
+               [DisplayName(3, "ID")]
                [ProtoMember(5)]
                public long EntityId;
+
+
        }
 
        /// <summary>
@@ -39,6 +49,8 @@ namespace Automap
        /// <remarks>Tracked by ID - these never leave.</remarks>
        public class EntitiesOfInterest : KeyedCollection<long, EntityOfInterest>
        {
+               protected override long GetKeyForItem(EntityOfInterest item)
+                       => item.EntityId;
 
                internal void AddReplace(EntityOfInterest entity)
                {
@@ -48,8 +60,6 @@ namespace Automap
                        Add(entity);
                }
 
-               protected override long GetKeyForItem(EntityOfInterest item)
-                       => item.EntityId;
        }
 }
 
index 77ffe00..50dd7a8 100644 (file)
@@ -13,7 +13,7 @@ using Vintagestory.API.MathTools;
 
 namespace Automap
 {
-       public delegate void EntityDesignatonAction(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity);
+       public delegate void EntityDesignatorAction(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity);
 
        /// <summary>
        /// Point of Interest Rule Designator
@@ -25,7 +25,7 @@ namespace Automap
                public Color Color;
 
                [JsonIgnore]
-               public EntityDesignatonAction SpecialAction;
+               public EntityDesignatorAction SpecialAction;
 
                [JsonProperty]
                public string SpecialActionName;
@@ -52,7 +52,7 @@ namespace Automap
                        Enabled = true;
                }
 
-               public EntityDesignator(AssetLocation pattern, Color color, EnumEntityState? state, EntityDesignatonAction specialAct)
+               public EntityDesignator(AssetLocation pattern, Color color, EnumEntityState? state, EntityDesignatorAction specialAct)
                {
                        Pattern = pattern;
                        Color = color;
index 16f49ff..a65c827 100644 (file)
@@ -1,11 +1,15 @@
 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>
@@ -17,14 +21,19 @@ namespace Automap
                [ProtoMember(1)]
                public string Name;
 
+               [DisplayName(1, "Notes")]
                [ProtoMember(2)]
                public string Notes;
 
+               [DisplayName(0, "Loc.")]
                [ProtoMember(3)]
                public BlockPos Location;
 
+               [DisplayName(2, "Time")]
                [ProtoMember(4)]
                public DateTime Timestamp;
+
+
        }
 
        public class PointsOfInterest : KeyedCollection<BlockPos, PointOfInterest>
index a8adfb9..929d618 100644 (file)
@@ -135,7 +135,7 @@ namespace Automap
 
                internal static void KeepTrackOfMerchant(ICoreClientAPI clientAPI, EntitiesOfInterest poi, BlockPos posn, Entity entity)
                {
-                       clientAPI.Logger.VerboseDebug("Trader: {0} @ {1}", entity.GetName(), posn);
+                       //clientAPI.Logger.VerboseDebug("Trader: {0} @ {1}", entity.GetName(), posn);
 
                        var traderJoe = entity as EntityTrader;
                        var message = $"{entity.GetName()} Alive: {traderJoe.Alive}";
diff --git a/Automap/MapSRC/build.js b/Automap/MapSRC/build.js
new file mode 100755 (executable)
index 0000000..7875da0
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/local/bin/node
+
+// im sorry
+// cd into MapSRC and run node ./build.js and this will concat and stuff
+const fs = require('fs');
+
+fs.readFile('./src/Automap.html', 'utf8', (err, d) => {
+       if (err) console.log(err);
+       let outD = d.replace(/<link rel=\"stylesheet\" href=\"(.*)\">/g, '<style>REP:$1</style>')
+               .replace(/(<script type=\"text\/javascript\") src=\"(.*)\">/g, '$1>REP:$2')
+               .replace(/REP:(\w*\.\w*)/g, (match, name, offset, string) => {
+                       return fs.readFileSync('./src/' + name, 'utf8')
+                               .replace(/\/\/.*\n?/g, '');
+               })
+               .replace(/[\t\n]/g, '');
+       fs.writeFile('./dist/automap.html', outD, err => {
+               if (err) console.log(err);
+       });
+       fs.writeFile('../assets/automap/config/automap.html', outD, err => {
+               if (err) console.log(err);
+       });
+});
\ No newline at end of file
diff --git a/Automap/MapSRC/src/Automap.css b/Automap/MapSRC/src/Automap.css
new file mode 100644 (file)
index 0000000..44e30e5
--- /dev/null
@@ -0,0 +1,38 @@
+html, body, .map {
+       width: 100%;
+       height: 100%;
+       margin: 0;
+       overflow: hidden;
+       outline: 1px dotted black;
+}
+
+.infobox {
+       width: 15em;
+       /* height: 15em; */
+       background-color: rgba(200, 200, 200, 0.5);
+       left: 0;
+       top: 0;
+       font-family: sans-serif;
+       position: absolute;
+       z-index: 1;
+}
+
+h1 {
+       font-size: 22px;
+       margin: .6em 1em;
+       text-align: center;
+}
+
+.infoboxTable {
+       margin: .3em auto;
+       width: 90%;
+       outline: 1px solid #333;
+}
+
+.infoboxTable th {
+       width: 30%;
+}
+
+.infoboxTable td {
+       text-align: right;
+}
\ No newline at end of file
diff --git a/Automap/MapSRC/src/Automap.html b/Automap/MapSRC/src/Automap.html
new file mode 100644 (file)
index 0000000..5b9ef8a
--- /dev/null
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<html lang="en" dir="ltr">
+
+<head>
+       <meta charset="utf-8">
+       <title>Automap</title>
+       <link rel="stylesheet" href="Automap.css">
+</head>
+
+<body>
+       <script type="text/javascript" src="ViewFrame.js"></script>
+       <script type="text/javascript" src="ViewFrameUtils.js"></script>
+       <div class="infobox">
+               <h1>Chunk Info</h1>
+               <table class="infoboxTable">
+               </table>
+       </div>
+       <script type="text/javascript" src="index.js"></script>
+
+</body>
+
+</html>
\ No newline at end of file
diff --git a/Automap/MapSRC/src/ViewFrame.js b/Automap/MapSRC/src/ViewFrame.js
new file mode 100644 (file)
index 0000000..663a50f
--- /dev/null
@@ -0,0 +1,140 @@
+function ViewFrame() {
+       // dom stuff
+       const map = document.createElement('canvas'); // the map we see
+       map.className = 'map';
+       map.height = window.innerHeight;
+       map.width = window.innerWidth;
+       document.getElementsByTagName('body')[0].append(map);
+       // this is the map that we actually draw on
+       this.map = map.getContext('2d', {
+               alpha: false
+       });
+       this.map.imageSmoothingEnabled = false;
+
+       // the info box in the corner
+       this.infobox = document.getElementsByClassName('infoboxTable')[0];
+       this.infoboxSlots = new Array();
+
+       // load the metadata!
+       this.chunkScript = document.createElement('script');
+       this.chunkScript.type = 'text/javascript';
+       this.chunkScript.src = 'Metadata.js';
+       document.getElementsByTagName('body')[0].append(this.chunkScript);
+       this.chunkScript.addEventListener('load', () => {
+               ViewFrame.initInfobox(this.infobox, this.infoboxSlots);
+               this.x = ViewFrame.chunks.startCoords[0];
+               this.y = ViewFrame.chunks.startCoords[1];
+               this.availableChunks = ViewFrame.chunks.chunkMetadata;
+               this.render();
+       }, {
+               once: true
+       });
+
+       // Tracks images that have been loaded and are on the map
+       this.loadedChunksByName = new Map();
+       // this is needed because [1, 2] != [1, 2] and thats how we store coords.
+       this.loadedChunksByCoords = new Map();
+       this.availableChunks = null; // the chunks in ./Metadata.js
+       // so that we dont render twice at the same time
+       this.rendering = false;
+
+       this.x = -1;
+       this.y = -1; // can be fractional
+       this.zoom = 32; // pixels wide the images are to be
+       this.updateEdges();
+}
+// prototypes, some less... notable? methods are
+// in ViewFrameUtils.js 
+ViewFrame.prototype.reloadChunkList = function () {
+       if (this.chunkScript) {
+               this.chunkScript.remove();
+               delete this.chunkScript;
+       }
+
+       this.chunkScript = document.createElement('script');
+       this.chunkScript.type = 'text/javascript';
+       this.chunkScript.src = 'Metadata.js';
+       document.getElementsByTagName('body')[0].append(this.chunkScript);
+
+       this.chunkScript.addEventListener('load', () => {
+               this.availableChunks = ViewFrame.chunks.chunkMetadata;
+               this.render();
+       });
+};
+
+ViewFrame.prototype.render = function () {
+       if (!this.availableChunks) return;
+       if (this.rendering) clearInterval(ViewFrame.intervalRef);
+       this.rendering = true;
+       this.updateEdges();
+       this.map.clearRect(0, 0, window.innerWidth, window.innerHeight);
+       // culling
+       this.loadedChunksByCoords
+               .forEach((chunk, coord) => { // check the bounds
+                       if (coord[0] < this.eastChunk &&
+                               coord[0] >= this.westChunk &&
+                               coord[1] <= this.northChunk &&
+                               coord[1] >= this.southChunk) {
+
+                               this.place(chunk, coord[0], coord[1]);
+                               return;
+                       }
+                       // its out of range!!!
+                       // get 'em boys!!!!!
+                       this.loadedChunksByCoords.delete(coord);
+                       this.loadedChunksByName.delete(coord.join('_'));
+                       chunk.remove();
+               });
+
+       // gathering what we need to load
+       const neededChunks = new Set();
+       for (var x = this.westChunk; x < this.eastChunk; x++) {
+               for (var y = this.southChunk; y < this.northChunk; y++) {
+                       const chunKey = [x, y]; // chunk + key = chunKey :)
+                       const name = chunKey.join('_');
+                       // continue if its not available, or it is loaded
+                       if (!this.availableChunks.has(name) ||
+                               this.loadedChunksByName.has(name)) continue;
+                       neededChunks.add(chunKey);
+               }
+       }
+       // iterating over everything we need to load
+       const it = neededChunks.values();
+       ViewFrame.intervalRef = setInterval(() => {
+               let round = it.next();
+               if (!round.done) {
+                       // load
+                       const img = new Image(32, 32);
+                       const name = round.value.join('_');
+
+                       img.src = name + '.png';
+
+                       decode(img, loadedImage => {
+                               this.place(img, round.value[0], round.value[1]);
+                       });
+                       this.loadedChunksByName.set(name, img);
+                       this.loadedChunksByCoords.set(round.value, img);
+               } else {
+                       clearInterval(ViewFrame.intervalRef);
+                       this.rendering = false;
+               }
+       }, 4);
+};
+
+ViewFrame.prototype.place = function (img, x, y) {
+       x -= this.x;
+       y -= this.y;
+       x *= this.zoom;
+       y *= this.zoom;
+       x += this.width / 2;
+       y += this.height / 2;
+
+       this.map.drawImage(img, Math.floor(x), Math.floor(y), this.zoom, this.zoom);
+};
+
+ViewFrame.prototype.updateInfobox = function (chunkName) {
+       const chunkMeta = this.availableChunks.get(chunkName);
+       this.infoboxSlots.forEach((l, k) => {
+               l.innerText = chunkMeta ? chunkMeta[k] : '0';
+       });
+};
\ No newline at end of file
diff --git a/Automap/MapSRC/src/ViewFrameUtils.js b/Automap/MapSRC/src/ViewFrameUtils.js
new file mode 100644 (file)
index 0000000..dc35335
--- /dev/null
@@ -0,0 +1,62 @@
+ViewFrame.initInfobox = function (ibox, iboxSlots) {
+
+       ViewFrame.chunks
+               .chunkMetadataNames.forEach((item, i) => {
+                       const slot = document.createElement('tr');
+                       const head = document.createElement('th');
+                       head.innerText = item;
+                       const row = document.createElement('td');
+                       row.innerText = '0';
+                       iboxSlots[i] = row;
+                       slot.append(head, row);
+                       ibox.append(slot);
+               });
+};
+
+ViewFrame.prototype.updateEdges = function () {
+       if (this.width != window.innerWidth || this.height != window.innerHeight) {
+               this.width = window.innerWidth;
+               this.map.canvas.width = this.width;
+               this.height = window.innerHeight;
+               this.map.canvas.height = this.height;
+               this.map.imageSmoothingEnabled = false;
+       }
+       const chunksWide = Math.ceil(this.width / this.zoom);
+       const chunksHigh = Math.ceil(this.height / this.zoom);
+
+       this.east = this.x + chunksWide / 2; // this is fractional and is used to keep track of the edges of the window
+       this.eastChunk = Math.ceil(this.east); // this is not and is used to track the chunks that need to load
+       this.west = this.x - chunksWide / 2;
+       this.westChunk = Math.floor(this.west);
+       this.north = this.y + chunksHigh / 2;
+       this.northChunk = Math.ceil(this.north);
+       this.south = this.y - chunksHigh / 2;
+       this.southChunk = Math.floor(this.south);
+};
+
+ViewFrame.prototype.moveCenter = function (dx, dy) {
+       // to pan when we click on the map!
+       this.x += (dx - this.width / 2) / this.zoom;
+       this.y += (dy - this.height / 2) / this.zoom;
+};
+ViewFrame.prototype.setCenter = function (x, y) {
+       this.x = x;
+       this.y = y;
+};
+
+ViewFrame.prototype.clear = function () {
+       this.loadedChunksByName.clear();
+       this.loadedChunksByCoords.clear();
+       if (this.chunkScript) this.chunkScript.remove();
+       delete this.chunkScript;
+       delete ViewFrame.chunks;
+       this.map.clearRect(0, 0, window.innerWidth, window.innerHeight);
+};
+
+function decode(img, cb) {
+       img.decode()
+               .then(() => {
+                       cb(img);
+               })
+               .catch(() => {}); // so images arent added on error
+}
\ No newline at end of file
diff --git a/Automap/MapSRC/src/index.js b/Automap/MapSRC/src/index.js
new file mode 100644 (file)
index 0000000..386dc6a
--- /dev/null
@@ -0,0 +1,93 @@
+const vf = new ViewFrame();
+vf.reloadChunkList();
+
+// the event handlers are in iifes so they dont make unneeded globals.
+// resize, delay re-render to reduce lag.
+(function () {
+       var id;
+       window.addEventListener('resize', () => {
+               clearTimeout(id);
+               id = setTimeout(() => {
+                       vf.render();
+               }, 500);
+       });
+}());
+
+// panning
+(function () {
+       var id;
+       vf.map.canvas.addEventListener('mousedown', event => {
+               clearTimeout(id);
+               vf.moveCenter(event.pageX, event.pageY);
+               id = setTimeout(() => {
+                       vf.render();
+               }, 250);
+       });
+}());
+
+
+// #### CONTROLS ####
+// hovering
+(function () {
+       var lastX = 0;
+       var lastY = 0;
+       vf.map.canvas.addEventListener('mousemove', event => {
+               // only count if the mouse moved more than a chunk
+               let x = Math.floor(vf.x +
+                       (event.clientX - vf.width / 2) / vf.zoom);
+               let y = Math.floor(vf.y +
+                       (event.clientY - vf.height / 2) / vf.zoom);
+               if (x == lastX && y == lastY) return;
+               lastX = x;
+               lastY = y;
+               vf.updateInfobox(x + '_' + y);
+       });
+}());
+
+// scroll/zoom
+(function () {
+       var id;
+       vf.map.canvas.addEventListener('wheel', event => {
+               clearTimeout(id);
+               vf.zoom += -Math.sign(event.deltaY);
+               id = setTimeout(() => {
+                       vf.render();
+               }, 250);
+       });
+}());
+
+// reload the chunk list every six seconds
+(function () {
+       setInterval(() => {
+               vf.reloadChunkList();
+       }, 6000);
+}());
+// 
+// var i = 500;
+// setTimeout(() => {
+//     vf.map.dispatchEvent(new MouseEvent('mousedown', {
+//             clientX: 879,
+//             clientY: 926
+//     }));
+// }, i += 1000);
+// 
+// setTimeout(() => {
+//     vf.map.dispatchEvent(new MouseEvent('mousedown', {
+//             clientX: 666,
+//             clientY: 924
+//     }));
+// }, i += 2000);
+// 
+// setTimeout(() => {
+//     vf.map.dispatchEvent(new MouseEvent('mousedown', {
+//             clientX: 1090,
+//             clientY: 936
+//     }));
+// }, i += 2000);
+// 
+// setTimeout(() => {
+//     vf.map.dispatchEvent(new MouseEvent('mousedown', {
+//             clientX: 29,
+//             clientY: 785
+//     }));
+// }, i += 2000);
\ No newline at end of file
index 8295017..858a563 100644 (file)
@@ -3,6 +3,7 @@ using System.Collections.Concurrent;
 using System.Collections.Generic;
 using System.IO;
 using System.Linq;
+using System.Reflection;
 using System.Text;
 using System.Text.RegularExpressions;
 using System.Threading;
@@ -29,6 +30,7 @@ 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";
@@ -43,6 +45,7 @@ namespace Automap
                private ColumnsMetadata chunkTopMetadata;
                private PointsOfInterest POIs = new PointsOfInterest();
                private EntitiesOfInterest EOIs = new EntitiesOfInterest();
+               private string jsonPreBuilt;
 
                internal Dictionary<int, BlockDesignator> BlockID_Designators { get; private set; }
                internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; }
@@ -72,14 +75,13 @@ namespace Automap
                        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) 
+                       if (configuration.Autostart)
                        {
                                CurrentState = CommandType.Run;
                                Logger.Debug("Autostart is Enabled.");
@@ -93,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));
@@ -102,6 +104,8 @@ namespace Automap
                        outputText.Write(staticMap.ToText());
                        outputText.Flush();
 
+                       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));
                        chunkTopMetadata = new ColumnsMetadata(startChunkColumn);
@@ -173,7 +177,7 @@ namespace Automap
                                if (!columnCounter.IsEmpty)
                                {
                                        var tempSet = columnCounter.ToArray().OrderByDescending(kvp => kvp.Value);
-                                       UpdateEntityMetadata( );
+                                       UpdateEntityMetadata();
 
                                        foreach (var mostActiveCol in tempSet)
                                        {
@@ -188,11 +192,13 @@ namespace Automap
                                                }
 
                                                ColumnMeta chunkMeta;
-                                               if (chunkTopMetadata.Contains(mostActiveCol.Key)) {
-                                               chunkMeta = chunkTopMetadata[mostActiveCol.Key];
+                                               if (chunkTopMetadata.Contains(mostActiveCol.Key))
+                                               {
+                                                       chunkMeta = chunkTopMetadata[mostActiveCol.Key];
                                                }
-                                               else {
-                                               chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
+                                               else
+                                               {
+                                                       chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
                                                }
 
                                                ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta);
@@ -225,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;
                                }
 
@@ -275,7 +281,7 @@ namespace Automap
                }
 
                private void Reload_POI_Designators()
-               {                       
+               {
                        Logger.VerboseDebug("Connecting {0} Configured Block-Designators", configuration.BlockDesignators.Count);
                        foreach (var designator in configuration.BlockDesignators)
                        {
@@ -310,223 +316,6 @@ namespace Automap
                }
 
 
-               /// <summary>
-               /// Generates the JSON Metadata. (in Map object format )
-               /// </summary>
-               private void GenerateJSONMetadata()
-               {
-                       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)
-                               {
-                                       jsonWriter.WriteStartArray( );
-                                       jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
-
-                                       jsonWriter.WriteStartObject();
-                                       jsonWriter.WritePropertyName("Name");
-                                       jsonWriter.WriteValue(poi.Name);
-                                       
-                                       jsonWriter.WritePropertyName("prettyCoord");
-                                       jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI) );
-
-                                       jsonWriter.WritePropertyName("notes");
-                                       jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
-
-                                       jsonWriter.WritePropertyName("time");
-                                       jsonWriter.WriteValue(poi.Timestamp);
-                                       
-                                       jsonWriter.WritePropertyName("chunkPos");
-                                       jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
-                                       
-                                       jsonWriter.WriteEndObject( );
-                                       jsonWriter.WriteEndArray( );
-                               }
-
-                               foreach (var poi in EOIs)
-                               {
-                                       jsonWriter.WriteStartArray( );
-                                       jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
-
-                                       jsonWriter.WriteStartObject( );
-                                       jsonWriter.WritePropertyName("Name");
-                                       jsonWriter.WriteValue(poi.Name);
-
-                                       jsonWriter.WritePropertyName("prettyCoord");
-                                       jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI));
-
-                                       jsonWriter.WritePropertyName("notes");
-                                       jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
-
-                                       jsonWriter.WritePropertyName("time");
-                                       jsonWriter.WriteValue(poi.Timestamp);
-
-                                       jsonWriter.WritePropertyName("chunkPos");
-                                       jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
-
-                                       jsonWriter.WriteEndObject( );
-                                       jsonWriter.WriteEndArray( );
-                               }
-
-                               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);
-                               
-                               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));
-                               //Color?
-
-                               jsonWriter.WriteEndObject( );
-                               jsonWriter.WriteEndArray( );
-                               }
-                               jsonWriter.WriteEndArray( );
-                               jsonWriter.WriteEndConstructor();
-                               
-                               jsonWriter.WriteRaw(";\n");
-
-                               jsonWriter.Flush();
-                       }
-                       }
-
-               }
 
                /// <summary>
                /// Store Points/Entity of Interest
@@ -550,7 +339,7 @@ namespace Automap
                }
                }
 
-               //Create Easy to Parse CSV file for tool/human use....
+               //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))
@@ -578,7 +367,7 @@ namespace Automap
 
                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(), (byte) chunkSize);
                        BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize,
                                                                                        mapChunk.YMax,
                                                                                        mostActiveCol.Key.Y * chunkSize);
@@ -630,12 +419,12 @@ namespace Automap
                                                }
 
                                                }
-                                               catch (PngjException someEx) 
+                                               catch (PngjException someEx)
                                                {
-                                                       Logger.Error("PNG Corruption in file '{0}' - Reason: {1}", shardFile.Name, someEx);
+                                                       Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
                                                        continue;
                                                }
-                                       }
+                                               }
 
                                        }
                                }
@@ -860,8 +649,10 @@ namespace Automap
                }
 
 
+
+
                #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( );
+               }
+       }
+}
+