• R/O
  • HTTP
  • SSH
  • HTTPS

Commit

Tags
No Tags

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

Revision71533a4171bb5d9bf719b239c3387c7f9c2800e0 (tree)
Time2020-04-27 23:25:07
AuthorThe Grand Dog <alex.h@me.c...>
CommiterThe Grand Dog

Log Message

COMPLETE rewrite of the JSON generator to use new lambda based syntax

Change Summary

Incremental Difference

--- a/Automap/Data/ColumnMeta.cs
+++ b/Automap/Data/ColumnMeta.cs
@@ -11,6 +11,7 @@ using System.IO;
1111 using System.Collections.ObjectModel;
1212 using System.Text;
1313 using Vintagestory.API.Client;
14+using Newtonsoft.Json.Linq;
1415
1516 namespace Automap
1617 {
@@ -18,13 +19,17 @@ namespace Automap
1819 public struct ColumnMeta
1920 {
2021 [ProtoMember(1)]
21- [DisplayName(0, "Coords.")]
2222 public Vec2i Location;
2323
24+ [DisplayName(0, "Coords.")]
25+ public string PrettyLocation;
26+
2427 [ProtoMember(2)]
25- [DisplayName(1, "Age")]
2628 public TimeSpan ChunkAge;//OLDEST CHUNK. from chunk last edit
2729
30+ [DisplayName(1, "Age")]
31+ public string ShortChunkAge { get => ChunkAge.ToString("c"); }
32+
2833 [ProtoMember(3)]
2934 [DisplayName(2, "Temp.")]
3035 public float Temperature;// Temperature - surface
@@ -34,24 +39,38 @@ namespace Automap
3439 public ushort YMax;// Y feature height
3540
3641 [ProtoMember(5)]
37- //[DisplayName(10, "Rocks")]
3842 public Dictionary<int, uint> RockRatio;//[Column] Geographic region (rock) Ratio. [BlockID * count]
3943
44+ //[DisplayName(10, "Rocks")]
45+ //public JArray FlatRocks
46+ //{
47+ // get {
48+ // string[] rocks = new string[this.RockRatio.Count];
49+ // int i = 0;
50+ // foreach (var roc in RockRatio)
51+ // {
52+ // rocks[i++] = $"\"{roc.Key}\":\"{roc.Value}\"";
53+ // }
54+ // return new JArray(rocks);
55+ // }
56+ //}
57+
58+
4059 [ProtoMember(6)]
4160 [DisplayName(4, "Fert.")]
4261 public float Fertility;
4362
4463 [ProtoMember(7)]
45- [DisplayName(5, "Forest")]
46- public float ForestDensity;
64+ //[DisplayName(5, "Forest")]
65+ public float ForestDensity; // not given to client
4766
4867 [ProtoMember(8)]
4968 [DisplayName(6, "Rain")]
5069 public float Rainfall;
5170
5271 [ProtoMember(9)]
53- [DisplayName(7, "Shrub")]
54- public float ShrubDensity;
72+ //[DisplayName(7, "Shrub")]
73+ public float ShrubDensity; // not given to client
5574
5675 [ProtoMember(10)]
5776 [DisplayName(8, "Air blocks")]
@@ -71,10 +90,10 @@ namespace Automap
7190 [ProtoMember(13)]
7291 private ushort[] _flattened_HeightMap;
7392
74-
75- public ColumnMeta(Vec2i loc, byte chunkSize = 32)
93+ public ColumnMeta(Vec2i loc, ICoreClientAPI clientAPI, byte chunkSize = 32)
7694 {
7795 Location = loc;
96+ PrettyLocation = loc.PrettyCoords(clientAPI);
7897 ChunkAge = TimeSpan.Zero;
7998 Temperature = 0f;
8099 YMax = 0;
@@ -150,6 +169,12 @@ namespace Automap
150169 }
151170
152171
172+ internal ColumnMeta Reload(ICoreClientAPI clientAPI)
173+ {
174+ this.PrettyLocation = Location.PrettyCoords(clientAPI);
175+ Console.Write(PrettyLocation == null ? "*" : ",");
176+ return this;
177+ }
153178 }
154179
155180 public class ColumnsMetadata : KeyedCollection<Vec2i, ColumnMeta>
--- a/Automap/Data/DisplayNameAttribute.cs
+++ b/Automap/Data/DisplayNameAttribute.cs
@@ -3,7 +3,7 @@ using System.Reflection;
33
44 namespace Automap
55 {
6- [AttributeUsage(AttributeTargets.Field)]
6+ [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
77 public class DisplayNameAttribute : Attribute
88 {
99 public string name;
--- a/Automap/Data/EntitiesOfInterest.cs
+++ b/Automap/Data/EntitiesOfInterest.cs
@@ -29,6 +29,8 @@ namespace Automap
2929 public string Notes;
3030
3131 [DisplayName(0, "Loc.")]
32+ public string PrettyLocation;
33+
3234 [ProtoMember(3)]
3335 public BlockPos Location;
3436
--- a/Automap/Data/PointOfInterest.cs
+++ b/Automap/Data/PointOfInterest.cs
@@ -26,6 +26,8 @@ namespace Automap
2626 public string Notes;
2727
2828 [DisplayName(0, "Loc.")]
29+ public string PrettyLocation;
30+
2931 [ProtoMember(3)]
3032 public BlockPos Location;
3133
--- a/Automap/Designators/DefaultDesignators.cs
+++ b/Automap/Designators/DefaultDesignators.cs
@@ -98,6 +98,7 @@ namespace Automap
9898 new PointOfInterest
9999 {
100100 Name = "Sign",
101+ PrettyLocation = posn.PrettyCoords(clientAPI),
101102 Location = posn.Copy(),
102103 Notes = signEntity.text,
103104 Timestamp = DateTime.UtcNow,
@@ -124,6 +125,7 @@ namespace Automap
124125 new PointOfInterest
125126 {
126127 Name = "Signpost",
128+ PrettyLocation = posn.PrettyCoords(clientAPI),
127129 Location = posn.Copy(),
128130 Notes = string.Join(",", signEntity.textByCardinalDirection),
129131 Timestamp = DateTime.UtcNow,
@@ -146,6 +148,7 @@ namespace Automap
146148 poi.AddReplace(new EntityOfInterest
147149 {
148150 Name = "Trader",
151+ PrettyLocation = posn.PrettyCoords(clientAPI),
149152 Location = posn.Copy(),
150153 Notes = message,
151154 Timestamp = DateTime.UtcNow,
@@ -174,6 +177,7 @@ namespace Automap
174177 new PointOfInterest
175178 {
176179 Name = "Translocator",
180+ PrettyLocation = posn.PrettyCoords(clientAPI),
177181 Location = posn.Copy(),
178182 Notes = textTarget.ToString(),
179183 Timestamp = DateTime.UtcNow,
--- a/Automap/MapSRC/build.js
+++ b/Automap/MapSRC/build.js
@@ -1,22 +1,23 @@
11 #!/usr/local/bin/node
22
33 // im sorry
4-// cd into MapSRC and run node ./build.js and this will concat and stuff
4+// run ./build.js and this will concat and stuff
55 const fs = require('fs');
66
7-fs.readFile('./src/Automap.html', 'utf8', (err, d) => {
7+fs.readFile(__dirname + '/src/Automap.html', 'utf8', (err, d) => {
88 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, '');
9+ let outD = d.replace(/<link rel=\"stylesheet\" href=\"(.*)\">/g, (match, name, offset, string) => {
10+ return '<style>' + fs.readFileSync(__dirname + '/src/' + name, 'utf8')
11+ .replace(/\/\/.*\n?/g, '')
12+ + '</style>';
13+ })
14+ .replace(/<script type=\"text\/javascript\" src=\"(.*)\">/g, (match, name, offset, string) => {
15+ return '<script type=\"text\/javascript\">' + fs.readFileSync(__dirname + '/src/' + name, 'utf8')
16+ .replace(/\/\/.*\n?/g, '')
17+ + '</script>';
1418 })
1519 .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+ fs.writeFile(__dirname + '/../assets/automap/config/automap.html', outD, err => {
2021 if (err) console.log(err);
2122 });
2223 });
\ No newline at end of file
--- a/Automap/MapSRC/src/index.js
+++ b/Automap/MapSRC/src/index.js
@@ -49,7 +49,7 @@ vf.reloadChunkList();
4949 var id;
5050 vf.map.canvas.addEventListener('wheel', event => {
5151 clearTimeout(id);
52- vf.zoom += -Math.sign(event.deltaY);
52+ vf.zoom += -Math.sign(event.deltaY)*2;
5353 id = setTimeout(() => {
5454 vf.render();
5555 }, 250);
@@ -57,37 +57,10 @@ vf.reloadChunkList();
5757 }());
5858
5959 // reload the chunk list every six seconds
60+var devBlockReload = false; // disable via command line
6061 (function () {
6162 setInterval(() => {
63+ if (devBlockReload) return;
6264 vf.reloadChunkList();
6365 }, 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
66+}());
\ No newline at end of file
--- a/Automap/Subsystems/AutomapSystem.cs
+++ b/Automap/Subsystems/AutomapSystem.cs
@@ -45,7 +45,6 @@ namespace Automap
4545 private ColumnsMetadata chunkTopMetadata;
4646 private PointsOfInterest POIs = new PointsOfInterest();
4747 private EntitiesOfInterest EOIs = new EntitiesOfInterest();
48- private string jsonPreBuilt;
4948
5049 internal Dictionary<int, BlockDesignator> BlockID_Designators { get; private set; }
5150 internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; }
@@ -64,7 +63,6 @@ namespace Automap
6463
6564 public static string AutomapStatusEventKey = @"AutomapStatus";
6665 public static string AutomapCommandEventKey = @"AutomapCommand";
67- PersistedConfiguration cachedConfiguration;
6866
6967 public AutomapSystem(ICoreClientAPI clientAPI, ILogger logger, PersistedConfiguration config)
7068 {
@@ -193,10 +191,18 @@ namespace Automap
193191 if (chunkTopMetadata.Contains(mostActiveCol.Key))
194192 {
195193 chunkMeta = chunkTopMetadata[mostActiveCol.Key];
194+#if DEBUG
195+ Logger.VerboseDebug("Loaded chunk {0}", mostActiveCol.Key);
196+ //Console.WriteLine($"Load {mostActiveCol.Key}");
197+#endif
196198 }
197199 else
198200 {
199201 chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
202+#if DEBUG
203+ Logger.VerboseDebug("Created chunk {0}", mostActiveCol.Key);
204+ //Console.WriteLine($"Created chunk {mostActiveCol.Key}");
205+#endif
200206 }
201207
202208 ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta);
@@ -206,10 +212,9 @@ namespace Automap
206212
207213 if (updatedPixels > 0)
208214 {
209-
210- #if DEBUG
215+#if DEBUG
211216 Logger.VerboseDebug("Wrote chunk shard: ({0}) - Edits#:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, updatedPixels);
212- #endif
217+#endif
213218 updatedChunks++;
214219 chunkTopMetadata.Update(chunkMeta);
215220 columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
@@ -255,7 +260,7 @@ namespace Automap
255260 finally
256261 {
257262 Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name);
258- PersistPointsData( );
263+ PersistPointsData();
259264 }
260265 }
261266
@@ -384,37 +389,46 @@ namespace Automap
384389 {
385390 var worldmapDir = new DirectoryInfo(path);
386391
387- if (worldmapDir.Exists)
392+ if (!worldmapDir.Exists)
388393 {
394+#if DEBUG
395+ Logger.VerboseDebug("Could not open world map directory");
396+#endif
397+ return;
398+ }
399+ var shardFiles = worldmapDir.GetFiles(chunkFile_filter);
389400
390- var shardFiles = worldmapDir.GetFiles(chunkFile_filter);
401+ if (shardFiles.Length > 0)
402+ {
403+#if DEBUG
404+ Logger.VerboseDebug("Metadata reloading from {0} shards", shardFiles.Length);
405+#endif
391406
392- if (shardFiles.Length > 0)
407+ foreach (var shardFile in shardFiles)
393408 {
394- #if DEBUG
395- Logger.VerboseDebug("Metadata reloading from {0} shards", shardFiles.Length);
396- #endif
397-
398- foreach (var shardFile in shardFiles) {
399409
400410 if (shardFile.Length < 1024) continue;
401411 var result = chunkShardRegex.Match(shardFile.Name);
402- if (result.Success) {
403- int X_chunk_pos = int.Parse(result.Groups["X"].Value);
404- int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
412+ if (result.Success)
413+ {
414+ int X_chunk_pos = int.Parse(result.Groups["X"].Value);
415+ int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
405416
406- try
417+ try
407418 {
408- using (var fileStream = shardFile.OpenRead( )) {
409-
410- PngReader pngRead = new PngReader(fileStream);
411- pngRead.ReadSkippingAllRows( );
412- pngRead.End( );
413- //Parse PNG chunks for METADATA in shard
414- PngMetadataChunk metadataFromPng = pngRead.GetChunksList( ).GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
419+ using (var fileStream = shardFile.OpenRead())
420+ {
415421
416- chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
417- }
422+ PngReader pngRead = new PngReader(fileStream);
423+ pngRead.ReadSkippingAllRows();
424+ pngRead.End();
425+ //Parse PNG chunks for METADATA in shard
426+ PngMetadataChunk metadataFromPng = pngRead.GetChunksList().GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
427+ var column = metadataFromPng.ChunkMetadata;
428+ if (column.PrettyLocation == null)
429+ column = column.Reload(ClientAPI);
430+ chunkTopMetadata.Add(column);
431+ }
418432
419433 }
420434 catch (PngjException someEx)
@@ -422,43 +436,37 @@ namespace Automap
422436 Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
423437 continue;
424438 }
425- }
426-
427439 }
440+
428441 }
442+ }
429443
430- //POI and EOI raw dump files ~ reload em!
431- //var poiRawFile = File.
432- string poiPath = Path.Combine(path, poiFileName);
433- string eoiPath = Path.Combine(path, eoiFileName);
444+ //POI and EOI raw dump files ~ reload em!
445+ //var poiRawFile = File.
446+ string poiPath = Path.Combine(path, poiFileName);
447+ string eoiPath = Path.Combine(path, eoiFileName);
434448
435- if (File.Exists(poiPath)) {
436- using (var poiFile = File.OpenRead(poiPath)) {
449+ if (File.Exists(poiPath))
450+ {
451+ using (var poiFile = File.OpenRead(poiPath))
452+ {
437453 this.POIs = Serializer.Deserialize<PointsOfInterest>(poiFile);
438454 Logger.VerboseDebug("Reloaded {0} POIs from file.", this.POIs.Count);
439- }
440455 }
456+ }
441457
442- if (File.Exists(eoiPath)) {
443- using (var eoiFile = File.OpenRead(eoiPath)) {
458+ if (File.Exists(eoiPath))
459+ {
460+ using (var eoiFile = File.OpenRead(eoiPath))
461+ {
444462 this.EOIs = Serializer.Deserialize<EntitiesOfInterest>(eoiFile);
445463 Logger.VerboseDebug("Reloaded {0} EOIs from file.", this.EOIs.Count);
446- }
447464 }
448-
449- }
450- else
451- {
452- #if DEBUG
453- Logger.VerboseDebug("Could not open world map directory");
454- #endif
455465 }
456466
457-
458-
459467 }
460468
461- private PngWriter SetupPngImage(Vec2i coord, ColumnMeta metadata)
469+ private PngWriter SetupPngImage(Vec2i coord, ref ColumnMeta metadata)
462470 {
463471 ImageInfo imageInf = new ImageInfo(chunkSize, chunkSize, 8, false);
464472
@@ -476,7 +484,7 @@ namespace Automap
476484 ChunkMetadata = metadata
477485 };
478486 pngWriter.GetChunksList().Queue(pngChunkMeta);
479- pngWriter.CompLevel = 9;// 9 is the maximum compression
487+ pngWriter.CompLevel = 5;// 9 is the maximum compression but thats too high for the small benefit it gives
480488 pngWriter.CompressionStrategy = Hjg.Pngcs.Zlib.EDeflateCompressStrategy.Huffman;
481489
482490 return pngWriter;
@@ -494,21 +502,22 @@ namespace Automap
494502 int targetChunkY = mapChunk.YMax / chunkSize;//Surface ...
495503 for (; targetChunkY > 0; targetChunkY--)
496504 {
497- WorldChunk chunkData = ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) as WorldChunk;
505+ WorldChunk chunkData = ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) as WorldChunk;
498506
499- if (chunkData == null || chunkData.BlockEntities == null) {
500- #if DEBUG
501- Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
502- #endif
503- continue;
504- }
507+ if (chunkData == null || chunkData.BlockEntities == null)
508+ {
509+#if DEBUG
510+ Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
511+#endif
512+ continue;
513+ }
505514
506515 /*************** Chunk Entities Scanning *********************/
507516 if (chunkData.BlockEntities != null && chunkData.BlockEntities.Length > 0)
508517 {
509- #if DEBUG
518+#if DEBUG
510519 Logger.VerboseDebug("Surface@ {0} = BlockEntities: {1}", key, chunkData.BlockEntities.Length);
511- #endif
520+#endif
512521
513522 foreach (var blockEnt in chunkData.BlockEntities)
514523 {
@@ -576,9 +585,9 @@ namespace Automap
576585 foreach (var loadedEntity in ClientAPI.World.LoadedEntities.ToArray())
577586 {
578587
579- #if DEBUG
588+#if DEBUG
580589 //Logger.VerboseDebug($"ENTITY: ({loadedEntity.Value.Code}) = #{loadedEntity.Value.EntityId} {loadedEntity.Value.State} {loadedEntity.Value.LocalPos} <<<<<<<<<<<<");
581- #endif
590+#endif
582591
583592 var dMatch = Entity_Designators.SingleOrDefault(se => se.Key.Equals(loadedEntity.Value.Code));
584593 if (dMatch.Value != null)
@@ -617,11 +626,12 @@ namespace Automap
617626 {
618627 switch (cmdData.State)
619628 {
620- case CommandType.Run:
629+ case CommandType.Run:
621630 case CommandType.Stop:
622- if (CurrentState != cmdData.State) {
623- CurrentState = cmdData.State;
624- AwakenCartographer(0.0f);
631+ if (CurrentState != cmdData.State)
632+ {
633+ CurrentState = cmdData.State;
634+ AwakenCartographer(0.0f);
625635 }
626636 break;
627637
--- a/Automap/Subsystems/JsonGenerator.cs
+++ b/Automap/Subsystems/JsonGenerator.cs
@@ -22,278 +22,340 @@ namespace Automap
2222 {
2323 private ICoreClientAPI ClientAPI { get; set; }
2424 private ILogger Logger { get; set; }
25- private string path { get; set; }
25+ private string Path { get; set; }
2626 private readonly int chunkSize;
2727
28- internal JArray ColumnMeta_fieldNames,PointsOfInterest_fieldNames,EntitiesOfInterest_fieldNames;
28+ internal JArray ColumnMeta_Names, PointsOfInterest_Names, EntitiesOfInterest_Names;
29+ internal MemberInfo[] ColumnMeta_Vals, PointsOfInterest_Vals, EntitiesOfInterest_Vals;
2930
30- public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path )
31+ public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path)
3132 {
32- this.ClientAPI = _ClientAPI;
33- this.Logger = _Logger;
34- this.path = _path;
35- this.chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
36-
37- ColumnMeta_fieldNames = Dynamic_Names<ColumnMeta>( );
38- PointsOfInterest_fieldNames = Dynamic_Names<PointOfInterest>( );
39- EntitiesOfInterest_fieldNames = Dynamic_Names<EntityOfInterest>( );
40- Logger.VerboseDebug("JSON Ready");
33+ this.ClientAPI = _ClientAPI;
34+ this.Logger = _Logger;
35+ this.Path = _path;
36+ this.chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
37+
38+ ColumnMeta_Names = Dynamic_Names<ColumnMeta>();
39+ ColumnMeta_Vals = Dynamic_Values<ColumnMeta>();
40+ PointsOfInterest_Names = Dynamic_Names<PointOfInterest>();
41+ PointsOfInterest_Vals = Dynamic_Values<PointOfInterest>();
42+ EntitiesOfInterest_Names = Dynamic_Names<EntityOfInterest>();
43+ EntitiesOfInterest_Vals = Dynamic_Values<EntityOfInterest>();
44+ Logger.VerboseDebug("JSON Ready");
4145 }
4246
4347
4448 /// <summary>
4549 /// Generates the JSON Metadata. (in Map object format )
4650 /// </summary>
47- public void GenerateJSONMetadata(ColumnsMetadata chunkTopMetadata, Vec2i startChunkColumn, PointsOfInterest POIs, EntitiesOfInterest EOIs, Dictionary<int, string> RockIdCodes )
51+ public void GenerateJSONMetadata(ColumnsMetadata chunkTopMetadata, Vec2i startChunkColumn, PointsOfInterest POIs, EntitiesOfInterest EOIs, Dictionary<int, string> RockIdCodes)
4852 {
49- string jsonFilename = Path.Combine(path, "Metadata.js");
50-
51- StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
52-
53- using (stream) {
54- JsonTextWriter jsonWriter = new JsonTextWriter(stream);
55-
56- jsonWriter.Formatting = Formatting.None;
57- jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
58- jsonWriter.Indentation = 0;
59- //jsonWriter.AutoCompleteOnClose = true;
60- jsonWriter.QuoteChar = '\'';
61- jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
62- jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
63-
64- /*
65-ViewFrame.chunks
66-vfc ={};
67-// the basic metadata right now
68-vfc.edges = [northmostedge, eastmost, west, south];
69-vfc.chunkMetadataNames=[...]; // the implementation with reflection
70-vfc.chunkMetadata = new Map([['the keys we have', [...metadatas in the same order as the names, stringified(maybe not for rocks thats complicated)],...]);
71-*/
72-
73- using (jsonWriter) {
74- jsonWriter.WriteRaw("ViewFrame.chunks={};\n");
75- jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum=");
76- jsonWriter.WriteValue(ClientAPI.World.Seed);
77- jsonWriter.WriteRaw(";\n");
78-
79- jsonWriter.WriteRaw("ViewFrame.chunks.genTime=");
80- jsonWriter.WriteValue(DateTimeOffset.UtcNow);
81- jsonWriter.WriteRaw(";\n");
82-
83- jsonWriter.WriteRaw("ViewFrame.chunks.startCoords=");
84- jsonWriter.WriteStartArray( );
85- jsonWriter.WriteValue(startChunkColumn.X);
86- jsonWriter.WriteValue(startChunkColumn.Y);
87- jsonWriter.WriteEndArray( );
88- jsonWriter.WriteRaw(";\n");
89-
90- jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize=");
91- jsonWriter.WriteValue(chunkSize);
92- jsonWriter.WriteRaw(";\n");
93-
94- jsonWriter.WriteRaw("ViewFrame.chunks.edges=");//whats NEWS
95- jsonWriter.WriteStartArray( );
96- jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk);
97- jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk);
98- jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk);
99- jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk);
100- jsonWriter.WriteEndArray( );
101- jsonWriter.WriteRaw(";\n");
102-
103- jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadataNames=");
104- ColumnMeta_fieldNames.WriteTo(jsonWriter);
105- jsonWriter.WriteRaw(";\n");
106-
107- jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterestNames=");
108- PointsOfInterest_fieldNames.WriteTo(jsonWriter);
109- jsonWriter.WriteRaw(";\n");
110-
111- jsonWriter.WriteRaw("ViewFrame.chunks.entityOfInterestNames=");
112- EntitiesOfInterest_fieldNames.WriteTo(jsonWriter);
113- jsonWriter.WriteRaw(";\n");
114-
115- //MAP object format - [key, value]: key is "x_y"
116- jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata=");
117- jsonWriter.WriteStartConstructor("Map");
118- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
119-
120-
121- foreach (var shard in chunkTopMetadata) {
122- //TODO:Flatten to array of values...Dynamism!
123- jsonWriter.WriteStartArray( );//Start tuple
124- jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple
125-
126- jsonWriter.WriteStartObject( );
127- jsonWriter.WritePropertyName("prettyCoord");
128- jsonWriter.WriteValue(shard.Location.PrettyCoords(ClientAPI));
129-
130- jsonWriter.WritePropertyName("chunkAge");
131- jsonWriter.WriteValue(shard.ChunkAge);
132-
133- jsonWriter.WritePropertyName("temp");
134- jsonWriter.WriteValue(shard.Temperature);
135-
136- jsonWriter.WritePropertyName("YMax");
137- jsonWriter.WriteValue(shard.YMax);
138-
139- jsonWriter.WritePropertyName("fert");
140- jsonWriter.WriteValue(shard.Fertility);
141-
142- jsonWriter.WritePropertyName("forestDens");
143- jsonWriter.WriteValue(shard.ForestDensity);
144-
145- jsonWriter.WritePropertyName("rain");
146- jsonWriter.WriteValue(shard.Rainfall);
147-
148- jsonWriter.WritePropertyName("shrubDens");
149- jsonWriter.WriteValue(shard.ShrubDensity);
150-
151- jsonWriter.WritePropertyName("airBlocks");
152- jsonWriter.WriteValue(shard.AirBlocks);
153-
154- jsonWriter.WritePropertyName("nonAirBlocks");
155- jsonWriter.WriteValue(shard.NonAirBlocks);
156-
157- //TODO: Heightmap ?
158- //Start rockMap ; FOR a Ratio....on tooltip GUI
159- jsonWriter.WritePropertyName("rockRatio");
160- jsonWriter.WriteStartConstructor("Map");
161- jsonWriter.WriteStartArray( );
162- foreach (var rockEntry in shard.RockRatio) {
163- var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key);
164- jsonWriter.WriteStartArray( );
165- jsonWriter.WriteValue(rockBlock.Code.Path);
166- jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column
167- jsonWriter.WriteEndArray( );
168- }
169- jsonWriter.WriteEndArray( );
170- jsonWriter.WriteEndConstructor( );//end rock-map
171-
172- jsonWriter.WriteEndObject( );//end Map value: {Object}
173- jsonWriter.WriteEndArray( );//end Tuple
174- }
53+ //Console.WriteLine($"53 {chunkTopMetadata.Count}");
54+ string jsonFilename = System.IO.Path.Combine(Path, "Metadata.js");
17555
176- jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata
177- jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata)
178- jsonWriter.WriteRaw(";\n");
56+ StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
17957
180- jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest=");
181- jsonWriter.WriteStartConstructor("Map");
182- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
183-
184- foreach (var poi in POIs) {
185- EmitJsonMap(poi, jsonWriter);
186- }
58+ using (stream)
59+ {
60+ JsonTextWriter jsonWriter = new JsonTextWriter(stream);
61+
62+ jsonWriter.Formatting = Formatting.None;
63+ jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
64+ jsonWriter.Indentation = 0;
65+ //jsonWriter.AutoCompleteOnClose = true;
66+ jsonWriter.QuoteChar = '\'';
67+ jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
68+ jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
69+
70+ using (jsonWriter)
71+ {
72+ jsonWriter.WriteRaw("ViewFrame.chunks=");
73+ jsonWriter.WriteStartObject();
74+ jsonWriter.WriteKeyValue("worldSeedNum", ClientAPI.World.Seed);
75+
76+ jsonWriter.WriteKeyValue("genTime", DateTimeOffset.UtcNow);
77+
78+ jsonWriter.WriteKeyRawValue("startCoords", $"[{startChunkColumn.X},{startChunkColumn.Y}]");
79+
80+ jsonWriter.WriteKeyValue("chunkSize", chunkSize);
81+
82+ // fix later
83+ //jsonWriter.WriteArray("edges", new int[4] {
84+ //chunkTopMetadata.North_mostChunk,
85+ //chunkTopMetadata.East_mostChunk,
86+ //chunkTopMetadata.South_mostChunk,
87+ //chunkTopMetadata.West_mostChunk } );
88+
89+ jsonWriter.WriteArray("chunkMetadataNames", ColumnMeta_Names);
90+
91+ jsonWriter.WriteArray("pointsOfInterestNames", PointsOfInterest_Names);
92+
93+ jsonWriter.WriteArray("entityOfInterestNames", EntitiesOfInterest_Names);
94+
95+ //MAP object format - [key, value]: key is "x_y"
96+ jsonWriter.WriteMapForeach("chunkMetadata", chunkTopMetadata, (shard) =>
97+ {
98+ //Console.WriteLine($"188 {chunkTopMetadata.Count}");
99+ jsonWriter.WriteMapTupleForeach(
100+ $"{shard.Location.X}_{shard.Location.Y}",
101+ ColumnMeta_Vals,
102+ (mem) =>
103+ {
104+ var val = GetValue(mem, shard);
105+ if (IsFloatingType(val))
106+ jsonWriter.WriteValue($"{val:F3}");
107+ else if (IsIntegralType(val))
108+ jsonWriter.WriteValue($"{val}");
109+ else
110+ jsonWriter.WriteValue(val);
111+ }
112+ );
113+ });
114+#if DEBUG
115+ jsonWriter.WriteWhitespace("\n");
116+#endif
117+ jsonWriter.WriteMapForeach("pointsOfInterest", POIs, (poi) =>
118+ {
119+ jsonWriter.WriteMapTupleForeach(
120+ $"{poi.Location.X}_{poi.Location.Z}",
121+ PointsOfInterest_Vals,
122+ (mem) => jsonWriter.WriteValue(GetValue(mem, poi))
123+ );
124+ });
125+#if DEBUG
126+ jsonWriter.WriteWhitespace("\n");
127+#endif
128+ jsonWriter.WriteMapForeach("entityOfInterest", EOIs, (poi) =>
129+ {
130+ jsonWriter.WriteMapTupleForeach(
131+ $"{poi.Location.X}_{poi.Location.Z}",
132+ EntitiesOfInterest_Vals,
133+ (el) => jsonWriter.WriteValue(GetValue(el, poi))
134+ );
135+ });
136+#if DEBUG
137+ jsonWriter.WriteWhitespace("\n");
138+#endif
139+ jsonWriter.WriteWhitespace("\n");
140+ jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
141+ jsonWriter.WriteWhitespace("\n");
142+
143+ jsonWriter.WriteMapForeach("rockLookup", RockIdCodes, (rock) =>
144+ {
145+ var block = ClientAPI.World.GetBlock(rock.Key);
146+ jsonWriter.WriteMapTuple(rock.Key.ToString(), Lang.GetUnformatted(block.Code.Path));
147+ });
148+ jsonWriter.WriteEndObject();
149+ jsonWriter.WriteRaw(";");
150+
151+ jsonWriter.Flush();
152+ }
153+ }
187154
188- foreach (var poi in EOIs) {
189- EmitJsonMap(poi, jsonWriter);
190155 }
191156
192- jsonWriter.WriteEndArray( );
193- jsonWriter.WriteEndConstructor( );
194- jsonWriter.WriteRaw(";\n");
195157
196- jsonWriter.WriteWhitespace("\n");
197- jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
198- jsonWriter.WriteWhitespace("\n");
158+ internal JArray Dynamic_Names<TData>() where TData : struct
159+ {
160+ Dictionary<byte, string> memberNames = new Dictionary<byte, string>();
199161
200- jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup =");
201- jsonWriter.WriteStartConstructor("Map");
202- jsonWriter.WriteStartArray( );//An array of... 2-component arrays
162+ foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
163+ {
164+ DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
165+ if (displayName != null)
166+ {
167+ if (!memberNames.ContainsKey(displayName.order))
168+ {//No duplicates, no overwrites
169+ memberNames.Add(displayName.order, displayName.name);
170+ }
171+ }
172+ }
203173
204- foreach (var entry in RockIdCodes) {
205- var block = ClientAPI.World.GetBlock(entry.Key);
206- // stream.Write("{0},", Lang.GetUnformatted(block.Code.Path));
207- jsonWriter.WriteStartArray( );
208- jsonWriter.WriteValue(block.Code.Path);
174+ return new JArray(memberNames.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray());
175+ }
209176
210- jsonWriter.WriteStartObject( );
211- jsonWriter.WritePropertyName("assetCode");
212- jsonWriter.WriteValue(entry.Value);
177+ internal MemberInfo[] Dynamic_Values<TData>() where TData : struct
178+ {
179+ Dictionary<byte, MemberInfo> memberVals = new Dictionary<byte, MemberInfo>();
213180
214- jsonWriter.WritePropertyName("name");
215- jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path));
216- //}
181+ foreach (var memberInfo in typeof(TData).GetMembers(BindingFlags.Instance | BindingFlags.Public))
182+ {
183+ DisplayNameAttribute displayName = memberInfo.GetCustomAttribute<DisplayNameAttribute>();
184+ if (displayName != null && !memberVals.ContainsKey(displayName.order))
185+ {
186+ memberVals.Add(displayName.order, memberInfo);
187+ }
188+ }
217189
218- jsonWriter.WriteEndObject( );
219- jsonWriter.WriteEndArray( );
190+ return memberVals.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray();
220191 }
221- jsonWriter.WriteEndArray( );
222- jsonWriter.WriteEndConstructor( );
223- //stream.Write("]);\n");
224- jsonWriter.WriteRaw(";\n");
225192
226- jsonWriter.Flush( );
227- }
193+ internal static object GetValue(MemberInfo member, object property)
194+ { // copied from https://stackoverflow.com/questions/12680341/how-to-get-both-fields-and-properties-in-single-call-via-reflection
195+ if (member.MemberType == MemberTypes.Property)
196+ return ((PropertyInfo) member).GetValue(property, null);
197+ else if (member.MemberType == MemberTypes.Field)
198+ return ((FieldInfo) member).GetValue(property);
199+ else
200+ throw new Exception("Property must be of type FieldInfo or PropertyInfo");
228201 }
229202
203+ internal static bool IsFloatingType(object o)
204+ {
205+ if (o == null) return false;
206+ switch (Type.GetTypeCode(o.GetType()))
207+ {
208+ case TypeCode.Decimal:
209+ case TypeCode.Double:
210+ case TypeCode.Single:
211+ return true;
212+ default:
213+ return false;
214+ }
230215 }
231216
232- public void EmitJsonMap(PointOfInterest @this, JsonTextWriter jsonWriter)
217+ internal static bool IsIntegralType(object o)
233218 {
234- jsonWriter.WriteStartArray( );
235- jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}");
236-
237- jsonWriter.WriteStartArray( );
238- //jsonWriter.WriteValue(@this.Name);
239-
240- jsonWriter.WriteValue(@this.Location.X);
241- jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world
242-
243- jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI));
244-
245- jsonWriter.WriteValue(@this.Notes.Replace('\\', ' '));//put more escaping in Java-script if needed
246-
247- jsonWriter.WriteValue(@this.Timestamp);
248-
249- jsonWriter.WriteEndArray( );
250- jsonWriter.WriteEndArray( );
219+ if (o == null) return false;
220+ switch (Type.GetTypeCode(o.GetType()))
221+ {
222+ case TypeCode.Byte:
223+ case TypeCode.SByte:
224+ case TypeCode.UInt16:
225+ case TypeCode.UInt32:
226+ case TypeCode.UInt64:
227+ case TypeCode.Int16:
228+ case TypeCode.Int32:
229+ case TypeCode.Int64:
230+ return true;
231+ default:
232+ return false;
233+ }
251234 }
235+ }
252236
253- public void EmitJsonMap(EntityOfInterest @this, JsonTextWriter jsonWriter)
237+ public static class JsonWriterExtentions
238+ {
239+ /// <summary>
240+ /// Writes an array in the form of key: [...ar] by calling .ToString() on all elements in ar.
241+ /// </summary>
242+ /// <param name="writer"></param>
243+ /// <param name="key"></param>
244+ /// <param name="ar"></param>
245+ public static void WriteArray(this JsonTextWriter writer, string key, object[] ar)
254246 {
255- jsonWriter.WriteStartArray( );
256- jsonWriter.WriteValue($"{@this.Location.X}_{@this.Location.Z}");
257-
258-
259- jsonWriter.WriteStartArray( );
260- //jsonWriter.WriteValue(@this.Name);
261-
262- jsonWriter.WriteValue(@this.Location.X);
263- jsonWriter.WriteValue(@this.Location.Z); //Y is HEIGHT from Mantle... Z is Right from edge of world
264-
265- jsonWriter.WriteValue(@this.Location.PrettyCoords(ClientAPI));
266-
267- jsonWriter.WriteValue(@this.Notes.Replace('\\', ' '));//put more escaping in Java-script if needed
247+ writer.WritePropertyName(key);
248+ writer.WriteStartArray();
249+ foreach (var el in ar)
250+ {
251+ writer.WriteValue(el.ToString());
252+ }
253+ writer.WriteEndArray();
254+ }
268255
269- jsonWriter.WriteValue(@this.Timestamp);
256+ /// <summary>
257+ /// Like WriteArray(string, object[]) but for JArrays.
258+ /// </summary>
259+ /// <param name="writer"></param>
260+ /// <param name="key"></param>
261+ /// <param name="ar"></param>
262+ public static void WriteArray(this JsonTextWriter writer, string key, JArray ar)
263+ {
264+ writer.WritePropertyName(key);
265+ ar.WriteTo(writer);
266+ }
270267
271- //jsonWriter.WriteValue(@this.EntityId);
268+ /// <summary>
269+ /// Easy extention to write JArrays.
270+ /// </summary>
271+ /// <param name="writer"></param>
272+ /// <param name="ar"></param>
273+ public static void WriteValue(this JsonTextWriter writer, JArray ar)
274+ {
275+ ar.WriteTo(writer);
276+ }
272277
273- jsonWriter.WriteEndArray( );
274- jsonWriter.WriteEndArray( );
278+ public static void WriteKeyValue(this JsonTextWriter writer, string key, object value)
279+ {
280+ writer.WritePropertyName(key);
281+ writer.WriteValue(value);
275282 }
276283
284+ public static void WriteKeyRawValue(this JsonTextWriter writer, string key, string value)
285+ {
286+ writer.WritePropertyName(key);
287+ writer.WriteRawValue(value);
288+ }
277289
278- internal JArray Dynamic_Names<TData>( ) where TData : struct
290+ /// <summary>
291+ /// Writes a Map by calling middle in the middle of the Map values array.
292+ /// </summary>
293+ /// <param name="writer"></param>
294+ /// <param name="key"></param>
295+ /// <param name="middle"></param>
296+ public static void WriteMap(this JsonTextWriter writer, string key, System.Action middle)
279297 {
280- Dictionary<byte, string> fieldNames = new Dictionary<byte, string>( );
298+ writer.WritePropertyName(key);
299+ writer.WriteStartConstructor("Map");
300+ writer.WriteStartArray();
301+ middle();
302+ writer.WriteEndArray();
303+ writer.WriteEndConstructor();
304+ }
281305
282- foreach (var fieldInfo in typeof(TData).GetFields(BindingFlags.Instance | BindingFlags.Public)) {
283- DisplayNameAttribute displayName = fieldInfo.GetCustomAttribute<DisplayNameAttribute>();
284- if (displayName != null)
306+ /// <summary>
307+ /// Writes a Map by calling middle on every element in en.
308+ /// </summary>
309+ /// <typeparam name="T"></typeparam>
310+ /// <param name="writer"></param>
311+ /// <param name="key"></param>
312+ /// <param name="en"></param>
313+ /// <param name="middle"></param>
314+ public static void WriteMapForeach<T>(this JsonTextWriter writer, string key, IEnumerable<T> en, System.Action<T> middle)
315+ {
316+ writer.WritePropertyName(key);
317+ writer.WriteStartConstructor("Map");
318+ writer.WriteStartArray();
319+ foreach (var el in en)
285320 {
286- if (!fieldNames.ContainsKey(displayName.order))
287- {//No duplicates, no overwrites
288- fieldNames.Add(displayName.order, displayName.name);
289- }
321+ middle(el);
290322 }
323+ writer.WriteEndArray();
324+ writer.WriteEndConstructor();
291325 }
292326
293- return new JArray(fieldNames.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray());
327+ /// <summary>
328+ /// Writes a Map tuple in the form of [key, value].
329+ /// </summary>
330+ /// <param name="writer"></param>
331+ /// <param name="key"></param>
332+ /// <param name="value"></param>
333+ public static void WriteMapTuple(this JsonTextWriter writer, string key, string value)
334+ {
335+ writer.WriteStartArray();
336+ writer.WriteValue(key);
337+ writer.WriteValue(value);
338+ writer.WriteEndArray();
294339 }
295340
296-
341+ /// <summary>
342+ /// Writes a Map tuple in the form of [key, [val, val]]. Where each val is given by the passed function.
343+ /// </summary>
344+ /// <param name="writer"></param>
345+ /// <param name="key"></param>
346+ /// <param name="middle"></param>
347+ public static void WriteMapTupleForeach<T>(this JsonTextWriter writer, string key, IEnumerable<T> en, System.Action<T> middle)
348+ {
349+ writer.WriteStartArray(); // start tuple
350+ writer.WriteValue(key);
351+ writer.WriteStartArray(); // start val
352+ foreach (var el in en)
353+ {
354+ middle(el);
355+ }
356+ writer.WriteEndArray(); // end val
357+ writer.WriteEndArray(); // end tuple
358+ }
297359 }
298360 }
299361