• R/O
  • HTTP
  • SSH
  • HTTPS

提交

標籤
無標籤

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Automap (client) [VS plugin mod]


Commit MetaInfo

修訂cdc29d29d788f9126faee33e48c4f65968b49702 (tree)
時間2020-03-29 03:44:50
作者The Grand Dog <alex.h@me.c...>
CommiterThe Grand Dog

Log Message

fully implement the most advanced version of the map so far

there are SO many changes

Change Summary

差異

--- a/Automap/Automap.csproj
+++ b/Automap/Automap.csproj
@@ -95,6 +95,7 @@
9595 <Compile Include="Data\CommandData.cs" />
9696 <Compile Include="Data\CommandType.cs" />
9797 <Compile Include="Data\PersistedConfiguration.cs" />
98+ <Compile Include="Data\DisplayNameAttribute.cs" />
9899 </ItemGroup>
99100 <ItemGroup>
100101 <Folder Include="VS_libs\" />
--- a/Automap/Data/ColumnMeta.cs
+++ b/Automap/Data/ColumnMeta.cs
@@ -1,6 +1,5 @@
11 using System;
22 using System.Collections.Generic;
3-using System.Collections.ObjectModel;
43 using System.Collections.Specialized;
54
65
@@ -8,7 +7,10 @@ using Vintagestory.API.MathTools;
87 using Vintagestory.API.Common;
98
109 using ProtoBuf;
11-
10+using System.IO;
11+using System.Collections.ObjectModel;
12+using System.Text;
13+using Vintagestory.API.Client;
1214
1315 namespace Automap
1416 {
@@ -16,36 +18,47 @@ namespace Automap
1618 public struct ColumnMeta
1719 {
1820 [ProtoMember(1)]
21+ [DisplayName(0, "Coords.")]
1922 public Vec2i Location;
2023
2124 [ProtoMember(2)]
25+ [DisplayName(1, "Age")]
2226 public TimeSpan ChunkAge;//OLDEST CHUNK. from chunk last edit
2327
2428 [ProtoMember(3)]
29+ [DisplayName(2, "Temp.")]
2530 public float Temperature;// Temperature - surface
2631
2732 [ProtoMember(4)]
33+ [DisplayName(3, "Y Max.")]
2834 public ushort YMax;// Y feature height
2935
3036 [ProtoMember(5)]
37+ //[DisplayName(10, "Rocks")]
3138 public Dictionary<int, uint> RockRatio;//[Column] Geographic region (rock) Ratio. [BlockID * count]
3239
3340 [ProtoMember(6)]
41+ [DisplayName(4, "Fert.")]
3442 public float Fertility;
3543
3644 [ProtoMember(7)]
45+ [DisplayName(5, "Forest")]
3746 public float ForestDensity;
3847
3948 [ProtoMember(8)]
49+ [DisplayName(6, "Rain")]
4050 public float Rainfall;
4151
4252 [ProtoMember(9)]
53+ [DisplayName(7, "Shrub")]
4354 public float ShrubDensity;
4455
4556 [ProtoMember(10)]
57+ [DisplayName(8, "Air blocks")]
4658 public uint AirBlocks;
4759
4860 [ProtoMember(11)]
61+ [DisplayName(9, "Non-air")]
4962 public uint NonAirBlocks;
5063
5164 [ProtoMember(12)]
@@ -56,7 +69,7 @@ namespace Automap
5669 public ushort[,] HeightMap;//Needs to be 'flattened' for Protocol-Buffer serialization
5770
5871 [ProtoMember(13)]
59- private ushort[ ] _flattened_HeightMap;
72+ private ushort[] _flattened_HeightMap;
6073
6174
6275 public ColumnMeta(Vec2i loc, byte chunkSize = 32)
@@ -89,48 +102,70 @@ namespace Automap
89102 this.YMax = mapChunk.YMax;
90103 }
91104
92-
105+ public void Write(StreamWriter stream, ICoreClientAPI ClientApi)
106+ {
107+ // this is gross i hate this
108+ stream.Write("['{0}_{1}',[",
109+ Location.X,
110+ Location.Y
111+ );
112+ stream.Write("'{0}',", Location.PrettyCoords(ClientApi));
113+ stream.Write("'{0}',", ChunkAge);
114+ stream.Write("'{0}',", Temperature.ToString("F3"));
115+ stream.Write("'{0}',", YMax);
116+ stream.Write("'{0}',", Fertility.ToString("F3"));
117+ stream.Write("'{0}',", ForestDensity.ToString("F3"));
118+ stream.Write("'{0}',", Rainfall.ToString("F3"));
119+ stream.Write("'{0}',", ShrubDensity.ToString("F3"));
120+ stream.Write("'{0}',", AirBlocks);
121+ stream.Write("'{0}',", NonAirBlocks);
122+ stream.Write("]]");
123+ }
93124
94125 [ProtoBeforeSerialization]
95- private void PrepareData( )
126+ private void PrepareData()
96127 {
97128
98- if (HeightMap != null) {
99- _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
100- int flatIndex = 0;
129+ if (HeightMap != null)
130+ {
131+ _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
132+ int flatIndex = 0;
133+
134+ for (byte col = 0; col < ChunkSize; col++)
135+ {
136+ for (byte row = 0; row < ChunkSize; row++)
137+ {
138+ _flattened_HeightMap[flatIndex] = HeightMap[col, row];
139+ flatIndex++;
140+ }
141+ }
101142
102- for (byte col = 0; col < ChunkSize; col++) {
103- for (byte row = 0; row < ChunkSize; row++) {
104- _flattened_HeightMap[flatIndex] = HeightMap[col, row];
105- flatIndex++;
106143 }
107- }
108-
109- }
110144
111145 }
112146
113147
114148 [ProtoAfterDeserialization]
115- private void PostProcess( )
149+ private void PostProcess()
116150 {
117- if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize];
118-
119- if (_flattened_HeightMap != null) {
120- int col, row;
151+ if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize];
121152
122- BitVector32 bitMasker = new BitVector32(0);
123- var rowSection = BitVector32.CreateSection(( short )(ChunkSize - 1));
124- var colSection = BitVector32.CreateSection(( short )(ChunkSize - 1), rowSection);
125-
126- for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++) {
127- bitMasker = new BitVector32(data: ( int )rowcol);
128- row = bitMasker[rowSection];
129- col = bitMasker[colSection];
130- HeightMap[col, row] = _flattened_HeightMap[rowcol];
131- }
153+ if (_flattened_HeightMap != null)
154+ {
155+ int col, row;
156+ _ = new BitVector32(0);
157+ var rowSection = BitVector32.CreateSection((short) (ChunkSize - 1));
158+ var colSection = BitVector32.CreateSection((short) (ChunkSize - 1), rowSection);
159+
160+ for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++)
161+ {
162+ BitVector32 bitMasker = new BitVector32(data: (int) rowcol);
163+ row = bitMasker[rowSection];
164+ col = bitMasker[colSection];
165+ HeightMap[col, row] = _flattened_HeightMap[rowcol];
166+ }
132167
133- }
168+ }
134169
135170 }
136171
@@ -217,5 +252,4 @@ namespace Automap
217252 }
218253
219254 }
220-}
221-
255+}
\ No newline at end of file
--- /dev/null
+++ b/Automap/Data/DisplayNameAttribute.cs
@@ -0,0 +1,17 @@
1+using System;
2+using System.Reflection;
3+
4+namespace Automap
5+{
6+ [AttributeUsage(AttributeTargets.Field)]
7+ public class DisplayNameAttribute : Attribute
8+ {
9+ public string name;
10+ public byte order;
11+ public DisplayNameAttribute(byte order, string name)
12+ {
13+ this.order = order;
14+ this.name = name;
15+ }
16+ }
17+}
\ No newline at end of file
--- a/Automap/Data/EntitiesOfInterest.cs
+++ b/Automap/Data/EntitiesOfInterest.cs
@@ -1,11 +1,11 @@
11 using System;
22 using System.Collections.Generic;
33 using System.Collections.ObjectModel;
4-
4+using System.IO;
55 using System.Linq;
6-
76 using Vintagestory.API.Common.Entities;
87 using Vintagestory.API.MathTools;
8+using Vintagestory.API.Client;
99
1010 namespace Automap
1111 {
@@ -14,10 +14,27 @@ namespace Automap
1414 /// </summary>
1515 public struct EntityOfInterest
1616 {
17+ [DisplayName(1, "Notes")]
1718 public string Notes;
19+ [DisplayName(0, "Loc.")]
1820 public BlockPos Location;
21+ [DisplayName(2, "Time")]
1922 public DateTimeOffset Timestamp;
23+ [DisplayName(3, "ID")]
2024 public long EntityId;
25+ public void Write(StreamWriter stream, ICoreClientAPI ClientApi)
26+ {
27+ // this is gross i hate this
28+ stream.Write("['{0}_{1}',[",
29+ Location.X,
30+ Location.Y
31+ );
32+ stream.Write("'{0}',", Location.PrettyCoords(ClientApi));
33+ stream.Write("'{0}',", System.Web.HttpUtility.HtmlEncode(Notes));
34+ stream.Write("'{0}',", Timestamp);
35+ stream.Write("'{0}',", EntityId);
36+ stream.Write("]]");
37+ }
2138 }
2239
2340 /// <summary>
--- a/Automap/Data/PointOfInterest.cs
+++ b/Automap/Data/PointOfInterest.cs
@@ -1,6 +1,7 @@
11 using System;
22 using System.Collections.ObjectModel;
3-
3+using System.IO;
4+using Vintagestory.API.Client;
45 using Vintagestory.API.Common;
56 using Vintagestory.API.MathTools;
67
@@ -11,9 +12,24 @@ namespace Automap
1112 /// </summary>
1213 public struct PointOfInterest
1314 {
15+ [DisplayName(1, "Notes")]
1416 public string Notes;
17+ [DisplayName(0, "Loc.")]
1518 public BlockPos Location;
19+ [DisplayName(2, "Time")]
1620 public DateTimeOffset Timestamp;
21+ public void Write(StreamWriter stream, ICoreClientAPI ClientApi)
22+ {
23+ // this is gross i hate this
24+ stream.Write("['{0}_{1}',[",
25+ Location.X,
26+ Location.Y
27+ );
28+ stream.Write("'{0}',", Location.PrettyCoords(ClientApi));
29+ stream.Write("'{0}',", System.Web.HttpUtility.HtmlEncode(Notes).Replace("\n", "&#13;&#10;").Replace("\\","\\\\"));
30+ stream.Write("'{0}',", Timestamp);
31+ stream.Write("]]");
32+ }
1733 }
1834
1935 public class PointsOfInterest : KeyedCollection<BlockPos, PointOfInterest>
--- /dev/null
+++ b/Automap/MapSRC/build.js
@@ -0,0 +1,22 @@
1+#!/usr/local/bin/node
2+
3+// im sorry
4+// cd into MapSRC and run node ./build.js and this will concat and stuff
5+const fs = require('fs');
6+
7+fs.readFile('./src/Automap.html', 'utf8', (err, d) => {
8+ if (err) console.log(err);
9+ let outD = d.replace(/<link rel=\"stylesheet\" href=\"(.*)\">/g, '<style>REP:$1</style>')
10+ .replace(/(<script type=\"text\/javascript\") src=\"(.*)\">/g, '$1>REP:$2')
11+ .replace(/REP:(\w*\.\w*)/g, (match, name, offset, string) => {
12+ return fs.readFileSync('./src/' + name, 'utf8')
13+ .replace(/\/\/.*\n?/g, '');
14+ })
15+ .replace(/[\t\n]/g, '');
16+ fs.writeFile('./dist/automap.html', outD, err => {
17+ if (err) console.log(err);
18+ });
19+ fs.writeFile('../assets/automap/config/automap.html', outD, err => {
20+ if (err) console.log(err);
21+ });
22+});
\ No newline at end of file
--- /dev/null
+++ b/Automap/MapSRC/src/Automap.css
@@ -0,0 +1,38 @@
1+html, body, .map {
2+ width: 100%;
3+ height: 100%;
4+ margin: 0;
5+ overflow: hidden;
6+ outline: 1px dotted black;
7+}
8+
9+.infobox {
10+ width: 15em;
11+ /* height: 15em; */
12+ background-color: rgba(200, 200, 200, 0.5);
13+ left: 0;
14+ top: 0;
15+ font-family: sans-serif;
16+ position: absolute;
17+ z-index: 1;
18+}
19+
20+h1 {
21+ font-size: 22px;
22+ margin: .6em 1em;
23+ text-align: center;
24+}
25+
26+.infoboxTable {
27+ margin: .3em auto;
28+ width: 90%;
29+ outline: 1px solid #333;
30+}
31+
32+.infoboxTable th {
33+ width: 30%;
34+}
35+
36+.infoboxTable td {
37+ text-align: right;
38+}
\ No newline at end of file
--- /dev/null
+++ b/Automap/MapSRC/src/Automap.html
@@ -0,0 +1,22 @@
1+<!DOCTYPE html>
2+<html lang="en" dir="ltr">
3+
4+<head>
5+ <meta charset="utf-8">
6+ <title>Automap</title>
7+ <link rel="stylesheet" href="Automap.css">
8+</head>
9+
10+<body>
11+ <script type="text/javascript" src="ViewFrame.js"></script>
12+ <script type="text/javascript" src="ViewFrameUtils.js"></script>
13+ <div class="infobox">
14+ <h1>Chunk Info</h1>
15+ <table class="infoboxTable">
16+ </table>
17+ </div>
18+ <script type="text/javascript" src="index.js"></script>
19+
20+</body>
21+
22+</html>
\ No newline at end of file
--- /dev/null
+++ b/Automap/MapSRC/src/ViewFrame.js
@@ -0,0 +1,140 @@
1+function ViewFrame() {
2+ // dom stuff
3+ const map = document.createElement('canvas'); // the map we see
4+ map.className = 'map';
5+ map.height = window.innerHeight;
6+ map.width = window.innerWidth;
7+ document.getElementsByTagName('body')[0].append(map);
8+ // this is the map that we actually draw on
9+ this.map = map.getContext('2d', {
10+ alpha: false
11+ });
12+ this.map.imageSmoothingEnabled = false;
13+
14+ // the info box in the corner
15+ this.infobox = document.getElementsByClassName('infoboxTable')[0];
16+ this.infoboxSlots = new Array();
17+
18+ // load the metadata!
19+ this.chunkScript = document.createElement('script');
20+ this.chunkScript.type = 'text/javascript';
21+ this.chunkScript.src = 'Metadata.js';
22+ document.getElementsByTagName('body')[0].append(this.chunkScript);
23+ this.chunkScript.addEventListener('load', () => {
24+ ViewFrame.initInfobox(this.infobox, this.infoboxSlots);
25+ this.x = ViewFrame.chunks.startCoords[0];
26+ this.y = ViewFrame.chunks.startCoords[1];
27+ this.availableChunks = ViewFrame.chunks.chunkMetadata;
28+ this.render();
29+ }, {
30+ once: true
31+ });
32+
33+ // Tracks images that have been loaded and are on the map
34+ this.loadedChunksByName = new Map();
35+ // this is needed because [1, 2] != [1, 2] and thats how we store coords.
36+ this.loadedChunksByCoords = new Map();
37+ this.availableChunks = null; // the chunks in ./Metadata.js
38+ // so that we dont render twice at the same time
39+ this.rendering = false;
40+
41+ this.x = -1;
42+ this.y = -1; // can be fractional
43+ this.zoom = 32; // pixels wide the images are to be
44+ this.updateEdges();
45+}
46+// prototypes, some less... notable? methods are
47+// in ViewFrameUtils.js
48+ViewFrame.prototype.reloadChunkList = function () {
49+ if (this.chunkScript) {
50+ this.chunkScript.remove();
51+ delete this.chunkScript;
52+ }
53+
54+ this.chunkScript = document.createElement('script');
55+ this.chunkScript.type = 'text/javascript';
56+ this.chunkScript.src = 'Metadata.js';
57+ document.getElementsByTagName('body')[0].append(this.chunkScript);
58+
59+ this.chunkScript.addEventListener('load', () => {
60+ this.availableChunks = ViewFrame.chunks.chunkMetadata;
61+ this.render();
62+ });
63+};
64+
65+ViewFrame.prototype.render = function () {
66+ if (!this.availableChunks) return;
67+ if (this.rendering) clearInterval(ViewFrame.intervalRef);
68+ this.rendering = true;
69+ this.updateEdges();
70+ this.map.clearRect(0, 0, window.innerWidth, window.innerHeight);
71+ // culling
72+ this.loadedChunksByCoords
73+ .forEach((chunk, coord) => { // check the bounds
74+ if (coord[0] < this.eastChunk &&
75+ coord[0] >= this.westChunk &&
76+ coord[1] <= this.northChunk &&
77+ coord[1] >= this.southChunk) {
78+
79+ this.place(chunk, coord[0], coord[1]);
80+ return;
81+ }
82+ // its out of range!!!
83+ // get 'em boys!!!!!
84+ this.loadedChunksByCoords.delete(coord);
85+ this.loadedChunksByName.delete(coord.join('_'));
86+ chunk.remove();
87+ });
88+
89+ // gathering what we need to load
90+ const neededChunks = new Set();
91+ for (var x = this.westChunk; x < this.eastChunk; x++) {
92+ for (var y = this.southChunk; y < this.northChunk; y++) {
93+ const chunKey = [x, y]; // chunk + key = chunKey :)
94+ const name = chunKey.join('_');
95+ // continue if its not available, or it is loaded
96+ if (!this.availableChunks.has(name) ||
97+ this.loadedChunksByName.has(name)) continue;
98+ neededChunks.add(chunKey);
99+ }
100+ }
101+ // iterating over everything we need to load
102+ const it = neededChunks.values();
103+ ViewFrame.intervalRef = setInterval(() => {
104+ let round = it.next();
105+ if (!round.done) {
106+ // load
107+ const img = new Image(32, 32);
108+ const name = round.value.join('_');
109+
110+ img.src = name + '.png';
111+
112+ decode(img, loadedImage => {
113+ this.place(img, round.value[0], round.value[1]);
114+ });
115+ this.loadedChunksByName.set(name, img);
116+ this.loadedChunksByCoords.set(round.value, img);
117+ } else {
118+ clearInterval(ViewFrame.intervalRef);
119+ this.rendering = false;
120+ }
121+ }, 4);
122+};
123+
124+ViewFrame.prototype.place = function (img, x, y) {
125+ x -= this.x;
126+ y -= this.y;
127+ x *= this.zoom;
128+ y *= this.zoom;
129+ x += this.width / 2;
130+ y += this.height / 2;
131+
132+ this.map.drawImage(img, Math.floor(x), Math.floor(y), this.zoom, this.zoom);
133+};
134+
135+ViewFrame.prototype.updateInfobox = function (chunkName) {
136+ const chunkMeta = this.availableChunks.get(chunkName);
137+ this.infoboxSlots.forEach((l, k) => {
138+ l.innerText = chunkMeta ? chunkMeta[k] : '0';
139+ });
140+};
\ No newline at end of file
--- /dev/null
+++ b/Automap/MapSRC/src/ViewFrameUtils.js
@@ -0,0 +1,62 @@
1+ViewFrame.initInfobox = function (ibox, iboxSlots) {
2+
3+ ViewFrame.chunks
4+ .chunkMetadataNames.forEach((item, i) => {
5+ const slot = document.createElement('tr');
6+ const head = document.createElement('th');
7+ head.innerText = item;
8+ const row = document.createElement('td');
9+ row.innerText = '0';
10+ iboxSlots[i] = row;
11+ slot.append(head, row);
12+ ibox.append(slot);
13+ });
14+};
15+
16+ViewFrame.prototype.updateEdges = function () {
17+ if (this.width != window.innerWidth || this.height != window.innerHeight) {
18+ this.width = window.innerWidth;
19+ this.map.canvas.width = this.width;
20+ this.height = window.innerHeight;
21+ this.map.canvas.height = this.height;
22+ this.map.imageSmoothingEnabled = false;
23+ }
24+ const chunksWide = Math.ceil(this.width / this.zoom);
25+ const chunksHigh = Math.ceil(this.height / this.zoom);
26+
27+ this.east = this.x + chunksWide / 2; // this is fractional and is used to keep track of the edges of the window
28+ this.eastChunk = Math.ceil(this.east); // this is not and is used to track the chunks that need to load
29+ this.west = this.x - chunksWide / 2;
30+ this.westChunk = Math.floor(this.west);
31+ this.north = this.y + chunksHigh / 2;
32+ this.northChunk = Math.ceil(this.north);
33+ this.south = this.y - chunksHigh / 2;
34+ this.southChunk = Math.floor(this.south);
35+};
36+
37+ViewFrame.prototype.moveCenter = function (dx, dy) {
38+ // to pan when we click on the map!
39+ this.x += (dx - this.width / 2) / this.zoom;
40+ this.y += (dy - this.height / 2) / this.zoom;
41+};
42+ViewFrame.prototype.setCenter = function (x, y) {
43+ this.x = x;
44+ this.y = y;
45+};
46+
47+ViewFrame.prototype.clear = function () {
48+ this.loadedChunksByName.clear();
49+ this.loadedChunksByCoords.clear();
50+ if (this.chunkScript) this.chunkScript.remove();
51+ delete this.chunkScript;
52+ delete ViewFrame.chunks;
53+ this.map.clearRect(0, 0, window.innerWidth, window.innerHeight);
54+};
55+
56+function decode(img, cb) {
57+ img.decode()
58+ .then(() => {
59+ cb(img);
60+ })
61+ .catch(() => {}); // so images arent added on error
62+}
\ No newline at end of file
--- /dev/null
+++ b/Automap/MapSRC/src/index.js
@@ -0,0 +1,93 @@
1+const vf = new ViewFrame();
2+vf.reloadChunkList();
3+
4+// the event handlers are in iifes so they dont make unneeded globals.
5+// resize, delay re-render to reduce lag.
6+(function () {
7+ var id;
8+ window.addEventListener('resize', () => {
9+ clearTimeout(id);
10+ id = setTimeout(() => {
11+ vf.render();
12+ }, 500);
13+ });
14+}());
15+
16+// panning
17+(function () {
18+ var id;
19+ vf.map.canvas.addEventListener('mousedown', event => {
20+ clearTimeout(id);
21+ vf.moveCenter(event.pageX, event.pageY);
22+ id = setTimeout(() => {
23+ vf.render();
24+ }, 250);
25+ });
26+}());
27+
28+
29+// #### CONTROLS ####
30+// hovering
31+(function () {
32+ var lastX = 0;
33+ var lastY = 0;
34+ vf.map.canvas.addEventListener('mousemove', event => {
35+ // only count if the mouse moved more than a chunk
36+ let x = Math.floor(vf.x +
37+ (event.clientX - vf.width / 2) / vf.zoom);
38+ let y = Math.floor(vf.y +
39+ (event.clientY - vf.height / 2) / vf.zoom);
40+ if (x == lastX && y == lastY) return;
41+ lastX = x;
42+ lastY = y;
43+ vf.updateInfobox(x + '_' + y);
44+ });
45+}());
46+
47+// scroll/zoom
48+(function () {
49+ var id;
50+ vf.map.canvas.addEventListener('wheel', event => {
51+ clearTimeout(id);
52+ vf.zoom += -Math.sign(event.deltaY);
53+ id = setTimeout(() => {
54+ vf.render();
55+ }, 250);
56+ });
57+}());
58+
59+// reload the chunk list every six seconds
60+(function () {
61+ setInterval(() => {
62+ vf.reloadChunkList();
63+ }, 6000);
64+}());
65+//
66+// var i = 500;
67+// setTimeout(() => {
68+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
69+// clientX: 879,
70+// clientY: 926
71+// }));
72+// }, i += 1000);
73+//
74+// setTimeout(() => {
75+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
76+// clientX: 666,
77+// clientY: 924
78+// }));
79+// }, i += 2000);
80+//
81+// setTimeout(() => {
82+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
83+// clientX: 1090,
84+// clientY: 936
85+// }));
86+// }, i += 2000);
87+//
88+// setTimeout(() => {
89+// vf.map.dispatchEvent(new MouseEvent('mousedown', {
90+// clientX: 29,
91+// clientY: 785
92+// }));
93+// }, i += 2000);
\ No newline at end of file
--- a/Automap/Subsystems/AutomapSystem.cs
+++ b/Automap/Subsystems/AutomapSystem.cs
@@ -1,8 +1,10 @@
11 using System;
22 using System.Collections.Concurrent;
33 using System.Collections.Generic;
4+using System.Diagnostics;
45 using System.IO;
56 using System.Linq;
7+using System.Reflection;
68 using System.Text;
79 using System.Text.RegularExpressions;
810 using System.Threading;
@@ -38,6 +40,7 @@ namespace Automap
3840 private ColumnsMetadata chunkTopMetadata;
3941 private PointsOfInterest POIs = new PointsOfInterest();
4042 private EntitiesOfInterest EOIs = new EntitiesOfInterest();
43+ private string jsonPreBuilt;
4144
4245 internal Dictionary<int, BlockDesignator> BlockID_Designators { get; private set; }
4346 internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; }
@@ -56,7 +59,7 @@ namespace Automap
5659
5760 public static string AutomapStatusEventKey = @"AutomapStatus";
5861 public static string AutomapCommandEventKey = @"AutomapCommand";
59- PersistedConfiguration cachedConfiguration;
62+ //PersistedConfiguration cachedConfiguration;
6063
6164 public AutomapSystem(ICoreClientAPI clientAPI, ILogger logger, PersistedConfiguration config)
6265 {
@@ -74,7 +77,7 @@ namespace Automap
7477 //Listen on bus for commands
7578 ClientAPI.Event.RegisterEventBusListener(CommandListener, 1.0, AutomapSystem.AutomapCommandEventKey);
7679
77- if (configuration.Autostart)
80+ if (configuration.Autostart)
7881 {
7982 CurrentState = CommandType.Run;
8083 Logger.Debug("Autostart is Enabled.");
@@ -97,6 +100,8 @@ namespace Automap
97100 outputText.Write(staticMap.ToText());
98101 outputText.Flush();
99102
103+ MakePreBuiltJSON();
104+
100105 Prefill_POI_Designators();
101106 startChunkColumn = new Vec2i((ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.X / chunkSize), (ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Z / chunkSize));
102107 chunkTopMetadata = new ColumnsMetadata(startChunkColumn);
@@ -132,11 +137,11 @@ namespace Automap
132137 Logger.VerboseDebug("Cartographer re-trigger from [{0}]", cartographer_thread.ThreadState);
133138 #endif
134139
135- if (cartographer_thread.ThreadState.HasFlag(ThreadState.Unstarted))
140+ if (cartographer_thread.ThreadState.HasFlag(System.Threading.ThreadState.Unstarted))
136141 {
137142 cartographer_thread.Start();
138143 }
139- else if (cartographer_thread.ThreadState.HasFlag(ThreadState.WaitSleepJoin))
144+ else if (cartographer_thread.ThreadState.HasFlag(System.Threading.ThreadState.WaitSleepJoin))
140145 {
141146 //Time to (re)write chunk shards
142147 cartographer_thread.Interrupt();
@@ -168,7 +173,7 @@ namespace Automap
168173 if (!columnCounter.IsEmpty)
169174 {
170175 var tempSet = columnCounter.ToArray().OrderByDescending(kvp => kvp.Value);
171- UpdateEntityMetadata( );
176+ UpdateEntityMetadata();
172177
173178 foreach (var mostActiveCol in tempSet)
174179 {
@@ -200,9 +205,9 @@ namespace Automap
200205 if (updatedPixels > 0)
201206 {
202207
203- #if DEBUG
208+#if DEBUG
204209 Logger.VerboseDebug("Wrote chunk shard: ({0}) - Edits#:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, updatedPixels);
205- #endif
210+#endif
206211 updatedChunks++;
207212 chunkTopMetadata.Update(chunkMeta);
208213 columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
@@ -271,7 +276,7 @@ namespace Automap
271276 }
272277
273278 private void Reload_POI_Designators()
274- {
279+ {
275280 Logger.VerboseDebug("Connecting {0} Configured Block-Designators", configuration.BlockDesignators.Count);
276281 foreach (var designator in configuration.BlockDesignators)
277282 {
@@ -305,7 +310,6 @@ namespace Automap
305310
306311 }
307312
308- //TODO: Rewrite as Newtonsoft JsonTextWriter !!!
309313 /// <summary>
310314 /// Generates the JSON Metadata. (in Map object format )
311315 /// </summary>
@@ -315,207 +319,84 @@ namespace Automap
315319
316320 StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
317321
318- using (stream) {
319- JsonTextWriter jsonWriter = new JsonTextWriter(stream);
320-
321- jsonWriter.Formatting = Formatting.None;
322- jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
323- jsonWriter.Indentation = 0;
324- //jsonWriter.AutoCompleteOnClose = true;
325- jsonWriter.QuoteChar = '\'';
326- jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
327- jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
328-
329- using (jsonWriter)
322+ using (stream)
330323 {
331- jsonWriter.WriteRaw("ViewFrame.chunks={};\n");
332- jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum=" );
333- jsonWriter.WriteValue(ClientAPI.World.Seed);
334- jsonWriter.WriteRaw(";\n");
335-
336- jsonWriter.WriteRaw("ViewFrame.chunks.genTime=");
337- jsonWriter.WriteValue(DateTimeOffset.UtcNow);
338- jsonWriter.WriteRaw(";\n");
339-
340- jsonWriter.WriteRaw("ViewFrame.chunks.startCoords=");
341- jsonWriter.WriteStartArray( );
342- jsonWriter.WriteValue(startChunkColumn.X);
343- jsonWriter.WriteValue(startChunkColumn.Y);
344- jsonWriter.WriteEndArray( );
345- jsonWriter.WriteRaw(";\n");
324+ Stopwatch stopWatch = new Stopwatch();
325+ stopWatch.Start();
346326
347- jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize=");
348- jsonWriter.WriteValue(chunkSize);
349- jsonWriter.WriteRaw(";\n");
327+ stream.Write(jsonPreBuilt);
350328
351- jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk=");
352- jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk);
353- jsonWriter.WriteRaw(";\n");
329+ stream.Write("ViewFrame.chunks.genTime='{0}';",
330+ DateTimeOffset.UtcNow
331+ );
354332
355- jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk=");
356- jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk);
357- jsonWriter.WriteRaw(";\n");
333+ stream.Write("ViewFrame.chunks.startCoords=[{0},{1}];",
334+ startChunkColumn.X, startChunkColumn.Y
335+ );
358336
359- jsonWriter.WriteRaw("ViewFrame.chunks.westMostChunk=");
360- jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk);
361- jsonWriter.WriteRaw(";\n");
362-
363- jsonWriter.WriteRaw("ViewFrame.chunks.eastMostChunk=");
364- jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk);
365- jsonWriter.WriteRaw(";\n");
337+ stream.Write("ViewFrame.chunks.bounds=[{0},{1},{2},{3}];",
338+ chunkTopMetadata.North_mostChunk,
339+ chunkTopMetadata.South_mostChunk,
340+ chunkTopMetadata.West_mostChunk,
341+ chunkTopMetadata.East_mostChunk
342+ );
366343
367344
368345 //MAP object format - [key, value]: key is "x_y"
369- jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata=");
370- jsonWriter.WriteStartConstructor("Map");
371- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
372-
346+ stream.Write("ViewFrame.chunks.chunkMetadata=new Map([");
373347
374348 foreach (var shard in chunkTopMetadata)
375349 {
376- jsonWriter.WriteStartArray( );//Start tuple
377- jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple
378-
379- jsonWriter.WriteStartObject( );
380- jsonWriter.WritePropertyName("prettyCoord");
381- jsonWriter.WriteValue( shard.Location.PrettyCoords(ClientAPI));
382-
383- jsonWriter.WritePropertyName("chunkAge");
384- jsonWriter.WriteValue(shard.ChunkAge);
385-
386- jsonWriter.WritePropertyName("temp");
387- jsonWriter.WriteValue(shard.Temperature);
388-
389- jsonWriter.WritePropertyName("YMax");
390- jsonWriter.WriteValue(shard.YMax);
391-
392- jsonWriter.WritePropertyName("fert");
393- jsonWriter.WriteValue(shard.Fertility);
394-
395- jsonWriter.WritePropertyName("forestDens");
396- jsonWriter.WriteValue( shard.ForestDensity);
397-
398- jsonWriter.WritePropertyName("rain");
399- jsonWriter.WriteValue( shard.Rainfall);
400-
401- jsonWriter.WritePropertyName("shrubDens");
402- jsonWriter.WriteValue( shard.ShrubDensity);
403-
404- jsonWriter.WritePropertyName("airBlocks");
405- jsonWriter.WriteValue( shard.AirBlocks);
406-
407- jsonWriter.WritePropertyName("nonAirBlocks");
408- jsonWriter.WriteValue( shard.NonAirBlocks);
409-
410- //TODO: Heightmap ?
411- //Start rockMap ; FOR a Ratio....on tooltip GUI
412- jsonWriter.WritePropertyName("rockRatio");
413- jsonWriter.WriteStartConstructor("Map");
414- jsonWriter.WriteStartArray( );
415- foreach (var rockEntry in shard.RockRatio) {
416- var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key);
417- jsonWriter.WriteStartArray( );
418- jsonWriter.WriteValue(rockBlock.Code.Path);
419- jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column
420- jsonWriter.WriteEndArray( );
421- }
422- jsonWriter.WriteEndArray( );
423- jsonWriter.WriteEndConstructor( );//end rock-map
424-
425- jsonWriter.WriteEndObject( );//end Map value: {Object}
426- jsonWriter.WriteEndArray( );//end Tuple
350+ shard.Write(stream, ClientAPI);
351+ stream.Write(",");
427352 }
353+ stream.Write("]);");// Close constructor of Map (chunkMetadata)
428354
429- jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata
430- jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata)
431- jsonWriter.WriteRaw(";\n");
432355
433- jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest=");
434- jsonWriter.WriteStartConstructor("Map");
435- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
356+ stream.Write("ViewFrame.chunks.pointsOfInterest=new Map([");
436357
437358 foreach (var poi in POIs)
438359 {
439- jsonWriter.WriteStartArray( );
440- jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
441-
442- jsonWriter.WriteStartObject();
443- jsonWriter.WritePropertyName("prettyCoord");
444- jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI) );
445-
446- jsonWriter.WritePropertyName("notes");
447- jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
448-
449- jsonWriter.WritePropertyName("time");
450- jsonWriter.WriteValue(poi.Timestamp);
451-
452- jsonWriter.WritePropertyName("chunkPos");
453- jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
454-
455- jsonWriter.WriteEndObject( );
456- jsonWriter.WriteEndArray( );
360+ poi.Write(stream, ClientAPI);
361+ stream.Write(",");
457362 }
458- jsonWriter.Write("]);");
459363
460- jsonWriter.Write("ViewFrame.chunks.entitiesOfInterest=new Map([");
364+ stream.Write("]);");
365+
366+ stream.Write("ViewFrame.chunks.entitiesOfInterest=new Map([");
461367 foreach (var eoi in EOIs)
462368 {
463- jsonWriter.WriteStartArray( );
464- jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
369+ eoi.Write(stream, ClientAPI);
370+ stream.Write(",");
371+ }
372+ stream.Write("]);\n");
465373
466- jsonWriter.WriteStartObject( );
467- jsonWriter.WritePropertyName("prettyCoord");
468- jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI));
374+ //stream.Write("//============= BlockID's for Rockmap / Rock-ratios ===============");
469375
470- jsonWriter.WritePropertyName("notes");
471- jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
376+ //stream.Write("ViewFrame.chunks.rockLookup=new Map([");
472377
473- jsonWriter.WritePropertyName("time");
474- jsonWriter.WriteValue(poi.Timestamp);
378+ //foreach (var entry in RockIdCodes)
379+ //{
380+ // var block = ClientAPI.World.GetBlock(entry.Key);
475381
476- jsonWriter.WritePropertyName("chunkPos");
477- jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
382+ // stream.Write("[");
383+ // stream.Write("'{0},", block.Code.Path);
478384
479- jsonWriter.WriteEndObject( );
480- jsonWriter.WriteEndArray( );
481- }
385+ // stream.Write("[");
386+ // stream.Write("'{0}',", entry.Value);
482387
483- jsonWriter.WriteEndArray( );
484- jsonWriter.WriteEndConstructor( );
485- jsonWriter.WriteRaw(";\n");
486-
487- jsonWriter.WriteWhitespace("\n");
488- jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
489- jsonWriter.WriteWhitespace("\n");
490-
491- jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup =");
492- jsonWriter.WriteStartConstructor("Map");
493- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
494-
495- foreach (var entry in RockIdCodes) {
496- var block = ClientAPI.World.GetBlock(entry.Key);
497-
498- jsonWriter.WriteStartArray( );
499- jsonWriter.WriteValue(block.Code.Path);
500-
501- jsonWriter.WriteStartObject( );
502- jsonWriter.WritePropertyName("assetCode");
503- jsonWriter.WriteValue(entry.Value);
504-
505- jsonWriter.WritePropertyName("name");
506- jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path));
507- //Color?
508-
509- jsonWriter.WriteEndObject( );
510- jsonWriter.WriteEndArray( );
511- }
512- jsonWriter.WriteEndArray( );
513- jsonWriter.WriteEndConstructor();
514-
515- jsonWriter.WriteRaw(";\n");
388+ // stream.Write("{0},", Lang.GetUnformatted(block.Code.Path));
389+ // //Color?
516390
517- jsonWriter.Flush();
518- }
391+ // stream.Write("]],");
392+ //}
393+
394+ //stream.Write("]);\n");
395+
396+ stream.Flush();
397+
398+ stopWatch.Stop();
399+ Logger.Debug("Run time of chunk write {0}", stopWatch.Elapsed);
519400 }
520401
521402 }
@@ -695,13 +576,6 @@ namespace Automap
695576 }
696577
697578 chunkMeta.NonAirBlocks++;
698-
699- ////Heightmap
700- //if (chunkMeta.HeightMap[X_index, Z_index] == 0)
701- //{
702- // chunkMeta.HeightMap[X_index, Z_index]
703- // = (ushort) (Y_index + (targetChunkY * chunkSize));
704- //}
705579 }
706580 while (X_index++ < (chunkSize - 1));
707581 X_index = 0;
@@ -721,9 +595,9 @@ namespace Automap
721595 foreach (var loadedEntity in ClientAPI.World.LoadedEntities.ToArray())
722596 {
723597
724- #if DEBUG
598+#if DEBUG
725599 //Logger.VerboseDebug($"ENTITY: ({loadedEntity.Value.Code}) = #{loadedEntity.Value.EntityId} {loadedEntity.Value.State} {loadedEntity.Value.LocalPos} <<<<<<<<<<<<");
726- #endif
600+#endif
727601
728602 var dMatch = Entity_Designators.SingleOrDefault(se => se.Key.Equals(loadedEntity.Value.Code));
729603 if (dMatch.Value != null)
@@ -798,6 +672,65 @@ namespace Automap
798672 }
799673
800674
675+ private void MakePreBuiltJSON()
676+ {
677+ var builder = new StringBuilder(512);
678+ builder.Append("ViewFrame.chunks={};\n");
679+ builder.AppendFormat("ViewFrame.chunks.worldSeedNum='{0}';",
680+ ClientAPI.World.Seed
681+ );
682+ builder.AppendFormat("ViewFrame.chunks.chunkSize={0};",
683+ chunkSize
684+ );
685+
686+ builder.Append("ViewFrame.chunks.chunkMetadataNames=[");
687+ var fields = typeof(ColumnMeta).GetFields();
688+ var attsToSort = new List<DisplayNameAttribute>();
689+ // this is so gross
690+ foreach (var f in fields)
691+ {
692+ var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
693+ if (att != null)
694+ {
695+ attsToSort.Add((DisplayNameAttribute) att);
696+ }
697+
698+ }
699+ foreach (var att in attsToSort.OrderBy(a => a.order))
700+ builder.AppendFormat("'{0}',", att.name);
701+ builder.Append("];\n");
702+
703+ builder.Append("ViewFrame.chunks.pointsOfInterestNames=[");
704+ fields = typeof(PointOfInterest).GetFields();
705+ attsToSort = new List<DisplayNameAttribute>();
706+
707+ foreach (var f in fields)
708+ {
709+ var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
710+ if (att != null)
711+ attsToSort.Add((DisplayNameAttribute) att);
712+ }
713+ foreach (var att in attsToSort.OrderBy(a => a.order))
714+ builder.AppendFormat("'{0}',", att.name);
715+ builder.Append("];\n");
716+
717+ builder.Append("ViewFrame.chunks.entityOfInterestNames=[");
718+ fields = typeof(EntityOfInterest).GetFields();
719+ attsToSort = new List<DisplayNameAttribute>();
720+
721+ foreach (var f in fields)
722+ {
723+ var att = f.GetCustomAttribute(typeof(DisplayNameAttribute));
724+ if (att != null)
725+ attsToSort.Add((DisplayNameAttribute) att);
726+ }
727+ foreach (var att in attsToSort.OrderBy(a => a.order))
728+ builder.AppendFormat("'{0}',", att.name);
729+ builder.Append("];\n");
730+
731+ jsonPreBuilt = builder.ToString();
732+ }
733+
801734 #endregion
802735
803736 }