private const string _chunkPath = @"Chunks";
private const string _domain = @"automap";
- private ConcurrentDictionary<Vec2i, uint> columnCounter = new ConcurrentDictionary<Vec2i, uint>(3, 103 );//ChunkMeta struct?
- private HashSet<Vec2i> knownChunkTops = new HashSet<Vec2i>( );
+ private ConcurrentDictionary<Vec2i, uint> columnCounter = new ConcurrentDictionary<Vec2i, uint>(3, 150 );
+ private ColumnsMetadata chunkTopMetadata;
private PointsOfInterest POIs;
private Dictionary<int, Designator> BlockID_Designators;
- private int North_mostChunk;
- private int East_mostChunk;
- private int West_mostChunk;
- private int South_mostChunk;
+
private Vec2i startChunkColumn;
private uint lastUpdate;
private void StartAutomap( )
{
path = ClientAPI.GetOrCreateDataPath(_mapPath);
- path = ClientAPI.GetOrCreateDataPath(Path.Combine(path, "World_" + ClientAPI.World.Seed));//Add name of World too!
+ path = ClientAPI.GetOrCreateDataPath(Path.Combine(path, "World_" + ClientAPI.World.Seed));//Add name of World too...'ServerApi.WorldManager.CurrentWorldName'
stylesFile = ClientAPI.World.AssetManager.Get(new AssetLocation(_domain, "config/automap_format.css"));
Logger.VerboseDebug("CSS loaded: {0} size: {1}",stylesFile.IsLoaded() ,stylesFile.ToText( ).Length);
-
Prefill_POI_Designators( );
startChunkColumn = new Vec2i((ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.X / ClientAPI.World.BlockAccessor.ChunkSize), (ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Z / ClientAPI.World.BlockAccessor.ChunkSize));
- North_mostChunk = startChunkColumn.Y;
- South_mostChunk = startChunkColumn.Y;
- East_mostChunk = startChunkColumn.X;
- West_mostChunk = startChunkColumn.X;
+ chunkTopMetadata = new ColumnsMetadata(startChunkColumn);
Logger.Notification("AUTOMAP Start {0}", startChunkColumn);
{
Vec2i topPosition = new Vec2i(chunkCoord.X, chunkCoord.Z);
- columnCounter.AddOrUpdate(topPosition, 1, (key, colAct) => colAct + 1);
+ columnCounter.AddOrUpdate(topPosition, 1, (key, colAct) => colAct + 1);
}
private void AwakenCartographer(float delayed)
//Time to (re)write chunk shards
cartographer_thread.Interrupt( );
}
- ClientAPI.TriggerChatMessage($"Automap {lastUpdate} changes - MAX (N:{North_mostChunk},S:{South_mostChunk},E:{East_mostChunk}, W:{West_mostChunk} - TOTAL: {knownChunkTops.Count})");
+ ClientAPI.TriggerChatMessage($"Automap {lastUpdate} changes - MAX (N:{chunkTopMetadata.North_mostChunk},S:{chunkTopMetadata.South_mostChunk},E:{chunkTopMetadata.East_mostChunk}, W:{chunkTopMetadata.West_mostChunk} - TOTAL: {chunkTopMetadata.Count})");
}
}
try {
uint ejectedItem = 0;
uint updatedChunks = 0;
+
//-- Should dodge enumerator changing underfoot....at a cost.
if (!columnCounter.IsEmpty) {
if (mapChunk == null) {
Logger.Warning("SKIP CHUNK: ({0}) - Map Chunk NULL!", mostActiveCol.Key);
- columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
+ columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem );
continue;
}
string filename = $"{mostActiveCol.Key.X}_{mostActiveCol.Key.Y}.png";
filename = Path.Combine(path, filename);
+ var chunkMeta = UpdateColumnMetadata(mostActiveCol,mapChunk);
+
uint pixels = 0;
var chkImg = GenerateChunkImage(mostActiveCol.Key, mapChunk, out pixels);
Logger.VerboseDebug("Wrote chunk shard: ({0}) - Edits#:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, pixels);
#endif
updatedChunks++;
- knownChunkTops.Add(mostActiveCol.Key);
+ chunkTopMetadata.Update(chunkMeta);
columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
}
else {
Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name);
}
}
- #endregion
+
+ #endregion
private void Prefill_POI_Designators( )
#region COPYPASTA
- //TODO: rewrite - with alternate algo.
+ //TODO: rewrite - with vertical ray caster, down to bottom-most chunk (for object detection...)
//A slightly re-written; ChunkMapLayer :: public int[] GenerateChunkImage(Vec2i chunkPos, IMapChunk mc)
internal Bitmap GenerateChunkImage(Vec2i chunkPos, IMapChunk mc, out uint pixelCount)
{
{
string mapFilename = Path.Combine(path, "Automap.html");
- North_mostChunk = knownChunkTops.Min(tc => tc.Y);
- South_mostChunk = knownChunkTops.Max(tc => tc.Y);
- East_mostChunk = knownChunkTops.Max(tc => tc.X);
- West_mostChunk = knownChunkTops.Min(tc => tc.X);
-
+ int TopNorth = chunkTopMetadata.North_mostChunk;
+ int TopSouth = chunkTopMetadata.South_mostChunk;
+ int TopEast = chunkTopMetadata.East_mostChunk;
+ int TopWest = chunkTopMetadata.West_mostChunk;
using (StreamWriter outputText = new StreamWriter(File.Open(mapFilename, FileMode.Create, FileAccess.Write, FileShare.ReadWrite))) {
using (HtmlTextWriter tableWriter = new HtmlTextWriter(outputText)) {
tableWriter.WriteEncodedText($"Created {DateTimeOffset.UtcNow.ToString("u")}");
tableWriter.RenderEndTag( );
tableWriter.RenderBeginTag(HtmlTextWriterTag.P);
- tableWriter.WriteEncodedText($"W:{West_mostChunk}, E: {East_mostChunk}, N:{North_mostChunk}, S:{South_mostChunk} ");
+ tableWriter.WriteEncodedText($"W:{TopWest}, E: {TopEast}, N:{TopNorth}, S:{TopSouth} ");
tableWriter.RenderEndTag( );
tableWriter.WriteLine( );
tableWriter.RenderBeginTag(HtmlTextWriterTag.Table);
tableWriter.Write("N, W");
tableWriter.RenderEndTag( );
- for (int xAxisT = West_mostChunk; xAxisT <= East_mostChunk; xAxisT++) {
+ for (int xAxisT = TopWest; xAxisT <= TopEast; xAxisT++) {
tableWriter.RenderBeginTag(HtmlTextWriterTag.Th);
tableWriter.Write(xAxisT);
tableWriter.RenderEndTag( );
//###### <tbody> - Chunk rows & Y-axis cols
tableWriter.RenderBeginTag(HtmlTextWriterTag.Tbody);
+
//######## <tr> for every vertical row
- for (int yAxis = North_mostChunk; yAxis <= South_mostChunk; yAxis++) {
+ for (int yAxis = TopNorth; yAxis <= TopSouth; yAxis++) {
tableWriter.RenderBeginTag(HtmlTextWriterTag.Tr);
tableWriter.RenderBeginTag(HtmlTextWriterTag.Td);
tableWriter.Write(yAxis);//legend: Y-axis
tableWriter.RenderEndTag( );
- for (int xAxis = West_mostChunk; xAxis <= East_mostChunk; xAxis++) {
+ for (int xAxis = TopWest; xAxis <= TopEast; xAxis++) {
//###### <td> #### for chunk shard
tableWriter.RenderBeginTag(HtmlTextWriterTag.Td);
- if (knownChunkTops.Contains( new Vec2i(xAxis, yAxis))){
- tableWriter.AddAttribute(HtmlTextWriterAttribute.Src, $"{xAxis}_{yAxis}.png");
- tableWriter.AddAttribute(HtmlTextWriterAttribute.Alt, $"X{xAxis}, Y{yAxis}");
+ var colLoc = new Vec2i(xAxis, yAxis);
+ if (chunkTopMetadata.Contains( colLoc)){
+ ColumnMeta meta = chunkTopMetadata[colLoc];
+ //Tooltip first
+ tableWriter.AddAttribute(HtmlTextWriterAttribute.Class, "tooltip");
+ tableWriter.RenderBeginTag(HtmlTextWriterTag.Div);
+
+ tableWriter.AddAttribute(HtmlTextWriterAttribute.Src, $"{xAxis}_{yAxis}.png");
tableWriter.RenderBeginTag(HtmlTextWriterTag.Img);
tableWriter.RenderEndTag( );
+ // <span class="tooltiptext">Tooltip text
+ tableWriter.AddAttribute(HtmlTextWriterAttribute.Class, "tooltiptext");
+ tableWriter.RenderBeginTag(HtmlTextWriterTag.Span);
+ tableWriter.WriteEncodedText($"{meta.Location.PrettyCoords(ClientAPI)} "+
+ $" Max-Height: {meta.YMax}, Temp: {meta.Temperature.ToString("F1")}"
+ );
+ tableWriter.RenderEndTag( );//</span>
+
+
+
+
+ tableWriter.RenderEndTag( );//</div> --tooltip enclosure
}
else {
tableWriter.Write("?");
- }
+ }
+
tableWriter.RenderEndTag( );
}//############ </td> ###########
tableWriter.RenderEndTag( );
tableWriter.RenderEndTag( );
- tableWriter.EndRender( );
- tableWriter.Flush( );
+
}
tableWriter.RenderEndTag( );
tableWriter.Write("S, W");
tableWriter.RenderEndTag( );
- for (int xAxisB = West_mostChunk; xAxisB <= East_mostChunk; xAxisB++) {
+ for (int xAxisB = TopWest; xAxisB <= TopEast; xAxisB++) {
tableWriter.RenderBeginTag(HtmlTextWriterTag.Td);
tableWriter.Write(xAxisB);
tableWriter.RenderEndTag( );
tableWriter.RenderEndTag( );
tableWriter.RenderEndTag( );
- tableWriter.RenderEndTag( );
+
tableWriter.EndRender( );
tableWriter.Flush( );
+ private ColumnMeta UpdateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
+ {
+ ColumnMeta data = new ColumnMeta(mostActiveCol.Key.Copy());
+ BlockPos equivBP = new BlockPos(mostActiveCol.Key.X * ClientAPI.World.BlockAccessor.ChunkSize,
+ mapChunk.YMax,
+ mostActiveCol.Key.Y * ClientAPI.World.BlockAccessor.ChunkSize);
+
+ var climate = ClientAPI.World.BlockAccessor.GetClimateAt(equivBP);
+ data.Temperature = climate.Temperature;
+ data.YMax = mapChunk.YMax;
+
+
+
+ return data;
+ }
}
}
\ No newline at end of file
--- /dev/null
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+
+using Vintagestory.API.MathTools;
+
+namespace Automap
+{
+
+ public struct ColumnMeta
+ {
+ public Vec2i Location;
+ public float Temperature;// Temperature
+ public int YMax;// Y feature height
+ public Dictionary<int,uint> RockRatio;//(surface) Geographic region (rock) Ratio. [BlockID * count]
+
+ public ColumnMeta(Vec2i loc)
+ {
+ Location = loc;
+ Temperature = 0f;
+ YMax = 0;
+ RockRatio = new Dictionary<int, uint>( 10 );
+ }
+ }
+
+ public class ColumnsMetadata : KeyedCollection<Vec2i, ColumnMeta>
+ {
+ private ColumnsMetadata( )
+ {
+ throw new NotSupportedException();
+ }
+
+ public ColumnsMetadata(Vec2i startChunkColumn)
+ {
+ North_mostChunk = startChunkColumn.Y;
+ South_mostChunk = startChunkColumn.Y;
+ East_mostChunk = startChunkColumn.X;
+ West_mostChunk = startChunkColumn.X;
+ }
+
+ public int North_mostChunk {
+ get; private set;
+ }
+
+ public int South_mostChunk {
+ get; private set;
+ }
+
+ public int East_mostChunk {
+ get; private set;
+ }
+
+ public int West_mostChunk {
+ get; private set;
+ }
+
+ protected override Vec2i GetKeyForItem(ColumnMeta item)
+ {
+ return item.Location;
+ }
+
+ internal void Update(ColumnMeta metaData)
+ {
+ if (this.Contains(metaData.Location)) {
+ this.Remove(metaData.Location);
+ this.Add(metaData);
+ }
+ else {
+ this.Add(metaData);
+ }
+
+ }
+
+ public new void Add(ColumnMeta newItem)
+ {
+ if (North_mostChunk > newItem.Location.Y) {
+ North_mostChunk = newItem.Location.Y;
+ }
+
+ if (South_mostChunk < newItem.Location.Y) {
+ South_mostChunk = newItem.Location.Y;
+ }
+
+ if (East_mostChunk < newItem.Location.X) {
+ East_mostChunk = newItem.Location.X;
+ }
+
+ if (West_mostChunk > newItem.Location.X) {
+ West_mostChunk = newItem.Location.X;
+ }
+
+ base.Add(newItem);
+ }
+
+ }
+}
+