OSDN Git Service

Assorted fixes
[automap/automap.git] / Automap / Subsystems / AutomapSystem.cs
index 11b573a..abbfc44 100644 (file)
@@ -33,21 +33,24 @@ namespace Automap
 
                internal const string _mapPath = @"Maps";
                internal const string _chunkPath = @"Chunks";
+               internal const uint editThreshold = 9;
                private const string _domain = @"automap";
                private const string chunkFile_filter = @"*_*.png";
                private const string poiFileName = @"poi_binary";
                private const string eoiFileName = @"eoi_binary";
                private const string pointsTsvFileName = @"points_of_interest.tsv";
+               private const string plainMetadataFileName = @"map_metadata.txt";
                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();
+               internal PointsOfInterest POIs = new PointsOfInterest();
+               internal EntitiesOfInterest EOIs = new EntitiesOfInterest();
 
                internal Dictionary<int, BlockDesignator> BlockID_Designators { get; private set; }
                internal Dictionary<AssetLocation, EntityDesignator> Entity_Designators { get; private set; }
                internal Dictionary<int, string> RockIdCodes { get; private set; }
+               internal Dictionary<int, string> AiryIdCodes { get; private set; }
 
                internal CommandType CurrentState { get; set; }
                //Run status, Chunks processed, stats, center of map....
@@ -68,11 +71,11 @@ namespace Automap
                        this.ClientAPI = clientAPI;
                        this.Logger = logger;
                        chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
-                       ClientAPI.Event.LevelFinalize += EngageAutomap;
+
                        configuration = config;
+                       ClientAPI.Event.LevelFinalize += EngageAutomap;
 
-                       //TODO:Choose which one from GUI 
-                       this.ChunkRenderer = new StandardRenderer(clientAPI, logger, this.configuration.SeasonalColors);
+                       this.ChunkRenderer = InstantiateChosenRenderer(config.RendererName);
 
                        //Listen on bus for commands
                        ClientAPI.Event.RegisterEventBusListener(CommandListener, 1.0, AutomapSystem.AutomapCommandEventKey);
@@ -131,9 +134,14 @@ namespace Automap
 
                private void ChunkAChanging(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
                {
-                       Vec2i topPosition = new Vec2i(chunkCoord.X, chunkCoord.Z);
-
-                       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, newOrEdit)
+                                            );
+               
                }
 
                private void AwakenCartographer(float delayed)
@@ -179,14 +187,14 @@ namespace Automap
 
                        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)
@@ -196,9 +204,11 @@ namespace Automap
                                                if (mapChunk == null)
                                                {
                                                        //TODO: REVISIT THIS CHUNK!
+                                                       #if DEBUG
                                                        Logger.Warning("SKIP CHUNK: ({0}) - Map Chunk NULL!", mostActiveCol.Key);
+                                                       #endif
                                                        nullMapCount++;
-                                                       columnCounter.TryRemove(mostActiveCol.Key, out ejectedItem);
+                                                       columnCounters.TryRemove(mostActiveCol.Key, out ejectedItem);
                                                        continue;
                                                }
 
@@ -218,29 +228,28 @@ namespace Automap
                                                        #endif
                                                }
                                                ProcessChunkBlocks(mostActiveCol.Key, mapChunk, ref chunkMeta);
+                                               mostActiveCol.Value.SetCutoff(chunkMeta.YMax / chunkSize);
 
                                                ChunkRenderer.SetupPngImage(mostActiveCol.Key, path, _chunkPath, ref chunkMeta);
-                                               ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, out updatedPixels);
+                                               ChunkRenderer.GenerateChunkPngShard(mostActiveCol.Key, mapChunk, chunkMeta, ref chunkTopMetadata, out updatedPixels);
 
                                                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 chun shard: ({0}) ", mostActiveCol.Key);
+                                                       Logger.VerboseDebug("Un-painted chunk shard: ({0}) ", mostActiveCol.Key);
                                                        #endif
                                                }
                                        }
-                                       //Cleanup persisted Metadata...
-                                       chunkTopMetadata.ClearMetadata();
                                }
 
                                UpdateStatus(this.updatedChunksTotal, this.nullChunkCount, updatedChunks);
@@ -251,8 +260,17 @@ namespace Automap
                                        updatedChunksTotal += updatedChunks;
                                        JsonGenerator.GenerateJSONMetadata(chunkTopMetadata, startChunkColumn, POIs, EOIs, RockIdCodes);
                                        updatedChunks = 0;
