Automap (client) [VS plugin mod]
Revision | 71533a4171bb5d9bf719b239c3387c7f9c2800e0 (tree) |
---|---|
Time | 2020-04-27 23:25:07 |
Author | The Grand Dog <alex.h@me.c...> |
Commiter | The Grand Dog |
COMPLETE rewrite of the JSON generator to use new lambda based syntax
@@ -11,6 +11,7 @@ using System.IO; | ||
11 | 11 | using System.Collections.ObjectModel; |
12 | 12 | using System.Text; |
13 | 13 | using Vintagestory.API.Client; |
14 | +using Newtonsoft.Json.Linq; | |
14 | 15 | |
15 | 16 | namespace Automap |
16 | 17 | { |
@@ -18,13 +19,17 @@ namespace Automap | ||
18 | 19 | public struct ColumnMeta |
19 | 20 | { |
20 | 21 | [ProtoMember(1)] |
21 | - [DisplayName(0, "Coords.")] | |
22 | 22 | public Vec2i Location; |
23 | 23 | |
24 | + [DisplayName(0, "Coords.")] | |
25 | + public string PrettyLocation; | |
26 | + | |
24 | 27 | [ProtoMember(2)] |
25 | - [DisplayName(1, "Age")] | |
26 | 28 | public TimeSpan ChunkAge;//OLDEST CHUNK. from chunk last edit |
27 | 29 | |
30 | + [DisplayName(1, "Age")] | |
31 | + public string ShortChunkAge { get => ChunkAge.ToString("c"); } | |
32 | + | |
28 | 33 | [ProtoMember(3)] |
29 | 34 | [DisplayName(2, "Temp.")] |
30 | 35 | public float Temperature;// Temperature - surface |
@@ -34,24 +39,38 @@ namespace Automap | ||
34 | 39 | public ushort YMax;// Y feature height |
35 | 40 | |
36 | 41 | [ProtoMember(5)] |
37 | - //[DisplayName(10, "Rocks")] | |
38 | 42 | public Dictionary<int, uint> RockRatio;//[Column] Geographic region (rock) Ratio. [BlockID * count] |
39 | 43 | |
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 | + | |
40 | 59 | [ProtoMember(6)] |
41 | 60 | [DisplayName(4, "Fert.")] |
42 | 61 | public float Fertility; |
43 | 62 | |
44 | 63 | [ProtoMember(7)] |
45 | - [DisplayName(5, "Forest")] | |
46 | - public float ForestDensity; | |
64 | + //[DisplayName(5, "Forest")] | |
65 | + public float ForestDensity; // not given to client | |
47 | 66 | |
48 | 67 | [ProtoMember(8)] |
49 | 68 | [DisplayName(6, "Rain")] |
50 | 69 | public float Rainfall; |
51 | 70 | |
52 | 71 | [ProtoMember(9)] |
53 | - [DisplayName(7, "Shrub")] | |
54 | - public float ShrubDensity; | |
72 | + //[DisplayName(7, "Shrub")] | |
73 | + public float ShrubDensity; // not given to client | |
55 | 74 | |
56 | 75 | [ProtoMember(10)] |
57 | 76 | [DisplayName(8, "Air blocks")] |
@@ -71,10 +90,10 @@ namespace Automap | ||
71 | 90 | [ProtoMember(13)] |
72 | 91 | private ushort[] _flattened_HeightMap; |
73 | 92 | |
74 | - | |
75 | - public ColumnMeta(Vec2i loc, byte chunkSize = 32) | |
93 | + public ColumnMeta(Vec2i loc, ICoreClientAPI clientAPI, byte chunkSize = 32) | |
76 | 94 | { |
77 | 95 | Location = loc; |
96 | + PrettyLocation = loc.PrettyCoords(clientAPI); | |
78 | 97 | ChunkAge = TimeSpan.Zero; |
79 | 98 | Temperature = 0f; |
80 | 99 | YMax = 0; |
@@ -150,6 +169,12 @@ namespace Automap | ||
150 | 169 | } |
151 | 170 | |
152 | 171 | |
172 | + internal ColumnMeta Reload(ICoreClientAPI clientAPI) | |
173 | + { | |
174 | + this.PrettyLocation = Location.PrettyCoords(clientAPI); | |
175 | + Console.Write(PrettyLocation == null ? "*" : ","); | |
176 | + return this; | |
177 | + } | |
153 | 178 | } |
154 | 179 | |
155 | 180 | public class ColumnsMetadata : KeyedCollection<Vec2i, ColumnMeta> |
@@ -3,7 +3,7 @@ using System.Reflection; | ||
3 | 3 | |
4 | 4 | namespace Automap |
5 | 5 | { |
6 | - [AttributeUsage(AttributeTargets.Field)] | |
6 | + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] | |
7 | 7 | public class DisplayNameAttribute : Attribute |
8 | 8 | { |
9 | 9 | public string name; |
@@ -29,6 +29,8 @@ namespace Automap | ||
29 | 29 | public string Notes; |
30 | 30 | |
31 | 31 | [DisplayName(0, "Loc.")] |
32 | + public string PrettyLocation; | |
33 | + | |
32 | 34 | [ProtoMember(3)] |
33 | 35 | public BlockPos Location; |
34 | 36 |
@@ -26,6 +26,8 @@ namespace Automap | ||
26 | 26 | public string Notes; |
27 | 27 | |
28 | 28 | [DisplayName(0, "Loc.")] |
29 | + public string PrettyLocation; | |
30 | + | |
29 | 31 | [ProtoMember(3)] |
30 | 32 | public BlockPos Location; |
31 | 33 |
@@ -98,6 +98,7 @@ namespace Automap | ||
98 | 98 | new PointOfInterest |
99 | 99 | { |
100 | 100 | Name = "Sign", |
101 | + PrettyLocation = posn.PrettyCoords(clientAPI), | |
101 | 102 | Location = posn.Copy(), |
102 | 103 | Notes = signEntity.text, |
103 | 104 | Timestamp = DateTime.UtcNow, |
@@ -124,6 +125,7 @@ namespace Automap | ||
124 | 125 | new PointOfInterest |
125 | 126 | { |
126 | 127 | Name = "Signpost", |
128 | + PrettyLocation = posn.PrettyCoords(clientAPI), | |
127 | 129 | Location = posn.Copy(), |
128 | 130 | Notes = string.Join(",", signEntity.textByCardinalDirection), |
129 | 131 | Timestamp = DateTime.UtcNow, |
@@ -146,6 +148,7 @@ namespace Automap | ||
146 | 148 | poi.AddReplace(new EntityOfInterest |
147 | 149 | { |
148 | 150 | Name = "Trader", |
151 | + PrettyLocation = posn.PrettyCoords(clientAPI), | |
149 | 152 | Location = posn.Copy(), |
150 | 153 | Notes = message, |
151 | 154 | Timestamp = DateTime.UtcNow, |
@@ -174,6 +177,7 @@ namespace Automap | ||
174 | 177 | new PointOfInterest |
175 | 178 | { |
176 | 179 | Name = "Translocator", |
180 | + PrettyLocation = posn.PrettyCoords(clientAPI), | |
177 | 181 | Location = posn.Copy(), |
178 | 182 | Notes = textTarget.ToString(), |
179 | 183 | Timestamp = DateTime.UtcNow, |
@@ -1,22 +1,23 @@ | ||
1 | 1 | #!/usr/local/bin/node |
2 | 2 | |
3 | 3 | // 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 | |
5 | 5 | const fs = require('fs'); |
6 | 6 | |
7 | -fs.readFile('./src/Automap.html', 'utf8', (err, d) => { | |
7 | +fs.readFile(__dirname + '/src/Automap.html', 'utf8', (err, d) => { | |
8 | 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, ''); | |
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>'; | |
14 | 18 | }) |
15 | 19 | .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 => { | |
20 | 21 | if (err) console.log(err); |
21 | 22 | }); |
22 | 23 | }); |
\ No newline at end of file |
@@ -49,7 +49,7 @@ vf.reloadChunkList(); | ||
49 | 49 | var id; |
50 | 50 | vf.map.canvas.addEventListener('wheel', event => { |
51 | 51 | clearTimeout(id); |
52 | - vf.zoom += -Math.sign(event.deltaY); | |
52 | + vf.zoom += -Math.sign(event.deltaY)*2; | |
53 | 53 | id = setTimeout(() => { |
54 | 54 | vf.render(); |
55 | 55 | }, 250); |
@@ -57,37 +57,10 @@ vf.reloadChunkList(); | ||
57 | 57 | }()); |
58 | 58 | |
59 | 59 | // reload the chunk list every six seconds |
60 | +var devBlockReload = false; // disable via command line | |
60 | 61 | (function () { |
61 | 62 | setInterval(() => { |
63 | + if (devBlockReload) return; | |
62 | 64 | vf.reloadChunkList(); |
63 | 65 | }, 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 |
@@ -45,7 +45,6 @@ namespace Automap | ||
45 | 45 | private ColumnsMetadata chunkTopMetadata; |
46 | 46 | private PointsOfInterest POIs = new PointsOfInterest(); |
47 | 47 | private EntitiesOfInterest EOIs = new EntitiesOfInterest(); |
48 | - private string jsonPreBuilt; | |
49 | 48 | |
50 | 49 | internal Dictionary<int, BlockDesignator> BlockID_Designators { get; private set; } |
51 | 50 | internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; } |
@@ -64,7 +63,6 @@ namespace Automap | ||
64 | 63 | |
65 | 64 | public static string AutomapStatusEventKey = @"AutomapStatus"; |
66 | 65 | public static string AutomapCommandEventKey = @"AutomapCommand"; |
67 | - PersistedConfiguration cachedConfiguration; | |
68 | 66 | |
69 | 67 | public AutomapSystem(ICoreClientAPI clientAPI, ILogger logger, PersistedConfiguration config) |
70 | 68 | { |
@@ -193,10 +191,18 @@ namespace Automap | ||
193 | 191 | if (chunkTopMetadata.Contains(mostActiveCol.Key)) |
194 | 192 | { |
195 | 193 | chunkMeta = chunkTopMetadata[mostActiveCol.Key]; |
194 | +#if DEBUG | |
195 | + Logger.VerboseDebug("Loaded chunk {0}", mostActiveCol.Key); | |
196 | + //Console.WriteLine($"Load {mostActiveCol.Key}"); | |
197 | +#endif | |
196 | 198 | } |
197 | 199 | else |
198 | 200 | { |
199 | 201 | chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk); |
202 | +#if DEBUG | |
203 | + Logger.VerboseDebug("Created chunk {0}", mostActiveCol.Key); | |
204 | + //Console.WriteLine($"Created chunk {mostActiveCol.Key}"); | |
205 | +#endif | |
200 | 206 | } |
201 | 207 | |
202 | 208 | ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta); |
@@ -206,10 +212,9 @@ namespace Automap | ||
206 | 212 | |
207 | 213 | if (updatedPixels > 0) |
208 | 214 | { |
209 | - | |
210 | - #if DEBUG | |
215 | +#if DEBUG | |
211 | 216 | Logger.VerboseDebug("Wrote chunk shard: ({0}) - Edits#:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, updatedPixels); |
212 | - #endif | |
217 | +#endif | |
213 | 218 | updatedChunks++; |
214 | 219 | chunkTopMetadata.Update(chunkMeta); |
215 | 220 | columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem); |
@@ -255,7 +260,7 @@ namespace Automap | ||
255 | 260 | finally |
256 | 261 | { |
257 | 262 | Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name); |
258 | - PersistPointsData( ); | |
263 | + PersistPointsData(); | |
259 | 264 | } |
260 | 265 | } |
261 | 266 |
@@ -384,37 +389,46 @@ namespace Automap | ||
384 | 389 | { |
385 | 390 | var worldmapDir = new DirectoryInfo(path); |
386 | 391 | |
387 | - if (worldmapDir.Exists) | |
392 | + if (!worldmapDir.Exists) | |
388 | 393 | { |
394 | +#if DEBUG | |
395 | + Logger.VerboseDebug("Could not open world map directory"); | |
396 | +#endif | |
397 | + return; | |
398 | + } | |
399 | + var shardFiles = worldmapDir.GetFiles(chunkFile_filter); | |
389 | 400 | |
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 | |
391 | 406 | |
392 | - if (shardFiles.Length > 0) | |
407 | + foreach (var shardFile in shardFiles) | |
393 | 408 | { |
394 | - #if DEBUG | |
395 | - Logger.VerboseDebug("Metadata reloading from {0} shards", shardFiles.Length); | |
396 | - #endif | |
397 | - | |
398 | - foreach (var shardFile in shardFiles) { | |
399 | 409 | |
400 | 410 | if (shardFile.Length < 1024) continue; |
401 | 411 | 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); | |
405 | 416 | |
406 | - try | |
417 | + try | |
407 | 418 | { |
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 | + { | |
415 | 421 | |
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 | + } | |
418 | 432 | |
419 | 433 | } |
420 | 434 | catch (PngjException someEx) |
@@ -422,43 +436,37 @@ namespace Automap | ||
422 | 436 | Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx); |
423 | 437 | continue; |
424 | 438 | } |
425 | - } | |
426 | - | |
427 | 439 | } |
440 | + | |
428 | 441 | } |
442 | + } | |
429 | 443 | |
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); | |
434 | 448 | |
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 | + { | |
437 | 453 | this.POIs = Serializer.Deserialize<PointsOfInterest>(poiFile); |
438 | 454 | Logger.VerboseDebug("Reloaded {0} POIs from file.", this.POIs.Count); |
439 | - } | |
440 | 455 | } |
456 | + } | |
441 | 457 | |
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 | + { | |
444 | 462 | this.EOIs = Serializer.Deserialize<EntitiesOfInterest>(eoiFile); |
445 | 463 | Logger.VerboseDebug("Reloaded {0} EOIs from file.", this.EOIs.Count); |
446 | - } | |
447 | 464 | } |
448 | - | |
449 | - } | |
450 | - else | |
451 | - { | |
452 | - #if DEBUG | |
453 | - Logger.VerboseDebug("Could not open world map directory"); | |
454 | - #endif | |
455 | 465 | } |
456 | 466 | |
457 | - | |
458 | - | |
459 | 467 | } |
460 | 468 | |
461 | - private PngWriter SetupPngImage(Vec2i coord, ColumnMeta metadata) | |
469 | + private PngWriter SetupPngImage(Vec2i coord, ref ColumnMeta metadata) | |
462 | 470 | { |
463 | 471 | ImageInfo imageInf = new ImageInfo(chunkSize, chunkSize, 8, false); |
464 | 472 |
@@ -476,7 +484,7 @@ namespace Automap | ||
476 | 484 | ChunkMetadata = metadata |
477 | 485 | }; |
478 | 486 | 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 | |
480 | 488 | pngWriter.CompressionStrategy = Hjg.Pngcs.Zlib.EDeflateCompressStrategy.Huffman; |
481 | 489 | |
482 | 490 | return pngWriter; |
@@ -494,21 +502,22 @@ namespace Automap | ||
494 | 502 | int targetChunkY = mapChunk.YMax / chunkSize;//Surface ... |
495 | 503 | for (; targetChunkY > 0; targetChunkY--) |
496 | 504 | { |
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; | |
498 | 506 | |
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 | + } | |
505 | 514 | |
506 | 515 | /*************** Chunk Entities Scanning *********************/ |
507 | 516 | if (chunkData.BlockEntities != null && chunkData.BlockEntities.Length > 0) |
508 | 517 | { |
509 | - #if DEBUG | |
518 | +#if DEBUG | |
510 | 519 | Logger.VerboseDebug("Surface@ {0} = BlockEntities: {1}", key, chunkData.BlockEntities.Length); |
511 | - #endif | |
520 | +#endif | |
512 | 521 | |
513 | 522 | foreach (var blockEnt in chunkData.BlockEntities) |
514 | 523 | { |
@@ -576,9 +585,9 @@ namespace Automap | ||
576 | 585 | foreach (var loadedEntity in ClientAPI.World.LoadedEntities.ToArray()) |
577 | 586 | { |
578 | 587 | |
579 | - #if DEBUG | |
588 | +#if DEBUG | |
580 | 589 | //Logger.VerboseDebug($"ENTITY: ({loadedEntity.Value.Code}) = #{loadedEntity.Value.EntityId} {loadedEntity.Value.State} {loadedEntity.Value.LocalPos} <<<<<<<<<<<<"); |
581 | - #endif | |
590 | +#endif | |
582 | 591 | |
583 | 592 | var dMatch = Entity_Designators.SingleOrDefault(se => se.Key.Equals(loadedEntity.Value.Code)); |
584 | 593 | if (dMatch.Value != null) |
@@ -617,11 +626,12 @@ namespace Automap | ||
617 | 626 | { |
618 | 627 | switch (cmdData.State) |
619 | 628 | { |
620 | - case CommandType.Run: | |
629 | + case CommandType.Run: | |
621 | 630 | 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); | |
625 | 635 | } |
626 | 636 | break; |
627 | 637 |
@@ -22,278 +22,340 @@ namespace Automap | ||
22 | 22 | { |
23 | 23 | private ICoreClientAPI ClientAPI { get; set; } |
24 | 24 | private ILogger Logger { get; set; } |
25 | - private string path { get; set; } | |
25 | + private string Path { get; set; } | |
26 | 26 | private readonly int chunkSize; |
27 | 27 | |
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; | |
29 | 30 | |
30 | - public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path ) | |
31 | + public JsonGenerator(ICoreClientAPI _ClientAPI, ILogger _Logger, string _path) | |
31 | 32 | { |
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"); | |
41 | 45 | } |
42 | 46 | |
43 | 47 | |
44 | 48 | /// <summary> |
45 | 49 | /// Generates the JSON Metadata. (in Map object format ) |
46 | 50 | /// </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) | |
48 | 52 | { |
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"); | |
175 | 55 | |
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); | |
179 | 57 | |
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 | + } | |
187 | 154 | |
188 | - foreach (var poi in EOIs) { | |
189 | - EmitJsonMap(poi, jsonWriter); | |
190 | 155 | } |
191 | 156 | |
192 | - jsonWriter.WriteEndArray( ); | |
193 | - jsonWriter.WriteEndConstructor( ); | |
194 | - jsonWriter.WriteRaw(";\n"); | |
195 | 157 | |
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>(); | |
199 | 161 | |
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 | + } | |
203 | 173 | |
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 | + } | |
209 | 176 | |
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>(); | |
213 | 180 | |
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 | + } | |
217 | 189 | |
218 | - jsonWriter.WriteEndObject( ); | |
219 | - jsonWriter.WriteEndArray( ); | |
190 | + return memberVals.OrderBy(kf => kf.Key).Select(kf => kf.Value).ToArray(); | |
220 | 191 | } |
221 | - jsonWriter.WriteEndArray( ); | |
222 | - jsonWriter.WriteEndConstructor( ); | |
223 | - //stream.Write("]);\n"); | |
224 | - jsonWriter.WriteRaw(";\n"); | |
225 | 192 | |
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"); | |
228 | 201 | } |
229 | 202 | |
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 | + } | |
230 | 215 | } |
231 | 216 | |
232 | - public void EmitJsonMap(PointOfInterest @this, JsonTextWriter jsonWriter) | |
217 | + internal static bool IsIntegralType(object o) | |
233 | 218 | { |
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 | + } | |
251 | 234 | } |
235 | + } | |
252 | 236 | |
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) | |
254 | 246 | { |
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 | + } | |
268 | 255 | |
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 | + } | |
270 | 267 | |
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 | + } | |
272 | 277 | |
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); | |
275 | 282 | } |
276 | 283 | |
284 | + public static void WriteKeyRawValue(this JsonTextWriter writer, string key, string value) | |
285 | + { | |
286 | + writer.WritePropertyName(key); | |
287 | + writer.WriteRawValue(value); | |
288 | + } | |
277 | 289 | |
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) | |
279 | 297 | { |
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 | + } | |
281 | 305 | |
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) | |
285 | 320 | { |
286 | - if (!fieldNames.ContainsKey(displayName.order)) | |
287 | - {//No duplicates, no overwrites | |
288 | - fieldNames.Add(displayName.order, displayName.name); | |
289 | - } | |
321 | + middle(el); | |
290 | 322 | } |
323 | + writer.WriteEndArray(); | |
324 | + writer.WriteEndConstructor(); | |
291 | 325 | } |
292 | 326 | |
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(); | |
294 | 339 | } |
295 | 340 | |
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 | + } | |
297 | 359 | } |
298 | 360 | } |
299 | 361 |