using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Linq;
+using System.Collections.Specialized;
+
using Vintagestory.API.MathTools;
using Vintagestory.API.Common;
public float ShrubDensity;
[ProtoMember(10)]
- public ushort AirBlocks;
+ public uint AirBlocks;
[ProtoMember(11)]
- public ushort NonAirBlocks;
+ public uint NonAirBlocks;
+
+ [ProtoMember(12)]
+ public byte ChunkSize;
+
- //[ProtoMember(12,OverwriteList = true)]
[ProtoIgnore]
- public ushort[,] HeightMap;
+ public ushort[,] HeightMap;//Needs to be 'flattened' for Protocol-Buffer serialization
+
+ [ProtoMember(13)]
+ private ushort[ ] _flattened_HeightMap;
- public ColumnMeta(Vec2i loc, int chunkSize = 32)
+
+ public ColumnMeta(Vec2i loc, byte chunkSize = 32)
{
Location = loc;
ChunkAge = TimeSpan.Zero;
ShrubDensity = 0f;
AirBlocks = 0;
NonAirBlocks = 0;
- HeightMap = new ushort[chunkSize, chunkSize];
+ ChunkSize = chunkSize;
+ HeightMap = new ushort[ChunkSize, ChunkSize];
+ _flattened_HeightMap = null;
}
internal void UpdateFieldsFrom(ClimateCondition climate, IMapChunk mapChunk, TimeSpan chunkAge)
this.ShrubDensity = climate.ShrubDensity;
this.YMax = mapChunk.YMax;
+ }
+
+ [ProtoBeforeSerialization]
+ private void PrepareData( )
+ {
+
+ if (HeightMap != null) {
+ _flattened_HeightMap = new ushort[ChunkSize * ChunkSize];
+ int flatIndex = 0;
+
+ for (byte col = 0; col < ChunkSize; col++) {
+ for (byte row = 0; row < ChunkSize; row++) {
+ _flattened_HeightMap[flatIndex] = HeightMap[col, row];
+ flatIndex++;
+ }
+ }
+
+ }
}
+
+
+ [ProtoAfterDeserialization]
+ private void PostProcess( )
+ {
+ if (this.HeightMap == null) this.HeightMap = new ushort[ChunkSize, ChunkSize];
+
+ if (_flattened_HeightMap != null) {
+ int col, row;
+
+ BitVector32 bitMasker = new BitVector32(0);
+ var rowSection = BitVector32.CreateSection(ChunkSize);
+ var colSection = BitVector32.CreateSection(ChunkSize, rowSection);
+
+ for (uint rowcol = 0; rowcol < (ChunkSize * ChunkSize); rowcol++) {
+ bitMasker = new BitVector32(data: ( int )rowcol);
+ row = bitMasker[rowSection];
+ col = bitMasker[colSection];
+ HeightMap[col, row] = _flattened_HeightMap[rowcol];
+ }
+
+ }
+
+ }
+
+
}
public class ColumnsMetadata : KeyedCollection<Vec2i, ColumnMeta>
using Hjg.Pngcs;
using Hjg.Pngcs.Chunks;
-
+using Newtonsoft.Json;
using Vintagestory.API.Client;
using Vintagestory.API.Common;
using Vintagestory.API.Config;
{
uint ejectedItem = 0;
uint updatedChunks = 0;
+ uint updatedPixels = 0;
//-- Should dodge enumerator changing underfoot....at a cost.
if (!columnCounter.IsEmpty)
continue;
}
- ColumnMeta chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
- PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
+ ColumnMeta chunkMeta;
+ if (chunkTopMetadata.Contains(mostActiveCol.Key)) {
+ chunkMeta = chunkTopMetadata[mostActiveCol.Key];
+ }
+ else {
+ chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
+ }
+
UpdateEntityMetadata();
ProcessChunkBlocks(mostActiveCol.Key, mapChunk, chunkMeta);
-
- ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out uint updatedPixels);
+ PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
+ ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out updatedPixels);
if (updatedPixels > 0)
{
jsonWriter.Write("airBlocks:'{0}',", shard.AirBlocks);
jsonWriter.Write("nonAirBlocks:'{0}',", shard.NonAirBlocks);
//TODO: Heightmap
- //TODO: Rock-ratio
+ //TODO: Rock-ratio, also requires a BlockID => Name lookup table....elsewhere
jsonWriter.Write("}],");
}
jsonWriter.Write("]);");
jsonWriter.Write("['{0}_{1}',", poi.Location.X, poi.Location.Z);
jsonWriter.Write("{");
jsonWriter.Write("prettyCoord:'{0}',", poi.Location.PrettyCoords(ClientAPI));
- jsonWriter.Write("notes:'{0}',", poi.Notes.Replace("'", "\'").Replace("\n","\\n"));
+ jsonWriter.Write("notes:{0},", JsonConvert.ToString(poi.Notes, '\'', StringEscapeHandling.EscapeHtml));
jsonWriter.Write("time:new Date('{0}'),", poi.Timestamp.ToString("O"));
jsonWriter.Write("chunkPos:'{0}_{1}',", (poi.Location.X / chunkSize), (poi.Location.Z / chunkSize));
jsonWriter.Write("}],");
jsonWriter.Write("['{0}_{1}',", poi.Location.X, poi.Location.Z);
jsonWriter.Write("{");
jsonWriter.Write("prettyCoord:'{0}',", poi.Location.PrettyCoords(ClientAPI));
- jsonWriter.Write("notes:'{0}',", poi.Notes.Replace("'", "\'"));
+ jsonWriter.Write("notes:{0},", JsonConvert.ToString(poi.Notes, '\'', StringEscapeHandling.EscapeHtml));
jsonWriter.Write("time:new Date('{0}'),", poi.Timestamp.ToString("O"));
jsonWriter.Write("chunkPos:'{0}_{1}',", (poi.Location.X / chunkSize), (poi.Location.Z / chunkSize));
jsonWriter.Write("}],");
private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
{
- ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), chunkSize);
+ ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), ( byte )chunkSize);
BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize,
mapChunk.YMax,
mostActiveCol.Key.Y * chunkSize);
if (files.Length > 0)
{
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("{0} Existing world chunk shards", files.Length);
-#endif
+ #endif
+
+ foreach (var shardFile in files) {
+ if (shardFile.Length < 1024) continue;
+ var result = chunkShardRegex.Match(shardFile.Name);
+ if (result.Success) {
+ int X_chunk_pos = int.Parse(result.Groups["X"].Value);
+ int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
-
- foreach (var shardFile in files)
- {
-
- if (shardFile.Length < 512) continue;
- var result = chunkShardRegex.Match(shardFile.Name);
- if (result.Success)
+ try
{
- int X_chunk_pos = int.Parse(result.Groups["X"].Value);
- int Z_chunk_pos = int.Parse(result.Groups["Z"].Value);
+ using (var fileStream = shardFile.OpenRead( )) {
- //Parse PNG chunks for METADATA in shard
- using (var fileStream = shardFile.OpenRead( )) {
- //TODO: Add corrupted PNG Exception handing HERE !
- PngReader pngRead = new PngReader(fileStream);
- pngRead.ReadSkippingAllRows( );
- pngRead.End( );
+ PngReader pngRead = new PngReader(fileStream);
+ pngRead.ReadSkippingAllRows( );
+ pngRead.End( );
+ //Parse PNG chunks for METADATA in shard
+ PngMetadataChunk metadataFromPng = pngRead.GetChunksList( ).GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
- PngMetadataChunk metadataFromPng = pngRead.GetChunksList( ).GetById1(PngMetadataChunk.ID) as PngMetadataChunk;
+ chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
+ }
- chunkTopMetadata.Add(metadataFromPng.ChunkMetadata);
- }
+ }
+ catch (PngjException someEx)
+ {
+ Logger.Error("PNG Corruption file '{0}' - Reason: {1}", shardFile.Name, someEx);
+ continue;
}
}
+ }
}
+
+
}
else
{
ChunkMetadata = metadata
};
pngWriter.GetChunksList().Queue(pngChunkMeta);
+ pngWriter.CompLevel = 9;// 9 is the maximum compression
+ pngWriter.CompressionStrategy = Hjg.Pngcs.Zlib.EDeflateCompressStrategy.Huffman;
return pngWriter;
}
/// <summary>
- /// Does the heavy lifting of Scanning columns of chunks - creates Heightmap and Processes POIs, Entities, and stats...
+ /// Does the heavy lifting of Scanning columns of chunks - scans for BlockEntity, creates Heightmap and stats...
/// </summary>
/// <param name="key">Chunk Coordinate</param>
/// <param name="mapChunk">Map chunk.</param>
int targetChunkY = mapChunk.YMax / chunkSize;//Surface ...
for (; targetChunkY > 0; targetChunkY--)
{
- if (!(ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) is WorldChunk chunkData) || chunkData.BlockEntities == null)
- {
-#if DEBUG
- Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
-#endif
- continue;
- }
+ WorldChunk chunkData = ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) as WorldChunk;
+
+ if (chunkData == null || chunkData.BlockEntities == null) {
+ #if DEBUG
+ Logger.VerboseDebug("Chunk null or empty X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
+ #endif
+ continue;
+ }
/*************** Chunk Entities Scanning *********************/
if (chunkData.BlockEntities != null && chunkData.BlockEntities.Length > 0)
{
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Surface@ {0} = BlockEntities: {1}", key, chunkData.BlockEntities.Length);
-#endif
+ #endif
foreach (var blockEnt in chunkData.BlockEntities)
{