+
+                                       //Cleanup in-memory Metadata...
+                                       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);
@@ -281,6 +299,7 @@ namespace Automap
                                Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name);
 #endif
                                PersistPointsData();
+                               Write_PlainMetadata( );
                        }
                }
 
@@ -322,41 +341,50 @@ namespace Automap
                        this.Entity_Designators = new Dictionary<AssetLocation, EntityDesignator>();
                        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
+                       var airBlocksQuery = from airyBlock in ClientAPI.World.Blocks
+                                                        where airyBlock.MatterState == EnumMatterState.Solid
+                                                        where airyBlock.BlockMaterial == EnumBlockMaterial.Plant || airyBlock.BlockMaterial == EnumBlockMaterial.Leaves
+                                                        where airyBlock.CollisionBoxes == null || airyBlock.CollisionBoxes.Length == 0 ||airyBlock.RainPermeable == true                                                        
+                                                        select airyBlock;                      
+                       //^^ 'Solid' phase - 'Plant' Blocks without any boundg box ? Except water...
+                       this.AiryIdCodes = airBlocksQuery.ToDictionary(aBlk => aBlk.BlockId, aBlk => aBlk.Code.Path);
 
+                       //Add special marker types for BlockID's of "Interest", overwrite colour, and method
                        Reload_POI_Designators();
                }
 
                private void Reload_POI_Designators()
                {
-                       Logger.VerboseDebug("Connecting {0} Configured Block-Designators", configuration.BlockDesignators.Count);
+               uint poisSetup =0, eoiSetup = 0;
                        foreach (var designator in configuration.BlockDesignators)
                        {
+                               if (designator.Enabled == false) continue;
                                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); }
                                foreach (var entry in blockIDs)
                                {
                                        BlockID_Designators.Add(entry.Key, designator);
+                                       poisSetup++;
                                }
                        }
                        this.ChunkRenderer.BlockID_Designators = BlockID_Designators;
+                       Logger.VerboseDebug("Connected {0} IDs from {1} Block-Designators", poisSetup, configuration.BlockDesignators.Count );
 
 
-                       Logger.VerboseDebug("Connecting {0} Configured Entity-Designators", configuration.EntityDesignators.Count);
                        foreach (var designator in configuration.EntityDesignators)
                        {
+                               if (designator.Enabled == false) continue;
                                //Get Variants first, from EntityTypes...better be populated!
                                var matched = ClientAPI.World.EntityTypes.FindAll(entp => entp.Code.BeginsWith(designator.Pattern.Domain, designator.Pattern.Path));
 
                                foreach (var match in matched)
-                               {
+                               {                                       
                                        Logger.VerboseDebug("Linked Entity: {0} Designator: {1}", match.Code, designator);
                                        this.Entity_Designators.Add(match.Code, designator);
+                                       eoiSetup++;
                                }
-
-                               //EntityProperties props = ClientAPI.World.GetEntityType(designator.Pattern);
                        }
-
+                       Logger.VerboseDebug("Connected {0} IDs from {1} Entity-Designators", eoiSetup, configuration.EntityDesignators.Count);
 
                }
 
@@ -374,17 +402,19 @@ namespace Automap
 
                        if (this.POIs.Count > 0)
                        {
-                               using (var poiFile = File.OpenWrite(poiPath))
+                               using (var poiFile = File.Open(poiPath, FileMode.Create, FileAccess.Write, FileShare.None))
                                {
                                        Serializer.Serialize<PointsOfInterest>(poiFile, this.POIs);
+                                       poiFile.Flush(true);
                                }
                        }
 
                        if (this.EOIs.Count > 0)
                        {
-                               using (var eoiFile = File.OpenWrite(eoiPath))
+                               using (var eoiFile = File.Open(eoiPath, FileMode.Create, FileAccess.Write, FileShare.None))
                                {
                                        Serializer.Serialize<EntitiesOfInterest>(eoiFile, this.EOIs);
+                                       eoiFile.Flush(true);
                                }
                        }
 
