using Hjg.Pngcs;
using Hjg.Pngcs.Chunks;
+
using Newtonsoft.Json;
+
using Vintagestory.API.Client;
using Vintagestory.API.Common;
using Vintagestory.API.Config;
internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; }
internal Dictionary<int, string> RockIdCodes { get; private set; }
- internal RunState CurrentState { get; set; }
+ internal CommandType CurrentState { get; set; }
//Run status, Chunks processed, stats, center of map....
private uint nullChunkCount, updatedChunksTotal;
private Vec2i startChunkColumn;
private readonly int chunkSize;
private string path;
private IAsset staticMap;
+ private PersistedConfiguration configuration;
+
public static string AutomapStatusEventKey = @"AutomapStatus";
public static string AutomapCommandEventKey = @"AutomapCommand";
+ PersistedConfiguration cachedConfiguration;
-
- public AutomapSystem(ICoreClientAPI clientAPI, ILogger logger)
+ public AutomapSystem(ICoreClientAPI clientAPI, ILogger logger, PersistedConfiguration config)
{
this.ClientAPI = clientAPI;
this.Logger = logger;
chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
ClientAPI.Event.LevelFinalize += EngageAutomap;
+ configuration = config;
+
+
//TODO:Choose which one from GUI
this.ChunkRenderer = new StandardRenderer(clientAPI, logger);
//Listen on bus for commands
ClientAPI.Event.RegisterEventBusListener(CommandListener, 1.0, AutomapSystem.AutomapCommandEventKey);
+ if (configuration.Autostart)
+ {
+ CurrentState = CommandType.Run;
+ Logger.Debug("Autostart is Enabled.");
+ }
+
}
private void AwakenCartographer(float delayed)
{
- if (CurrentState == RunState.Run && (ClientAPI.IsGamePaused != false || ClientAPI.IsShuttingDown != true))
+ if (CurrentState == CommandType.Run && (ClientAPI.IsGamePaused != false || ClientAPI.IsShuttingDown != true))
{
#if DEBUG
Logger.VerboseDebug("Cartographer re-trigger from [{0}]", cartographer_thread.ThreadState);
//ClientAPI.TriggerChatMessage($"Automap {updatedChunksTotal} Updates - MAX (N:{chunkTopMetadata.North_mostChunk},S:{chunkTopMetadata.South_mostChunk},E:{chunkTopMetadata.East_mostChunk}, W:{chunkTopMetadata.West_mostChunk} - TOTAL: {chunkTopMetadata.Count})");
//#endif
}
- else if (CurrentState == RunState.Snapshot)
+ else if (CurrentState == CommandType.Snapshot)
{
//TODO: Snapshot generator second thread...
}
if (!columnCounter.IsEmpty)
{
var tempSet = columnCounter.ToArray().OrderByDescending(kvp => kvp.Value);
+ UpdateEntityMetadata( );
+
foreach (var mostActiveCol in tempSet)
{
-
var mapChunk = ClientAPI.World.BlockAccessor.GetMapChunk(mostActiveCol.Key);
if (mapChunk == null)
chunkMeta = CreateColumnMetadata(mostActiveCol, mapChunk);
}
- UpdateEntityMetadata();
- ProcessChunkBlocks(mostActiveCol.Key, mapChunk, chunkMeta);
+ ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta);
PngWriter pngWriter = SetupPngImage(mostActiveCol.Key, chunkMeta);
ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, pngWriter, out updatedPixels);
if (updatedPixels > 0)
{
-#if DEBUG
+ #if DEBUG
Logger.VerboseDebug("Wrote chunk shard: ({0}) - Edits#:{1}, Pixels#:{2}", mostActiveCol.Key, mostActiveCol.Value, updatedPixels);
-#endif
+ #endif
updatedChunks++;
chunkTopMetadata.Update(chunkMeta);
columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
private void UpdateStatus(uint totalUpdates, uint voidChunks, uint delta)
{
- StatusData updateData = new StatusData(totalUpdates, voidChunks, delta, RunState.Run);
+ StatusData updateData = new StatusData(totalUpdates, voidChunks, delta, CommandType.Run);
this.ClientAPI.Event.PushEvent(AutomapStatusEventKey, updateData);
}
this.BlockID_Designators = new Dictionary<int, BlockDesignator>();
this.Entity_Designators = new Dictionary<AssetLocation, EntityDesignator>();
- this.RockIdCodes = Helpers.ArbitrarytBlockIdHunter(ClientAPI, new AssetLocation(GlobalConstants.DefaultDomain, "rock"), EnumBlockMaterial.Stone);
+ this.RockIdCodes = Helpers.ArbitrarytBlockIdHunter(ClientAPI, new AssetLocation(GlobalConstants.DefaultDomain, "rock-"), EnumBlockMaterial.Stone);
//Add special marker types for BlockID's of "Interest", overwrite colour, and method
- Install_POI_Designators(DefaultDesignators.DefaultBlockDesignators(), DefaultDesignators.DefaultEntityDesignators());
+ Reload_POI_Designators();
}
- private void Install_POI_Designators(ICollection<BlockDesignator> blockDesig, List<EntityDesignator> entDesig)
- {
- Logger.VerboseDebug("Connecting {0} standard Block-Designators", blockDesig.Count);
- foreach (var designator in blockDesig)
+ private void Reload_POI_Designators()
+ {
+ Logger.VerboseDebug("Connecting {0} Configured Block-Designators", configuration.BlockDesignators.Count);
+ foreach (var designator in configuration.BlockDesignators)
{
var blockIDs = Helpers.ArbitrarytBlockIdHunter(ClientAPI, designator.Pattern, designator.Material);
if (blockIDs.Count > 0) { Logger.VerboseDebug("Designator {0} has {1} associated blockIDs", designator.ToString(), blockIDs.Count); }
this.ChunkRenderer.BlockID_Designators = BlockID_Designators;
- Logger.VerboseDebug("Connecting {0} standard Entity-Designators", entDesig.Count);
- foreach (var designator in entDesig)
+ Logger.VerboseDebug("Connecting {0} Configured Entity-Designators", configuration.EntityDesignators.Count);
+ foreach (var designator in configuration.EntityDesignators)
{
//Get Variants first, from EntityTypes...better be populated!
var matched = ClientAPI.World.EntityTypes.FindAll(entp => entp.Code.BeginsWith(designator.Pattern.Domain, designator.Pattern.Path));
}
+ //TODO: Rewrite as Newtonsoft JsonTextWriter !!!
/// <summary>
/// Generates the JSON Metadata. (in Map object format )
/// </summary>
{
string jsonFilename = Path.Combine(path, "Metadata.js");
- StreamWriter jsonWriter = new StreamWriter(jsonFilename, false, Encoding.UTF8);
+ StreamWriter stream = new StreamWriter(jsonFilename, false, Encoding.UTF8);
+
+ using (stream) {
+ JsonTextWriter jsonWriter = new JsonTextWriter(stream);
+
+ jsonWriter.Formatting = Formatting.None;
+ jsonWriter.StringEscapeHandling = StringEscapeHandling.EscapeHtml;
+ jsonWriter.Indentation = 0;
+ //jsonWriter.AutoCompleteOnClose = true;
+ jsonWriter.QuoteChar = '\'';
+ jsonWriter.DateFormatHandling = DateFormatHandling.IsoDateFormat;
+ jsonWriter.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
+
using (jsonWriter)
{
- jsonWriter.Write("ViewFrame.chunks={};");
- jsonWriter.Write("ViewFrame.chunks.worldSeedNum={0};", ClientAPI.World.Seed);
- jsonWriter.Write("ViewFrame.chunks.genTime=new Date('{0}');", DateTimeOffset.UtcNow.ToString("O"));
- jsonWriter.Write("ViewFrame.chunks.startCoords=[{0},{1}];", startChunkColumn.X, startChunkColumn.Y);
- jsonWriter.Write("ViewFrame.chunks.chunkSize={0};", chunkSize);
- jsonWriter.Write("ViewFrame.chunks.northMostChunk={0};", chunkTopMetadata.North_mostChunk);
- jsonWriter.Write("ViewFrame.chunks.southMostChunk={0};", chunkTopMetadata.South_mostChunk);
- jsonWriter.Write("ViewFrame.chunks.eastMostChunk={0};", chunkTopMetadata.East_mostChunk);
- jsonWriter.Write("ViewFrame.chunks.westMostChunk={0};", chunkTopMetadata.West_mostChunk);
- // this is so that the tool tip doesnt need to be hard coded in the map
- jsonWriter.Write("ViewFrame.chunks.chunkMetaNames=[");
- // there are 10 (TEN) (ten) things
- jsonWriter.Write("'Loc.','Age','Temp.','Y Max','Fert.','Forest','Rain','Shrub','Air','Non-Air'");
- jsonWriter.Write("];");
+ jsonWriter.WriteRaw("ViewFrame.chunks={};\n");
+ jsonWriter.WriteRaw("ViewFrame.chunks.worldSeedNum=" );
+ jsonWriter.WriteValue(ClientAPI.World.Seed);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.genTime=");
+ jsonWriter.WriteValue(DateTimeOffset.UtcNow);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.startCoords=");
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue(startChunkColumn.X);
+ jsonWriter.WriteValue(startChunkColumn.Y);
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.chunkSize=");
+ jsonWriter.WriteValue(chunkSize);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.northMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.North_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.southMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.South_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.westMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.West_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.eastMostChunk=");
+ jsonWriter.WriteValue(chunkTopMetadata.East_mostChunk);
+ jsonWriter.WriteRaw(";\n");
+
+
//MAP object format - [key, value]: key is "x_y"
- jsonWriter.Write("ViewFrame.chunks.chunkMetadata=new Map([");
+ jsonWriter.WriteRaw("ViewFrame.chunks.chunkMetadata=");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+
foreach (var shard in chunkTopMetadata)
{
- jsonWriter.Write("['{0}_{1}',", shard.Location.X, shard.Location.Y);
- jsonWriter.Write("[");
- // 10 things but 0 indexed so NINE (9)
- jsonWriter.Write("'{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{9}'",
- shard.Location.PrettyCoords(ClientAPI),
- shard.ChunkAge.ToString("g"),//World age - relative? or last edit ??
- shard.Temperature.ToString("F1"),
- shard.YMax,
- shard.Fertility.ToString("F1"),
- shard.ForestDensity.ToString("F1"),
- shard.Rainfall.ToString("F1"),
- shard.ShrubDensity.ToString("F1"),
- shard.AirBlocks,
- shard.NonAirBlocks
- );
- //TODO: Rock-ratio, also requires a BlockID => Name lookup table....elsewhere
- jsonWriter.Write("]],");
+ jsonWriter.WriteStartArray( );//Start tuple
+ jsonWriter.WriteValue($"{shard.Location.X}_{shard.Location.Y}");//Key of Tuple
+
+ jsonWriter.WriteStartObject( );
+ jsonWriter.WritePropertyName("prettyCoord");
+ jsonWriter.WriteValue( shard.Location.PrettyCoords(ClientAPI));
+
+ jsonWriter.WritePropertyName("chunkAge");
+ jsonWriter.WriteValue(shard.ChunkAge);
+
+ jsonWriter.WritePropertyName("temp");
+ jsonWriter.WriteValue(shard.Temperature);
+
+ jsonWriter.WritePropertyName("YMax");
+ jsonWriter.WriteValue(shard.YMax);
+
+ jsonWriter.WritePropertyName("fert");
+ jsonWriter.WriteValue(shard.Fertility);
+
+ jsonWriter.WritePropertyName("forestDens");
+ jsonWriter.WriteValue( shard.ForestDensity);
+
+ jsonWriter.WritePropertyName("rain");
+ jsonWriter.WriteValue( shard.Rainfall);
+
+ jsonWriter.WritePropertyName("shrubDens");
+ jsonWriter.WriteValue( shard.ShrubDensity);
+
+ jsonWriter.WritePropertyName("airBlocks");
+ jsonWriter.WriteValue( shard.AirBlocks);
+
+ jsonWriter.WritePropertyName("nonAirBlocks");
+ jsonWriter.WriteValue( shard.NonAirBlocks);
+
+ //TODO: Heightmap ?
+ //Start rockMap ; FOR a Ratio....on tooltip GUI
+ jsonWriter.WritePropertyName("rockRatio");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );
+ foreach (var rockEntry in shard.RockRatio) {
+ var rockBlock = ClientAPI.World.GetBlock(rockEntry.Key);
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue(rockBlock.Code.Path);
+ jsonWriter.WriteValue(rockEntry.Value);//Total per chunk-column
+ jsonWriter.WriteEndArray( );
+ }
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndConstructor( );//end rock-map
+
+ jsonWriter.WriteEndObject( );//end Map value: {Object}
+ jsonWriter.WriteEndArray( );//end Tuple
}
- jsonWriter.Write("]);");
+ jsonWriter.WriteEndArray( );//Enclose tuples of chunkMetadata
+ jsonWriter.WriteEndConstructor( );//Close constructor of Map (chunkMetadata)
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.pointsOfInterest=");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );//An array of... 2-component arrays
- jsonWriter.Write("ViewFrame.chunks.pointsOfInterest=new Map([");
foreach (var poi in POIs)
{
- jsonWriter.Write("['{0}_{1}',", (float) poi.Location.X / chunkSize, (float) poi.Location.Z / chunkSize);
- jsonWriter.Write("{");
- jsonWriter.Write("prettyCoord:'{0}',", poi.Location.PrettyCoords(ClientAPI));
- 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.WriteStartArray( );
+ jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
+
+ jsonWriter.WriteStartObject();
+ jsonWriter.WritePropertyName("prettyCoord");
+ jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI) );
+
+ jsonWriter.WritePropertyName("notes");
+ jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
+
+ jsonWriter.WritePropertyName("time");
+ jsonWriter.WriteValue(poi.Timestamp);
+
+ jsonWriter.WritePropertyName("chunkPos");
+ jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
+
+ jsonWriter.WriteEndObject( );
+ jsonWriter.WriteEndArray( );
}
jsonWriter.Write("]);");
jsonWriter.Write("ViewFrame.chunks.entitiesOfInterest=new Map([");
foreach (var eoi in EOIs)
{
- jsonWriter.Write("['{0}_{1}',", (float) eoi.Location.X / chunkSize, (float) eoi.Location.Z / chunkSize);
- jsonWriter.Write("{");
- jsonWriter.Write("prettyCoord:'{0}',", eoi.Location.PrettyCoords(ClientAPI));
- jsonWriter.Write("notes:{0},", JsonConvert.ToString(eoi.Notes, '\'', StringEscapeHandling.EscapeHtml));
- jsonWriter.Write("time:new Date('{0}'),", eoi.Timestamp.ToString("O"));
- jsonWriter.Write("chunkPos:'{0}_{1}',", (eoi.Location.X / chunkSize), (eoi.Location.Z / chunkSize));
- jsonWriter.Write("entityId:'{0}'", eoi.EntityId);
- jsonWriter.Write("}],");
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue($"{poi.Location.X}_{poi.Location.Z}");
+
+ jsonWriter.WriteStartObject( );
+ jsonWriter.WritePropertyName("prettyCoord");
+ jsonWriter.WriteValue(poi.Location.PrettyCoords(ClientAPI));
+
+ jsonWriter.WritePropertyName("notes");
+ jsonWriter.WriteValue(poi.Notes);//Encoded to HTML Entities
+
+ jsonWriter.WritePropertyName("time");
+ jsonWriter.WriteValue(poi.Timestamp);
+
+ jsonWriter.WritePropertyName("chunkPos");
+ jsonWriter.WriteValue($"{(poi.Location.X / chunkSize)}_{(poi.Location.Z / chunkSize)}");
+
+ jsonWriter.WriteEndObject( );
+ jsonWriter.WriteEndArray( );
}
- jsonWriter.Write("]);");
+
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndConstructor( );
+ jsonWriter.WriteRaw(";\n");
+
+ jsonWriter.WriteWhitespace("\n");
+ jsonWriter.WriteComment("============= BlockID's for Rockmap / Rock-ratios ===============");
+ jsonWriter.WriteWhitespace("\n");
+
+ jsonWriter.WriteRaw("ViewFrame.chunks.rock_Lookup =");
+ jsonWriter.WriteStartConstructor("Map");
+ jsonWriter.WriteStartArray( );//An array of... 2-component arrays
+
+ foreach (var entry in RockIdCodes) {
+ var block = ClientAPI.World.GetBlock(entry.Key);
+
+ jsonWriter.WriteStartArray( );
+ jsonWriter.WriteValue(block.Code.Path);
+
+ jsonWriter.WriteStartObject( );
+ jsonWriter.WritePropertyName("assetCode");
+ jsonWriter.WriteValue(entry.Value);
+
+ jsonWriter.WritePropertyName("name");
+ jsonWriter.WriteValue(Lang.GetUnformatted(block.Code.Path));
+ //Color?
+
+ jsonWriter.WriteEndObject( );
+ jsonWriter.WriteEndArray( );
+ }
+ jsonWriter.WriteEndArray( );
+ jsonWriter.WriteEndConstructor();
+
+ jsonWriter.WriteRaw(";\n");
jsonWriter.Flush();
}
+ }
}
/// <param name="key">Chunk Coordinate</param>
/// <param name="mapChunk">Map chunk.</param>
/// <param name="chunkMeta">Chunk metadata</param>
- private void ProcessChunkBlocks(Vec2i key, IMapChunk mapChunk, ColumnMeta chunkMeta)
+ private void ProcessChunkBlocks(Vec2i key, IMapChunk mapChunk, ref ColumnMeta chunkMeta)
{
int targetChunkY = mapChunk.YMax / chunkSize;//Surface ...
{
Logger.Debug("Presently {0} Entities", ClientAPI.World.LoadedEntities.Count);
//Mabey scan only for 'new' entities by tracking ID in set?
- foreach (var loadedEntity in ClientAPI.World.LoadedEntities.ToList())
+ foreach (var loadedEntity in ClientAPI.World.LoadedEntities.ToArray())
{
-#if DEBUG
+ #if DEBUG
//Logger.VerboseDebug($"ENTITY: ({loadedEntity.Value.Code}) = #{loadedEntity.Value.EntityId} {loadedEntity.Value.State} {loadedEntity.Value.LocalPos} <<<<<<<<<<<<");
-#endif
+ #endif
var dMatch = Entity_Designators.SingleOrDefault(se => se.Key.Equals(loadedEntity.Value.Code));
if (dMatch.Value != null)
CommandData cmdData = data as CommandData;
- if (CurrentState != RunState.Snapshot)
+ if (CurrentState != CommandType.Snapshot)
{
switch (cmdData.State)
{
- case RunState.Run:
+ case CommandType.Run:
CurrentState = cmdData.State;
AwakenCartographer(0.0f);
break;
- case RunState.Stop:
+ case CommandType.Stop:
CurrentState = cmdData.State;
break;
- case RunState.Snapshot:
- CurrentState = RunState.Stop;
+ case CommandType.Snapshot:
+ CurrentState = CommandType.Stop;
//Snapshot starts a second thread/process...
break;
- case RunState.Notation:
+ case CommandType.Notation:
//Add to POI list where player location
AddNote(cmdData.Notation);
break;