--- /dev/null
+using System;
+using System.Linq;
+
+using Vintagestory.API.MathTools;
+
+namespace Automap
+{
+ public struct ColumnCounter
+ {
+ public bool NewOrLoaded;
+ public byte[] EditTally;
+
+ public uint WeightedSum
+ {
+ get
+ {//TODO: Rank deduction for lower chunks
+ return ( uint )(EditTally.Sum(ed => ed)) + (NewOrLoaded ? 100u : 0u);
+ }
+ }
+
+ public ColumnCounter(int chunkSize)
+ {
+ NewOrLoaded = false;
+ EditTally = new byte[chunkSize];
+ }
+
+ public ColumnCounter(int chunkSize, bool editLoaded)
+ {
+ NewOrLoaded = editLoaded;
+ EditTally = new byte[chunkSize];
+ }
+
+ public ColumnCounter(int chunkSize, bool editLoaded, Vec3i chunkCoord)
+ {
+ int chunkY = chunkCoord.Y % chunkSize;
+
+ NewOrLoaded = editLoaded;
+ EditTally = new byte[chunkSize];
+
+ EditTally[chunkY]++;
+ }
+
+ public ColumnCounter Update(Vec3i chunkCoord, int chunkSize)
+ {
+ int chunkY = chunkCoord.Y % chunkSize;
+ EditTally[chunkY]++;
+
+ return this;
+ }
+
+ public override string ToString( )
+ {
+ return $"{(NewOrLoaded?'N':'O')} W:{WeightedSum}";
+ }
+}
+}
+
var west = new Vec2i(chunkPos.X - 1, chunkPos.Y);
var south = new Vec2i(chunkPos.X, chunkPos.Y - 1);
+ bool nullSouthWest = false, nullSouth = false, nullWest = false;
+
/*
For missing corners / cardinal heightmaps...
make fake heightmap dummy
*/
if (allCols.Contains(south_west)) {
- mapCornerChunks.Add(allCols[south_west]);
+ mapCornerChunks.Add(allCols[south_west]);
}
- else {
- mapCornerChunks.Add(targetColMeta);//TODO: Make mirror image - heightmap
+ else {
+ nullSouthWest = true;
+ mapCornerChunks.Add(targetColMeta);//Temporary!
}
if (allCols.Contains(south)) {
mapCornerChunks.Add(allCols[south]);
}
else {
- mapCornerChunks.Add(targetColMeta);//TODO: Make mirror image - heightmap
+ nullSouth = true;
+ mapCornerChunks.Add(targetColMeta);//Temporary!
}
if (allCols.Contains(west)) {
mapCornerChunks.Add(allCols[west]);
}
else {
- mapCornerChunks.Add(targetColMeta);//TODO: Make mirror image - heightmap
+ nullWest = true;
+ mapCornerChunks.Add(targetColMeta);//Temporary!
}
topX = GameMath.Mod(topX, chunkSize);
leftZ = GameMath.Mod(leftZ, chunkSize);
- leftTop = Math.Sign(localY - leftTopMapChunk.HeightMap[topX, leftZ]);
- rightTop = Math.Sign(localY - rightTopMapChunk.HeightMap[topX, rightZ]);
- leftBot = Math.Sign(localY - leftBotMapChunk.HeightMap[botX, leftZ]);
+ leftTop = nullSouthWest ? 0 : Math.Sign(localY - leftTopMapChunk.HeightMap[topX, leftZ]);
+ rightTop = nullSouth ? 0 : Math.Sign(localY - rightTopMapChunk.HeightMap[topX, rightZ]);
+ leftBot = nullWest ? 0 : Math.Sign(localY - leftBotMapChunk.HeightMap[botX, leftZ]);
float slopeness = (leftTop + rightTop + leftBot);
internal const string _mapPath = @"Maps";
internal const string _chunkPath = @"Chunks";
+ internal const uint editThreshold = 1;
private const string _domain = @"automap";
private const string chunkFile_filter = @"*_*.png";
private const string poiFileName = @"poi_binary";
private const string pointsTsvFileName = @"points_of_interest.tsv";
private static Regex chunkShardRegex = new Regex(@"(?<X>[\d]+)_(?<Z>[\d]+)\.png", RegexOptions.Singleline);
- private ConcurrentDictionary<Vec2i, uint> columnCounter = new ConcurrentDictionary<Vec2i, uint>(3, 150);
+ private ConcurrentDictionary<Vec2i, ColumnCounter> columnCounters = new ConcurrentDictionary<Vec2i, ColumnCounter>(3, 150);
private ColumnsMetadata chunkTopMetadata;
private PointsOfInterest POIs = new PointsOfInterest();
private EntitiesOfInterest EOIs = new EntitiesOfInterest();
private void ChunkAChanging(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
{
- Vec2i topPosition = new Vec2i(chunkCoord.X, chunkCoord.Z);
-
- //TODO: Track Y Chunk - Column, surface chunks being more important
- //Only NEW/LOADED chunks unless edits > N
- //if (reason == EnumChunkDirtyReason.NewlyCreated || reason == EnumChunkDirtyReason.NewlyLoaded)
- //{
- columnCounter.AddOrUpdate(topPosition, 1, (key, colAct) => colAct + 1);
- //}
+ Vec2i topPosition = new Vec2i(chunkCoord.X, chunkCoord.Z);
+ bool newOrEdit = (reason == EnumChunkDirtyReason.NewlyCreated || reason == EnumChunkDirtyReason.NewlyLoaded);
+
+ columnCounters.AddOrUpdate(topPosition,
+ new ColumnCounter(chunkSize, newOrEdit, chunkCoord),
+ (chkPos, chkChng) => chkChng.Update(chunkCoord, chunkSize)
+ );
+
}
private void AwakenCartographer(float delayed)
try
{
- uint ejectedItem = 0;
+ ColumnCounter ejectedItem ;
uint updatedChunks = 0;
uint updatedPixels = 0;
//-- Should dodge enumerator changing underfoot....at a cost.
- if (!columnCounter.IsEmpty)
+ if (!columnCounters.IsEmpty)
{
- var tempSet = columnCounter.ToArray().OrderByDescending(kvp => kvp.Value);
+ var tempSet = columnCounters.ToArray().Where(cks => cks.Value.WeightedSum > editThreshold) .OrderByDescending(kvp => kvp.Value.WeightedSum);
UpdateEntityMetadata();
foreach (var mostActiveCol in tempSet)
//TODO: REVISIT THIS CHUNK!
Logger.Warning("SKIP CHUNK: ({0}) - Map Chunk NULL!", mostActiveCol.Key);
nullMapCount++;
- columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
+ columnCounters.TryRemove(mostActiveCol.Key, out ejectedItem);
continue;
}
if (updatedPixels > 0)
{
#if DEBUG
- Logger.VerboseDebug("Wrote top-chunk shard: ({0}) - Edits#:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, updatedPixels);
+ Logger.VerboseDebug("Wrote top-chunk shard: ({0}) - Weight:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, updatedPixels);
#endif
updatedChunks++;
chunkTopMetadata.Update(chunkMeta);
- columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
+ columnCounters.TryRemove(mostActiveCol.Key, out ejectedItem);
}
else
{
- columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
+ columnCounters.TryRemove(mostActiveCol.Key, out ejectedItem);
#if DEBUG
Logger.VerboseDebug("Un-painted chunk shard: ({0}) ", mostActiveCol.Key);
#endif
chunkTopMetadata.ClearMetadata( );
}
+ #if DEBUG
+ Logger.VerboseDebug("Clearing Column Counters of: {0} non-written shards", columnCounters.Count);
+ #endif
+
+ columnCounters.Clear( );
+
//Then sleep until interupted again, and repeat
#if DEBUG
Logger.VerboseDebug("Thread '{0}' about to sleep indefinitely.", Thread.CurrentThread.Name);
}
- private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
+ private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, ColumnCounter> mostActiveCol, IMapChunk mapChunk)
{
ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy(), ClientAPI, (byte) chunkSize, (ClientAPI.World.BlockAccessor.MapSizeY / chunkSize));
BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * chunkSize,