@@ -393,31 +423,33 @@ namespace Automap
 
                        using (var tsvWriter = new StreamWriter(pointsTsvPath, false, Encoding.UTF8))
                        {
-                               tsvWriter.WriteLine("Name\tDescription\tLocation\tTime\tDestination");
+                               tsvWriter.WriteLine("Name\tDescription\tLocation\tTime\tDestination\tEntity_UID");
                                foreach (var point in this.POIs)
                                {
                                        tsvWriter.Write(point.Name + "\t");
                                        var notes = point.Notes
-                                               .Replace("\n", "\\n")
+                                               .Replace('\n', '\x001f')
                                                .Replace("\t", "\\t")
                                                .Replace("\\", "\\\\");
                                        tsvWriter.Write(notes + "\t");
                                        tsvWriter.Write(point.Location.PrettyCoords(ClientAPI) + "\t");
                                        tsvWriter.Write(point.Timestamp.ToString("u") + "\t");
                                        tsvWriter.Write((point.Destination != null ? point.Destination.PrettyCoords(ClientAPI) : "---") +"\t");
+                                       tsvWriter.Write("null\t");
                                        tsvWriter.WriteLine();
                                }
                                foreach (var entity in this.EOIs)
                                {
                                        tsvWriter.Write(entity.Name + "\t");
                                        var notes = entity.Notes
-                                               .Replace("\n", "\\n")
+                                               .Replace('\n', '\x001f')
                                                .Replace("\t", "\\t")
                                                .Replace("\\", "\\\\");
                                        tsvWriter.Write(notes + "\t");
                                        tsvWriter.Write(entity.Location.PrettyCoords(ClientAPI) + "\t");
                                        tsvWriter.Write(entity.Timestamp.ToString("u") + "\t");
-                                       tsvWriter.Write("n/a\t");
+                                       tsvWriter.Write("---\t");
+                                       tsvWriter.Write(entity.EntityId.ToString("D"));
                                        tsvWriter.WriteLine();
                                }
                                tsvWriter.WriteLine();
@@ -426,7 +458,33 @@ namespace Automap
 
                }
 
