From cdc29d29d788f9126faee33e48c4f65968b49702 Mon Sep 17 00:00:00 2001 From: The Grand Dog Date: Sat, 28 Mar 2020 14:44:50 -0400 Subject: [PATCH] fully implement the most advanced version of the map so far there are SO many changes --- Automap/Automap.csproj | 1 + Automap/Data/ColumnMeta.cs | 100 +++++++---- Automap/Data/DisplayNameAttribute.cs | 17 ++ Automap/Data/EntitiesOfInterest.cs | 21 ++- Automap/Data/PointOfInterest.cs | 18 +- Automap/MapSRC/build.js | 22 +++ Automap/MapSRC/src/Automap.css | 38 +++++ Automap/MapSRC/src/Automap.html | 22 +++ Automap/MapSRC/src/ViewFrame.js | 140 ++++++++++++++++ Automap/MapSRC/src/ViewFrameUtils.js | 62 +++++++ Automap/MapSRC/src/index.js | 93 +++++++++++ Automap/Subsystems/AutomapSystem.cs | 315 ++++++++++++++--------------------- 12 files changed, 622 insertions(+), 227 deletions(-) create mode 100644 Automap/Data/DisplayNameAttribute.cs create mode 100755 Automap/MapSRC/build.js create mode 100644 Automap/MapSRC/src/Automap.css create mode 100644 Automap/MapSRC/src/Automap.html create mode 100644 Automap/MapSRC/src/ViewFrame.js create mode 100644 Automap/MapSRC/src/ViewFrameUtils.js create mode 100644 Automap/MapSRC/src/index.js diff --git a/Automap/Automap.csproj b/Automap/Automap.csproj index 76f41bb..24c5382 100644 --- a/Automap/Automap.csproj +++ b/Automap/Automap.csproj @@ -95,6 +95,7 @@ + diff --git a/Automap/Data/ColumnMeta.cs b/Automap/Data/ColumnMeta.cs index 102fa2d..9fd9aef 100644 --- a/Automap/Data/ColumnMeta.cs +++ b/Automap/Data/ColumnMeta.cs @@ -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 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 index 0000000..c767fb3 --- /dev/null +++ b/Automap/Data/DisplayNameAttribute.cs @@ -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 diff --git a/Automap/Data/EntitiesOfInterest.cs b/Automap/Data/EntitiesOfInterest.cs index 9760c3b..1da27e9 100644 --- a/Automap/Data/EntitiesOfInterest.cs +++ b/Automap/Data/EntitiesOfInterest.cs @@ -1,11 +1,11 @@ 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; namespace Automap { @@ -14,10 +14,27 @@ namespace Automap /// public struct EntityOfInterest { + [DisplayName(1, "Notes")] public string Notes; + [DisplayName(0, "Loc.")] public BlockPos Location; + [DisplayName(2, "Time")] public DateTimeOffset Timestamp; + [DisplayName(3, "ID")] 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("]]"); + } } /// diff --git a/Automap/Data/PointOfInterest.cs b/Automap/Data/PointOfInterest.cs index b19335d..4876957 100644 --- a/Automap/Data/PointOfInterest.cs +++ b/Automap/Data/PointOfInterest.cs @@ -1,6 +1,7 @@ using System; using System.Collections.ObjectModel; - +using System.IO; +using Vintagestory.API.Client; using Vintagestory.API.Common; using Vintagestory.API.MathTools; @@ -11,9 +12,24 @@ namespace Automap /// public struct PointOfInterest { + [DisplayName(1, "Notes")] public string Notes; + [DisplayName(0, "Loc.")] 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", " ").Replace("\\","\\\\")); + stream.Write("'{0}',", Timestamp); + stream.Write("]]"); + } } public class PointsOfInterest : KeyedCollection diff --git a/Automap/MapSRC/build.js b/Automap/MapSRC/build.js new file mode 100755 index 0000000..7875da0 --- /dev/null +++ b/Automap/MapSRC/build.js @@ -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(//g, '') + .replace(/( + +
+

Chunk Info

+ +
+
+ + + + + \ No newline at end of file diff --git a/Automap/MapSRC/src/ViewFrame.js b/Automap/MapSRC/src/ViewFrame.js new file mode 100644 index 0000000..663a50f --- /dev/null +++ b/Automap/MapSRC/src/ViewFrame.js @@ -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 index 0000000..dc35335 --- /dev/null +++ b/Automap/MapSRC/src/ViewFrameUtils.js @@ -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 index 0000000..386dc6a --- /dev/null +++ b/Automap/MapSRC/src/index.js @@ -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 diff --git a/Automap/Subsystems/AutomapSystem.cs b/Automap/Subsystems/AutomapSystem.cs index ba58ae3..53a785f 100644 --- a/Automap/Subsystems/AutomapSystem.cs +++ b/Automap/Subsystems/AutomapSystem.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; +using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Text; using System.Text.RegularExpressions; using System.Threading; @@ -38,6 +40,7 @@ namespace Automap private ColumnsMetadata chunkTopMetadata; private PointsOfInterest POIs = new PointsOfInterest(); private EntitiesOfInterest EOIs = new EntitiesOfInterest(); + private string jsonPreBuilt; internal Dictionary BlockID_Designators { get; private set; } internal Dictionary Entity_Designators { get; private set; } @@ -56,7 +59,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) { @@ -74,7 +77,7 @@ namespace Automap //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."); @@ -97,6 +100,8 @@ namespace Automap outputText.Write(staticMap.ToText()); outputText.Flush(); + 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); @@ -132,11 +137,11 @@ namespace Automap Logger.VerboseDebug("Cartographer re-trigger from [{0}]", cartographer_thread.ThreadState); #endif - if (cartographer_thread.ThreadState.HasFlag(ThreadState.Unstarted)) + if (cartographer_thread.ThreadState.HasFlag(System.Threading.ThreadState.Unstarted)) { cartographer_thread.Start(); } - else if (cartographer_thread.ThreadState.HasFlag(ThreadState.WaitSleepJoin)) + else if (cartographer_thread.ThreadState.HasFlag(System.Threading.ThreadState.WaitSleepJoin)) { //Time to (re)write chunk shards cartographer_thread.Interrupt(); @@ -168,7 +173,7 @@ namespace Automap if (!columnCounter.IsEmpty) { var tempSet = columnCounter.ToArray().OrderByDescending(kvp => kvp.Value); - UpdateEntityMetadata( ); + UpdateEntityMetadata(); foreach (var mostActiveCol in tempSet) { @@ -200,9 +205,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); @@ -271,7 +276,7 @@ namespace Automap } private void Reload_POI_Designators() - { + { Logger.VerboseDebug("Connecting {0} Configured Block-Designators", configuration.BlockDesignators.Count); foreach (var designator in configuration.BlockDesignators) { @@ -305,7 +310,6 @@ namespace Automap } - //TODO: Rewrite as Newtonsoft JsonTextWriter !!! /// /// Generates the JSON Metadata. (in Map object format ) /// @@ -315,207 +319,84 @@ namespace Automap 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) + using (stream) { - 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"); + Stopwatch stopWatch = new Stopwatch(); + stopWatch.Start(); - jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize="); - jsonWriter.WriteValue(chunkSize); - jsonWriter.WriteRaw(";\n"); + stream.Write(jsonPreBuilt); - jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk="); - jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk); - jsonWriter.WriteRaw(";\n"); + stream.Write("ViewFrame.chunks.genTime='{0}';", + DateTimeOffset.UtcNow + ); - jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk="); - jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk); - jsonWriter.WriteRaw(";\n"); + stream.Write("ViewFrame.chunks.startCoords=[{0},{1}];", + startChunkColumn.X, startChunkColumn.Y + ); - 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"); + 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" - jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata="); - jsonWriter.WriteStartConstructor("Map"); - jsonWriter.WriteStartArray( );//An array of... 2-component arrays - + stream.Write("ViewFrame.chunks.chunkMetadata=new Map(["); 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 + shard.Write(stream, ClientAPI); + stream.Write(","); } + stream.Write("]);");// Close constructor of Map (chunkMetadata) - 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 + stream.Write("ViewFrame.chunks.pointsOfInterest=new Map(["); foreach (var poi in POIs) { - jsonWriter.WriteStartArray( ); - jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}"); - - jsonWriter.WriteStartObject(); - 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( ); + poi.Write(stream, ClientAPI); + stream.Write(","); } - jsonWriter.Write("]);"); - jsonWriter.Write("ViewFrame.chunks.entitiesOfInterest=new Map(["); + stream.Write("]);"); + + stream.Write("ViewFrame.chunks.entitiesOfInterest=new Map(["); foreach (var eoi in EOIs) { - jsonWriter.WriteStartArray( ); - jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}"); + eoi.Write(stream, ClientAPI); + stream.Write(","); + } + stream.Write("]);\n"); - jsonWriter.WriteStartObject( ); - jsonWriter.WritePropertyName("prettyCoord"); - jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI)); + //stream.Write("//============= BlockID's for Rockmap / Rock-ratios ==============="); - jsonWriter.WritePropertyName("notes"); - jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities + //stream.Write("ViewFrame.chunks.rockLookup=new Map(["); - jsonWriter.WritePropertyName("time"); - jsonWriter.WriteValue(poi.Timestamp); + //foreach (var entry in RockIdCodes) + //{ + // var block = ClientAPI.World.GetBlock(entry.Key); - jsonWriter.WritePropertyName("chunkPos"); - jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}"); + // stream.Write("["); + // stream.Write("'{0},", block.Code.Path); - jsonWriter.WriteEndObject( ); - jsonWriter.WriteEndArray( ); - } + // stream.Write("["); + // stream.Write("'{0}',", entry.Value); - 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"); + // stream.Write("{0},", Lang.GetUnformatted(block.Code.Path)); + // //Color? - jsonWriter.Flush(); - } + // stream.Write("]],"); + //} + + //stream.Write("]);\n"); + + stream.Flush(); + + stopWatch.Stop(); + Logger.Debug("Run time of chunk write {0}", stopWatch.Elapsed); } } @@ -695,13 +576,6 @@ 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; @@ -721,9 +595,9 @@ 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) @@ -798,6 +672,65 @@ namespace Automap } + 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(); + // 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(); + + 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(); + + 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 } -- 2.11.0