OSDN Git Service

Added assists aiding Aspiring Apiarists
[automap/automap.git] / Automap / AutomapMod.cs
index 73fc203..7b24649 100644 (file)
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.IO;
-using System.Threading;
-using System.Drawing;
-using System.Drawing.Imaging;
+using System.Collections.ObjectModel;
 using System.Linq;
 
-
 using Vintagestory.API.Client;
 using Vintagestory.API.Common;
-using Vintagestory.API.Common.Entities;
-using Vintagestory.API.Config;
-using Vintagestory.API.MathTools;
-using Vintagestory.API.Server;
-using Vintagestory.GameContent;
-using Vintagestory.API.Datastructures;
 
 
 namespace Automap
 {
-       public class AutomapMod : ModSystem
-       {
-               private ICoreAPI API { get; set; }
-               private ICoreClientAPI ClientAPI { get; set; }
-               private ILogger Logger { get; set; }
+    public class AutomapMod : ModSystem
+    {
+               public const string _configFilename = @"automap.json";
 
-               private const string _mapPath = @"Maps";
-               private const string _chunkPath = @"Chunks";
-               private readonly object colLock = new object( );
-               private Dictionary<Vec2i, uint> columnCounter = new Dictionary<Vec2i, uint>();
-               private HashSet<Vec2i> knownChunkTops = new HashSet<Vec2i>();
-               private Vec2i startPosition;
+        private ICoreAPI API { get; set; }
+        private ICoreClientAPI ClientAPI { get; set; }
+        private ILogger Logger { get; set; }
+        private AutomapSystem _localAutomap;
+        private AutomapGUIDialog _automapDialog;
 
-               private Thread cartographer_thread;
 
-               public override bool ShouldLoad(EnumAppSide forSide)
-               {
-                       return forSide.IsClient();
-               }
+        public override bool ShouldLoad(EnumAppSide forSide)
+        {
+            return forSide.IsClient();
+        }
 
                public override void StartClientSide(ICoreClientAPI api)
-               {                       
+               {
                        this.API = api;
 
-                       if (api.Side == EnumAppSide.Client) {
-                       this.ClientAPI = api as ICoreClientAPI;
-                       this.Logger = Mod.Logger;
-                       
-                       ClientAPI.Event.LevelFinalize += StartAutomap;
-                       }
+                       if (api.Side == EnumAppSide.Client)
+                       {
+                               this.ClientAPI = api as ICoreClientAPI;
+                               this.Logger = Mod.Logger;
 
-                       base.StartClientSide(api);
-               }
+                               ClientAPI.Logger.VerboseDebug("Automap Present!");
+                               PrepareClientsideConfig( );
+                               _localAutomap = new AutomapSystem(this.ClientAPI, this.Logger,  this.CachedConfiguration);
+                               _automapDialog = new AutomapGUIDialog(ClientAPI, _localAutomap, this.CachedConfiguration);
 
-               public override double ExecuteOrder( )
-               {
-               return 0.2;
-               }
+                               ClientAPI.Input.RegisterHotKey(AutomapGUIDialog._automapControlPanelKey, "Automap control panel", GlKeys.M, HotkeyType.GUIOrOtherControls, shiftPressed: true);
+                               ClientAPI.Input.SetHotKeyHandler(AutomapGUIDialog._automapControlPanelKey, ToggleAM_Dialog);
 
+                               ClientAPI.Event.LeaveWorld += PersistParameterChange;
+                       }
 
+            base.StartClientSide(api);
+        }
 
-               #region Internals
-               private void StartAutomap( )
+               public override double ExecuteOrder()
                {
-               Mod.Logger.Notification("AUTOMAP SETUP");
-               startPosition = new Vec2i(ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.X, ClientAPI.World.Player.Entity.LocalPos.AsBlockPos.Z);
-               ClientAPI.Event.ChunkDirty += ChunkAChanging;
-               
-               cartographer_thread = new Thread(Cartographer);
-               cartographer_thread.Name = "Cartographer";
-               cartographer_thread.Priority = ThreadPriority.Lowest;
-               cartographer_thread.IsBackground = true;
-
-               ClientAPI.Event.RegisterGameTickListener(AwakenCartographer, 6000);
+                       return 1.2;
                }
 
-               private void AwakenCartographer(float delayed)
+               private bool ToggleAM_Dialog(KeyCombination comb)
                {
+                       if (_automapDialog.IsOpened()) _automapDialog.TryClose();
+                       else _automapDialog.TryOpen();
 
-               if (ClientAPI.IsGamePaused != false || ClientAPI.IsShuttingDown != true) 
-               {               
-               #if DEBUG
-                       Logger.VerboseDebug("Cartographer re-trigger from [{0}]", cartographer_thread.ThreadState);
-               #endif
-
-                       if (cartographer_thread.ThreadState.HasFlag(ThreadState.Unstarted)) 
-                       {                                       
-                       cartographer_thread.Start( );
-                       }
-                       else if (cartographer_thread.ThreadState.HasFlag(ThreadState.WaitSleepJoin)) {          
-                       //Time to (re)write chunk shards
-                       cartographer_thread.Interrupt( );
-                       }
+                       return true;
                }
 
-               }
-
-
-               private void Cartographer( )
-               {
-       wake:
-               Logger.VerboseDebug("Cartographer thread awoken");
-
-               try {
-
-                       while (columnCounter.Count > 0) 
+               internal PersistedConfiguration CachedConfiguration {
+                       get
                        {
-                       var mostActiveCol = columnCounter.OrderByDescending(kvp => kvp.Value).First();
-                       var mapChunk = ClientAPI.World.BlockAccessor.GetMapChunk(mostActiveCol.Key);
-                       Logger.VerboseDebug("Selected: ({0}) - Edits#:{1}", mostActiveCol.Key, mostActiveCol.Value);
-
-                       if (mapChunk == null) {
-                               Logger.Warning("SKIP CHUNK: ({0}) - Map Chunk NULL!",mostActiveCol.Key);
-                               columnCounter.Remove(mostActiveCol.Key);
-                               continue;
+                       return ( PersistedConfiguration )ClientAPI.ObjectCache[_configFilename];
                        }
-
-                       string filename = $"{mostActiveCol.Key.X}_{mostActiveCol.Key.Y}.png";
-
-                       filename = Path.Combine(ClientAPI.GetOrCreateDataPath(_mapPath), filename);
-
-                       var chkImg = GenerateChunkImage(mostActiveCol.Key, mapChunk);
-                       
-                       chkImg.Save(filename, ImageFormat.Png);
-
-                       knownChunkTops.Add(mostActiveCol.Key);
-                       columnCounter.Remove(mostActiveCol.Key);                        
-                       } 
-
-
-
-               //Then sleep until interupted again, and repeat
-
-               Logger.VerboseDebug("Thread '{0}' about to sleep indefinitely.", Thread.CurrentThread.Name);
-
-               Thread.Sleep(Timeout.Infinite);
-
-               } catch (ThreadInterruptedException) {
-
-               Logger.VerboseDebug("Thread '{0}' interupted [awoken]", Thread.CurrentThread.Name);
-               goto wake;
-
-               } catch (ThreadAbortException) {
-               Logger.VerboseDebug("Thread '{0}' aborted.", Thread.CurrentThread.Name);
-
-               } finally {
-               Logger.VerboseDebug("Thread '{0}' executing finally block.", Thread.CurrentThread.Name);
-               }
-               }
-               #endregion
-
-
-
-               private void ChunkAChanging(Vec3i chunkCoord, IWorldChunk chunk, EnumChunkDirtyReason reason)
-               {
-               //Logger.VerboseDebug($"Change: @({chunkCoord}) R: {reason}");
-               Vec2i topPosition = new Vec2i(chunkCoord.X, chunkCoord.Z);
-               
-                       lock (colLock)
+                       set
                        {
-                       if (columnCounter.ContainsKey(topPosition)) { columnCounter[topPosition]++; } else { columnCounter.Add(topPosition, 1); }
+                       ClientAPI.ObjectCache.Add(_configFilename, value);
                        }
-
                }
 
-               private void print_stats(float interval)
+               private void PrepareClientsideConfig( )
                {
-               if (columnCounter != null && columnCounter.Count > 0) {
-               foreach (var count in columnCounter) {
-               Logger.VerboseDebug($"({count.Key}): {count.Value}");
-               }
-               }
+               PersistedConfiguration config = ClientAPI.LoadModConfig<PersistedConfiguration>(_configFilename);
 
+               if (config == null) {
+               //Regen default
+               Mod.Logger.Warning("Regenerating default config as it was missing / unparsable...");
+               ClientAPI.StoreModConfig<PersistedConfiguration>(new PersistedConfiguration(defaults: true ), _configFilename);
+               config = ClientAPI.LoadModConfig<PersistedConfiguration>(_configFilename);
                }
 
-
-               #region COPYPASTA
-               public Bitmap GenerateChunkImage(Vec2i chunkPos, IMapChunk mc)
-               {
-               BlockPos tmpPos = new BlockPos( );
-               Vec2i localpos = new Vec2i( );          
-               int chunkSize = ClientAPI.World.BlockAccessor.ChunkSize;
-               var chunksColumn = new IWorldChunk[ClientAPI.World.BlockAccessor.MapSizeY / chunkSize];
-               Bitmap chunkImage = new Bitmap(chunkSize, chunkSize, PixelFormat.Format24bppRgb );
-               int topChunkY = mc.YMax / chunkSize;//Heywaitaminute -- this isn't a highest FEATURE, if Rainmap isn't accurate!
-                //Metadata of DateTime chunk was edited, chunk coords.,world-seed? Y-Max feature height
-               //Grab a chunk COLUMN... Topmost Y down...
-               for (int chunkY = 0; chunkY < topChunkY; chunkY++) {
-               chunksColumn[chunkY] = ClientAPI.World.BlockAccessor.GetChunk(chunkPos.X, chunkY, chunkPos.Y);
-               //What to do if chunk is a void? invalid?
+               this.CachedConfiguration = config;
                }
-               
-               // Prefetch map chunks, in pattern
-               IMapChunk[ ] mapChunks = new IMapChunk[ ]
-               {
-                       ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y - 1),
-                       ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X - 1, chunkPos.Y),
-                       ClientAPI.World.BlockAccessor.GetMapChunk(chunkPos.X, chunkPos.Y - 1)
-               };
-                                       
-
-               for (int posIndex = 0; posIndex < (chunkSize * chunkSize); posIndex++) {
-               int mapY = mc.RainHeightMap[posIndex];
-               int localChunkY = mapY / chunkSize;
-               if (localChunkY >= (chunksColumn.Length ) ) continue;//Out of range!
-
-               MapUtil.PosInt2d(posIndex, chunkSize, localpos);
-               int localX = localpos.X;
-               int localZ = localpos.Y;
 
-               float b = 1;
-               int leftTop, rightTop, leftBot;
-
-               IMapChunk leftTopMapChunk = mc;
-               IMapChunk rightTopMapChunk = mc;
-               IMapChunk leftBotMapChunk = mc;
-
-               int topX = localX - 1;
-               int botX = localX;
-               int leftZ = localZ - 1;
-               int rightZ = localZ;
+               internal void PersistParameterChange( )
+               {
+               //Store altered parameters
 
-               if (topX < 0 && leftZ < 0) {
-               leftTopMapChunk = mapChunks[0];
-               rightTopMapChunk = mapChunks[1];
-               leftBotMapChunk = mapChunks[2];
-               }
-               else {
-               if (topX < 0) {
-               leftTopMapChunk = mapChunks[1];
-               rightTopMapChunk = mapChunks[1];
+               ClientAPI.StoreModConfig<PersistedConfiguration>(this.CachedConfiguration, _configFilename);
                }
-               if (leftZ < 0) {
-               leftTopMapChunk = mapChunks[2];
-               leftBotMapChunk = mapChunks[2];
-               }
-               }
-
-               topX = GameMath.Mod(topX, chunkSize);
-               leftZ = GameMath.Mod(leftZ, chunkSize);
-
-               leftTop = leftTopMapChunk == null ? 0 : Math.Sign(mapY - leftTopMapChunk.RainHeightMap[leftZ * chunkSize + topX]);
-               rightTop = rightTopMapChunk == null ? 0 : Math.Sign(mapY - rightTopMapChunk.RainHeightMap[rightZ * chunkSize + topX]);
-               leftBot = leftBotMapChunk == null ? 0 : Math.Sign(mapY - leftBotMapChunk.RainHeightMap[leftZ * chunkSize + botX]);
-
-               float slopeness = (leftTop + rightTop + leftBot);
 
-               if (slopeness > 0) b = 1.2f;
-               if (slopeness < 0) b = 0.8f;
+               #region External Interfaces
+               //Perhaps Other mods can make use of POI / EOI?
 
-               b -= 0.15f; // Map seems overally a bit too bright
-                                       //b = 1;
-               if (chunksColumn[localChunkY] == null) {
-                       
-               continue;
+               public ReadOnlyCollection<PointOfInterest> PointsOfInterest {
+                       get 
+                       {
+                               return _localAutomap.POIs.ToList().AsReadOnly();
+                       }
                }
 
-               chunksColumn[localChunkY].Unpack( );
-               int blockId = chunksColumn[localChunkY].Blocks[MapUtil.Index3d(localpos.X, mapY % chunkSize, localpos.Y, chunkSize, chunkSize)];
-               Block block = ClientAPI.World.Blocks[blockId];
-
-               tmpPos.Set(chunkSize * chunkPos.X + localpos.X, mapY, chunkSize * chunkPos.Y + localpos.Y);
-
-               int avgCol = block.GetColor(ClientAPI, tmpPos);
-               int rndCol = block.GetRandomColor(ClientAPI, tmpPos, BlockFacing.UP);
-               //Merge color?
-               int col = ColorUtil.ColorOverlay(avgCol, rndCol, 0.25f);
-               var packedFormat = ColorUtil.ColorMultiply3Clamped(col, b) | 255 << 24;//Is the Struct, truly so undesirable?
-
-               Color pixelColor = Color.FromArgb(ColorUtil.ColorR(packedFormat), ColorUtil.ColorG(packedFormat), ColorUtil.ColorB(packedFormat));
-               chunkImage.SetPixel(localX,localZ, pixelColor);
+               public ReadOnlyCollection<EntityOfInterest> EntitiesOfInterest {
+                       get 
+                       {
+                               return _localAutomap.EOIs.ToList().AsReadOnly();
+                       }
                }
 
-
-               return chunkImage;
+               public CommandType Status
+               {
+                       get { return _localAutomap.CurrentState; }
                }
+
                #endregion
+
+
        }
 }