-               private ColumnMeta CreateColumnMetadata(KeyValuePair<Vec2i, uint> mostActiveCol, IMapChunk mapChunk)
+               private void Write_PlainMetadata( )
+               { 
+               string metaPath = Path.Combine(path, plainMetadataFileName);
+
+               using (var metaDataFile = File.Open(metaPath,FileMode.Create)) {
+               using (var mdWriter = new StreamWriter(metaDataFile, Encoding.ASCII)) 
+                       {
+                               mdWriter.WriteLine("WorldSeed {0}", ClientAPI.World.Seed);
+                               mdWriter.WriteLine("PlayerChunkCoords {0:D} {1:D}", startChunkColumn.X, startChunkColumn.Y);
+                               mdWriter.WriteLine("DefaultSpawnPos {0:D} {1:D} {2:D}", ClientAPI.World.DefaultSpawnPosition.AsBlockPos.X,ClientAPI.World.DefaultSpawnPosition.AsBlockPos.Y,ClientAPI.World.DefaultSpawnPosition.AsBlockPos.Z);
+                               mdWriter.WriteLine("ChunkSize {0}", chunkSize);
+                               mdWriter.WriteLine("SeaLevel {0:D}", ClientAPI.World.SeaLevel);
+                               mdWriter.WriteLine("WorldSize {0:D} {1:D} {2:D}", ClientAPI.World.BulkBlockAccessor.MapSizeX, ClientAPI.World.BulkBlockAccessor.MapSizeY,ClientAPI.World.BulkBlockAccessor.MapSizeZ);
+                               mdWriter.WriteLine("RegionSize {0:D}", ClientAPI.World.BulkBlockAccessor.RegionSize);
+                               mdWriter.WriteLine("AMVersion '{0}'", ClientAPI.Self().Info.Version);
+                               mdWriter.WriteLine("PlayTime {0:F1}", ClientAPI.InWorldEllapsedMilliseconds / 1000);
+                               mdWriter.WriteLine("GameDate {0}", ClientAPI.World.Calendar.PrettyDate());
+                               mdWriter.WriteLine("Chunks {0:D}", chunkTopMetadata.Count);
+                               mdWriter.WriteLine("Chunks Updated {0:D}", updatedChunksTotal);
+                               mdWriter.WriteLine("Null Chunks {0:D}", nullChunkCount);        
+                               mdWriter.Flush( );
+                       }
+               }
+               }
+                       
+
+               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,
@@ -537,9 +595,16 @@ namespace Automap
                /// <param name="chunkMeta">Chunk metadata</param>
                private void ProcessChunkBlocks(Vec2i key, IMapChunk mapChunk, ref ColumnMeta chunkMeta)
                {
+                       int targetChunkY = mapChunk.YMax / chunkSize;//Surface ish... 
+                       byte chunkTally = 0;
+
+               #if DEBUG
+               Logger.VerboseDebug("Start col @ X{0} Y{1} Z{2} !", key.X, targetChunkY, key.Y);
+               #endif
+
+               chunkMeta.ResetMetadata(ClientAPI.World.BlockAccessor.MapSizeY);
 
-                       int targetChunkY = mapChunk.YMax / chunkSize;//Surface ... 
-                       for (; targetChunkY > 0; targetChunkY--)
+               for (; targetChunkY > 0; targetChunkY--)
                        {
                                WorldChunk worldChunk = ClientAPI.World.BlockAccessor.GetChunk(key.X, targetChunkY, key.Y) as WorldChunk;
 
@@ -554,7 +619,9 @@ namespace Automap
 
                                if (worldChunk.IsPacked()) 
                                {
+                               #if DEBUG
                                Logger.VerboseDebug("WORLD chunk: Compressed: X{0} Y{1} Z{2}", key.X, targetChunkY, key.Y);
+                               #endif
                                worldChunk.Unpack( );//RESEARCH: Thread Unsafe? 
                                }
 
@@ -567,83 +634,85 @@ namespace Automap
 
                                        foreach (var blockEnt in worldChunk.BlockEntities)
                                        {
-                                               if (blockEnt.Value != null && blockEnt.Value.Block != null && BlockID_Designators.ContainsKey(blockEnt.Value.Block.BlockId))
+                                               if (blockEnt.Key != null && blockEnt.Value != null && blockEnt.Value.Block != null && BlockID_Designators.ContainsKey(blockEnt.Value.Block.BlockId))
                                                {
                                                        var designator = BlockID_Designators[blockEnt.Value.Block.BlockId];
-                                                       designator.SpecialAction(ClientAPI, POIs, blockEnt.Value.Pos.Copy(), blockEnt.Value.Block);
+                                                       designator?.SpecialAction(ClientAPI, POIs, blockEnt.Value.Pos.Copy(), blockEnt.Value.Block);
                                                }
                                        }
                                }
 
-                               //NOTE: Temporary; remove - replace later
-                               if (chunkMeta.ColumnPresense == null) { chunkMeta.ColumnPresense = new BitArray((ClientAPI.World.BlockAccessor.MapSizeY / chunkSize), false); }
-                               chunkMeta.ColumnPresense[targetChunkY] = true;
-
                                /********************* Chunk/Column BLOCKs scanning ****************/
                                //Heightmap, Stats, block tally
 
                                int X_index, Y_index, Z_index;
 
-                               //Ensure ChunkData Metadata fields arn't null...due to being tossed out
-                               if (chunkMeta.HeightMap == null) { chunkMeta.HeightMap = new ushort[chunkSize, chunkSize]; }
-                               if (chunkMeta.RockRatio == null) { chunkMeta.RockRatio = new Dictionary<int, uint>(10); }
-
                                //First Chance fail-safe;
                                if (worldChunk.Blocks == null || worldChunk.Blocks.Length <= 0) {
+                               #if DEBUG
                                Logger.VerboseDebug("WORLD chunk; Missing block DATA⁈ X{0} Y{1} Z{2} ⁈", key.X, targetChunkY, key.Y);
+                               #endif
+                               nullChunkCount++;
                                continue;
                                }               
 
-                               for (Y_index = 0; Y_index < chunkSize - 1; Y_index++)
+                               chunkMeta.ColumnPresense[targetChunkY] = true;
+                               chunkTally++;
+                               for (Y_index = 0; Y_index < chunkSize; Y_index++)
                                {
-                                       for (Z_index = 0; Z_index < chunkSize - 1; Z_index++)
+                                       for (Z_index = 0; Z_index < chunkSize; Z_index++)
                                        {
-                                               for (X_index = 0; X_index < chunkSize - 1; X_index++)
+                                               for (X_index = 0; X_index < chunkSize; X_index++) 
                                                {
-                                               /* Encode packed indicie
-                                               (y * chunksize + z) * chunksize + x
-                                               */
-                                               var indicie = Helpers.ChunkBlockIndicie16(X_index, Y_index, Z_index);
+                                               var indicie = MapUtil.Index3d(X_index, Y_index, Z_index, chunkSize, chunkSize);
 
                                                //'Last' Chance fail-safe;
                                                if (worldChunk.Blocks == null || worldChunk.Blocks.Length <= 0) {
+                                               #if DEBUG
                                                Logger.VerboseDebug("Processing Block: Missing block DATA⁈ X{0} Y{1} Z{2} ⁈", X_index, Y_index, Z_index);
-                                               goto loop_bustout;;
+                                               #endif
+                                               nullChunkCount++;
+                                               goto loop_bustout; 
                                                }
-                                               
+
                                                int aBlockId = worldChunk.Blocks[indicie];
 
-                                               if (aBlockId == 0)
-                                               {//Air
-                                                       chunkMeta.AirBlocks++;
-                                                       continue;
+                                               if (aBlockId == 0 || AiryIdCodes.ContainsKey(aBlockId)) {//Airy blocks,,,
+                                               chunkMeta.AirBlocks++;
+                                               continue;
                                                }
 
-                                               if (RockIdCodes.ContainsKey(aBlockId))
-                                               {
-                                                       if (chunkMeta.RockRatio.ContainsKey(aBlockId))
-                                                               chunkMeta.RockRatio[aBlockId]++;
-                                                       else
-                                                               chunkMeta.RockRatio.Add(aBlockId, 1);
+                                               if (RockIdCodes.ContainsKey(aBlockId)) {
+                                               if (chunkMeta.RockRatio.ContainsKey(aBlockId))
+                                                       chunkMeta.RockRatio[aBlockId]++;
+                                               else
+                                                       chunkMeta.RockRatio.Add(aBlockId, 1);
                                                }
 
                                                chunkMeta.NonAirBlocks++;
 
-                                               //Heightmap 
-                                               if (chunkMeta.HeightMap[X_index, Z_index] == 0)
-                                               {
-                                               chunkMeta.HeightMap[X_index, Z_index] = (ushort) (Y_index + (targetChunkY * chunkSize));
-                                               }
+                                               ushort localHeight = ( ushort )(Y_index + (targetChunkY * chunkSize));
+                                               //Heightmap - Need to ignore Grass & Snow
+                                               if (localHeight > chunkMeta.HeightMap[X_index, Z_index]) 
+                                                       {
+                                                       chunkMeta.HeightMap[X_index, Z_index] = localHeight;
+                                                       if (localHeight > chunkMeta.YMax) chunkMeta.YMax = localHeight;
+                                                       }
                                                }
                                        }
                                }
                                loop_bustout:;
                        }
+                       #if DEBUG
+                       Logger.VerboseDebug("COLUMN X{0} Z{1}: {2}, processed.", key.X , key.Y, chunkTally + 1);
+                       #endif
                }
 
                private void UpdateEntityMetadata()
                {
+                       #if DEBUG
                        Logger.Debug("Presently {0} Entities", ClientAPI.World.LoadedEntities.Count);
+                       #endif
                        //Mabey scan only for 'new' entities by tracking ID in set?
                        foreach (var loadedEntity in ClientAPI.World.LoadedEntities.ToArray())
                        {
@@ -701,12 +770,32 @@ namespace Automap
                                        AddNote(cmdData.Notation);
                                        break;
                        }
-#if DEBUG
+
                        ClientAPI.TriggerChatMessage($"Automap commanded to: {cmdData.State} ");
-#endif
+
                }
-               #endregion
+#endregion
 
+               private AChunkRenderer InstantiateChosenRenderer(string rendererName )
+               {
+               Logger.VerboseDebug("Using '{0}' style Shard Renderer", rendererName);
+               switch (rendererName) 
+               {                               
+               case StandardRenderer.Name:
+                       return new StandardRenderer(ClientAPI, Logger, this.configuration.SeasonalColors);
+               
+               case AlternateRenderer.Name:
+                       return new AlternateRenderer(ClientAPI, Logger, this.configuration.SeasonalColors);
+       
+               case FlatRenderer.Name:
+                       return new FlatRenderer(ClientAPI, Logger, this.configuration.SeasonalColors);  
+
+               default:
+                       throw new ArgumentOutOfRangeException("rendererName",rendererName,"That value isn't supported or known...");
+               }
+
+               return null;
+               }
        }
 
 }