• 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

Revision5156c68e472ccc1f71aa688c34f649f0a952ee45 (tree)
Time2020-02-29 14:25:41
Authormelchior <melchior@user...>
Commitermelchior

Log Message

Post-PR4 #2: Heightmap in PNG Metadata, JSON encoding for POI notes
partial PNG error mis-handling (untested)

Change Summary

Incremental Difference

--- a/Automap/Automap.csproj
+++ b/Automap/Automap.csproj
@@ -70,6 +70,10 @@
7070 <HintPath>VS_libs\Pngcs.dll</HintPath>
7171 </Reference>
7272 <Reference Include="System.Xml" />
73+ <Reference Include="Newtonsoft.Json">
74+ <HintPath>VS_libs\Newtonsoft.Json.dll</HintPath>
75+ <Private>False</Private>
76+ </Reference>
7377 </ItemGroup>
7478 <ItemGroup>
7579 <Compile Include="AutomapMod.cs" />
--- a/Automap/Data/ColumnMeta.cs
+++ b/Automap/Data/ColumnMeta.cs
@@ -1,7 +1,8 @@
11 using System;
22 using System.Collections.Generic;
33 using System.Collections.ObjectModel;
4-using System.Linq;
4+using System.Collections.Specialized;
5+
56
67 using Vintagestory.API.MathTools;
78 using Vintagestory.API.Common;
@@ -42,16 +43,23 @@ namespace Automap
4243 public float ShrubDensity;
4344
4445 [ProtoMember(10)]
45- public ushort AirBlocks;
46+ public uint AirBlocks;
4647
4748 [ProtoMember(11)]
48- public ushort NonAirBlocks;
49+ public uint NonAirBlocks;
50+
51+ [ProtoMember(12)]
52+ public byte ChunkSize;
53+
4954
50- //[ProtoMember(12,OverwriteList = true)]
5155 [ProtoIgnore]
52- public ushort[,] HeightMap;
56+ public ushort[,] HeightMap;//Needs to be 'flattened' for Protocol-Buffer serialization
57+
58+ [ProtoMember(13)]
59+ private ushort[ ] _flattened_HeightMap;
5360
54- public ColumnMeta(Vec2i loc, int chunkSize = 32)
61+
62+ public ColumnMeta(Vec2i loc, byte chunkSize = 32)
5563 {
5664 Location = loc;
5765 ChunkAge = TimeSpan.Zero;
@@ -64,7 +72,9 @@ namespace Automap
6472 ShrubDensity = 0f;
6573 AirBlocks = 0;
6674 NonAirBlocks = 0;
67- HeightMap = new ushort[chunkSize, chunkSize];
75+ ChunkSize = chunkSize;
76+ HeightMap = new ushort[ChunkSize, ChunkSize];
77+ _flattened_HeightMap = null;
6878 }
6979
7080 internal void UpdateFieldsFrom(ClimateCondition climate, IMapChunk mapChunk, TimeSpan chunkAge)
@@ -77,8 +87,52 @@ namespace Automap
7787 this.ShrubDensity = climate.ShrubDensity;
7888
7989 this.YMax = mapChunk.YMax;
90+ }
91+
92+ [ProtoBeforeSerialization]
93+ private void PrepareData( )
94+ {
95+
96+ if (HeightMap != null) {
97+ _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
98+ int flatIndex = 0;
99+
100+ for (byte col = 0; col < ChunkSize; col++) {
101+ for (byte row = 0; row < ChunkSize; row++) {
102+ _flattened_HeightMap[flatIndex] = HeightMap[col, row];
103+ flatIndex++;
104+ }
105+ }
106+
107+ }
80108
81109 }
110+
111+
112+ [ProtoAfterDeserialization]
113+ private void PostProcess( )
114+ {
115+ if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize];
116+
117+ if (_flattened_HeightMap != null) {
118+ int col, row;
119+
120+ BitVector32 bitMasker = new BitVector32(0);
121+ var rowSection = BitVector32.CreateSection(ChunkSize);
122+ var colSection = BitVector32.CreateSection(ChunkSize, rowSection);
123+
124+ for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++) {
125+ bitMasker = new BitVector32(data: ( int )rowcol);
126+ row = bitMasker[rowSection];
127+ col = bitMasker[colSection];
128+ HeightMap[col, row] = _flattened_HeightMap[rowcol];
129+ }
130+
131+ }
132+
133+ }
134+
135+
82136 }
83137
84138 public class ColumnsMetadata : KeyedCollection<Vec2i, ColumnMeta>
--- a/Automap/Subsystems/AutomapSystem.cs
+++ b/Automap/Subsystems/AutomapSystem.cs
@@ -9,7 +9,7 @@ using System.Threading;
99
1010 using Hjg.Pngcs;
1111 using Hjg.Pngcs.Chunks;
12-
12+using Newtonsoft.Json;
1313 using Vintagestory.API.Client;
1414 using Vintagestory.API.Common;
1515 using Vintagestory.API.Config;
@@ -149,6 +149,7 @@ namespace Automap
149149 {
150150 uint ejectedItem = 0;
151151 uint updatedChunks = 0;
152+ uint updatedPixels = 0;
152153
153154 //-- Should dodge enumerator changing underfoot....at a cost.
154155 if (!columnCounter.IsEmpty)
@@ -167,13 +168,19 @@ namespace Automap
167168 continue;
168169 }
169170
170- ColumnMeta chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
171- PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
171+ ColumnMeta chunkMeta;
172+ if (chunkTopMetadata.Contains(mostActiveCol.Key)) {
173+ chunkMeta = chunkTopMetadata[mostActiveCol.Key];
174+ }
175+ else {
176+ chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
177+ }
178+
172179 UpdateEntityMetadata();
173180 ProcessChunkBlocks(mostActiveCol.Key, mapChunk, chunkMeta);
174181
175-
176- ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out uint updatedPixels);
182+ PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
183+ ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out updatedPixels);
177184
178185 if (updatedPixels > 0)
179186 {
@@ -319,7 +326,7 @@ namespace Automap
319326 jsonWriter.Write("airBlocks:'{0}',", shard.AirBlocks);
320327 jsonWriter.Write("nonAirBlocks:'{0}',", shard.NonAirBlocks);
321328 //TODO: Heightmap
322- //TODO: Rock-ratio
329+ //TODO: Rock-ratio, also requires a BlockID => Name lookup table....elsewhere
323330 jsonWriter.Write("}],");
324331 }
325332 jsonWriter.Write("]);");
@@ -331,7 +338,7 @@ namespace Automap
331338 jsonWriter.Write("['{0}_{1}',", poi.Location.X, poi.Location.Z);
332339 jsonWriter.Write("{");
333340 jsonWriter.Write("prettyCoord:'{0}',", poi.Location.PrettyCoords(ClientAPI));
334- jsonWriter.Write("notes:'{0}',", poi.Notes.Replace("'", "\'").Replace("\n","\\n"));
341+ jsonWriter.Write("notes:{0},", JsonConvert.ToString(poi.Notes, '\'', StringEscapeHandling.EscapeHtml));
335342 jsonWriter.Write("time:new Date('{0}'),", poi.Timestamp.ToString("O"));
336343 jsonWriter.Write("chunkPos:'{0}_{1}',", (poi.Location.X / chunkSize), (poi.Location.Z / chunkSize));
337344 jsonWriter.Write("}],");
@@ -342,7 +349,7 @@ namespace Automap
342349 jsonWriter.Write("['{0}_{1}',", poi.Location.X, poi.Location.Z);
343350 jsonWriter.Write("{");
344351 jsonWriter.Write("prettyCoord:'{0}',", poi.Location.PrettyCoords(ClientAPI));
345- jsonWriter.Write("notes:'{0}',", poi.Notes.Replace("'", "\'"));
352+ jsonWriter.Write("notes:{0},", JsonConvert.ToString(poi.Notes, '\'', StringEscapeHandling.EscapeHtml));
346353 jsonWriter.Write("time:new Date('{0}'),", poi.Timestamp.ToString("O"));
347354 jsonWriter.Write("chunkPos:'{0}_{1}',", (poi.Location.X / chunkSize), (poi.Location.Z / chunkSize));
348355 jsonWriter.Write("}],");
@@ -357,7 +364,7 @@ namespace Automap
357364
358365 private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
359366 {
360- ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), chunkSize);
367+ ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), ( byte )chunkSize);
361368 BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize,
362369 mapChunk.YMax,
363370 mostActiveCol.Key.Y * chunkSize);
@@ -383,37 +390,43 @@ namespace Automap
383390
384391 if (files.Length > 0)
385392 {
386-#if DEBUG
393+ #if DEBUG
387394 Logger.VerboseDebug("{0} Existing world chunk shards", files.Length);
388-#endif
395+ #endif
396+
397+ foreach (var shardFile in files) {
389398
399+ if (shardFile.Length < 1024) continue;
400+ var result = chunkShardRegex.Match(shardFile.Name);
401+ if (result.Success) {
402+ int X_chunk_pos = int.Parse(result.Groups["X"].Value);
403+ int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
390404
391-
392- foreach (var shardFile in files)
393- {
394-
395- if (shardFile.Length < 512) continue;
396- var result = chunkShardRegex.Match(shardFile.Name);
397- if (result.Success)
405+ try
398406 {
399- int X_chunk_pos = int.Parse(result.Groups["X"].Value);
400- int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
407+ using (var fileStream = shardFile.OpenRead( )) {
401408
402- //Parse PNG chunks for METADATA in shard
403- using (var fileStream = shardFile.OpenRead( )) {
404- //TODO: Add corrupted PNG Exception handing HERE !
405- PngReader pngRead = new PngReader(fileStream);
406- pngRead.ReadSkippingAllRows( );
407- pngRead.End( );
409+ PngReader pngRead = new PngReader(fileStream);
410+ pngRead.ReadSkippingAllRows( );
411+ pngRead.End( );
412+ //Parse PNG chunks for METADATA in shard
413+ PngMetadataChunk metadataFromPng = pngRead.GetChunksList( ).GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
408414
409- PngMetadataChunk metadataFromPng = pngRead.GetChunksList( ).GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
415+ chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
416+ }
410417
411- chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
412- }
418+ }
419+ catch (PngjException someEx)
420+ {
421+ Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
422+ continue;
413423 }
414424 }
415425
426+ }
416427 }
428+
429+
417430 }
418431 else
419432 {
@@ -444,12 +457,14 @@ namespace Automap
444457 ChunkMetadata = metadata
445458 };
446459 pngWriter.GetChunksList().Queue(pngChunkMeta);
460+ pngWriter.CompLevel = 9;// 9 is the maximum compression
461+ pngWriter.CompressionStrategy = Hjg.Pngcs.Zlib.EDeflateCompressStrategy.Huffman;
447462
448463 return pngWriter;
449464 }
450465
451466 /// <summary>
452- /// Does the heavy lifting of Scanning columns of chunks - creates Heightmap and Processes POIs, Entities, and stats...
467+ /// Does the heavy lifting of Scanning columns of chunks - scans for BlockEntity, creates Heightmap and stats...
453468 /// </summary>
454469 /// <param name="key">Chunk Coordinate</param>
455470 /// <param name="mapChunk">Map chunk.</param>
@@ -460,20 +475,21 @@ namespace Automap
460475 int targetChunkY = mapChunk.YMax / chunkSize;//Surface ...
461476 for (; targetChunkY > 0; targetChunkY--)
462477 {
463- if (!(ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) is WorldChunk chunkData) || chunkData.BlockEntities == null)
464- {
465-#if DEBUG
466- Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
467-#endif
468- continue;
469- }
478+ WorldChunk chunkData = ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) as WorldChunk;
479+
480+ if (chunkData == null || chunkData.BlockEntities == null) {
481+ #if DEBUG
482+ Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
483+ #endif
484+ continue;
485+ }
470486
471487 /*************** Chunk Entities Scanning *********************/
472488 if (chunkData.BlockEntities != null && chunkData.BlockEntities.Length > 0)
473489 {
474-#if DEBUG
490+ #if DEBUG
475491 Logger.VerboseDebug("Surface@ {0} = BlockEntities: {1}", key, chunkData.BlockEntities.Length);
476-#endif
492+ #endif
477493
478494 foreach (var blockEnt in chunkData.BlockEntities)
479495 {