PageRenderTime 64ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Mooege/Core/GS/Map/Debug/DebugNavMesh.cs

https://github.com/angerwin/d3sharp
C# | 347 lines | 263 code | 62 blank | 22 comment | 44 complexity | 64929fb2947935440bc83475f3666e67 MD5 | raw file
  1. /*
  2. * Copyright (C) 2011 mooege project
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. */
  18. using System.Drawing;
  19. using System.Linq;
  20. using System.Threading.Tasks;
  21. using System.Windows;
  22. using Mooege.Common.Helpers.Concurrency;
  23. using Mooege.Core.GS.Actors;
  24. using Mooege.Core.GS.Players;
  25. namespace Mooege.Core.GS.Map.Debug
  26. {
  27. public class DebugNavMesh
  28. {
  29. public World World { get; private set; }
  30. public Player Player { get; private set; }
  31. public Rect Bounds { get { return World.QuadTree.RootNode.Bounds; } }
  32. public ConcurrentList<Scene> MasterScenes { get; private set; }
  33. public ConcurrentList<Scene> SubScenes { get; private set; }
  34. public ConcurrentList<Rect> UnWalkableCells { get; private set; }
  35. public ConcurrentList<Rect> WalkableCells { get; private set; }
  36. public ConcurrentList<Player> Players { get; private set; }
  37. public ConcurrentList<Monster> Monsters { get; private set; }
  38. public ConcurrentList<NPC> NPCs { get; private set; }
  39. public bool DrawMasterScenes;
  40. public bool DrawSubScenes;
  41. public bool DrawWalkableCells;
  42. public bool DrawUnwalkableCells;
  43. public bool DrawMonsters;
  44. public bool DrawNPCs;
  45. public bool DrawPlayers;
  46. public bool PrintSceneLabels;
  47. public bool FillCells;
  48. public bool DrawPlayerProximityCircle;
  49. public bool DrawPlayerProximityRectangle;
  50. private readonly Pen _masterScenePen = new Pen(Color.Black, 1.0f);
  51. private readonly Pen _subScenePen = new Pen(Color.DarkGray, 1.0f);
  52. private readonly Brush _unwalkableBrush = Brushes.Red;
  53. private readonly Pen _unwalkablePen = new Pen(Color.Red, 1.0f);
  54. private readonly Brush _walkableBrush = Brushes.Blue;
  55. private readonly Pen _walkablePen = new Pen(Color.Blue, 1.0f);
  56. private readonly Pen _playerProximityPen = new Pen(Brushes.DarkViolet, 2.0f);
  57. private readonly Font _sceneFont = new Font("Verdana", 7);
  58. public DebugNavMesh(World world, Player player = null)
  59. {
  60. this.World = world;
  61. this.Player = player;
  62. this._subScenePen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot;
  63. this.MasterScenes = new ConcurrentList<Scene>();
  64. this.SubScenes = new ConcurrentList<Scene>();
  65. this.UnWalkableCells = new ConcurrentList<Rect>();
  66. this.WalkableCells = new ConcurrentList<Rect>();
  67. this.Players = new ConcurrentList<Player>();
  68. this.Monsters = new ConcurrentList<Monster>();
  69. this.NPCs = new ConcurrentList<NPC>();
  70. }
  71. #region update
  72. public void Update(bool processObjectsInAllTheWorld)
  73. {
  74. this.MasterScenes.Clear();
  75. this.SubScenes.Clear();
  76. this.WalkableCells.Clear();
  77. this.UnWalkableCells.Clear();
  78. this.Players.Clear();
  79. this.Monsters.Clear();
  80. this.NPCs.Clear();
  81. var scenes = (processObjectsInAllTheWorld || this.Player == null)
  82. ? World.QuadTree.Query<Scene>(World.QuadTree.RootNode.Bounds)
  83. : this.Player.GetScenesInRegion();
  84. Parallel.ForEach(scenes, scene =>
  85. {
  86. if (scene.Parent == null)
  87. this.MasterScenes.Add(scene);
  88. else
  89. this.SubScenes.Add(scene);
  90. this.AnalyzeScene(scene);
  91. });
  92. var actors = (processObjectsInAllTheWorld || this.Player == null)
  93. ? World.QuadTree.Query<Actor>(World.QuadTree.RootNode.Bounds)
  94. : this.Player.GetActorsInRange();
  95. Parallel.ForEach(actors, actor =>
  96. {
  97. if (actor is Player)
  98. this.Players.Add(actor as Player);
  99. else if (actor is NPC)
  100. this.NPCs.Add(actor as NPC);
  101. else if (actor is Monster)
  102. this.Monsters.Add(actor as Monster);
  103. });
  104. }
  105. private void AnalyzeScene(Scene scene)
  106. {
  107. Parallel.ForEach(scene.NavZone.NavCells, cell =>
  108. {
  109. float x = scene.Position.X + cell.Min.X;
  110. float y = scene.Position.Y + cell.Min.Y;
  111. float sizex = cell.Max.X - cell.Min.X;
  112. float sizey = cell.Max.Y - cell.Min.Y;
  113. var rect = new Rect(x, y, sizex, sizey);
  114. // TODO: Feature request: Also allow drawing of NavCellFlags.NOSpawn, NavCellFlags.LevelAreaBit0, NavCellFlags.LevelAreaBit1 cells. /raist.
  115. if ((cell.Flags & Mooege.Common.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk) != Mooege.Common.MPQ.FileFormats.Scene.NavCellFlags.AllowWalk)
  116. UnWalkableCells.Add(rect);
  117. else
  118. WalkableCells.Add(rect);
  119. });
  120. }
  121. #endregion
  122. #region drawing
  123. public Bitmap Draw()
  124. {
  125. // As quad-tree always has 4 quad-nodes beneath the root node, the quad node's area will be far larger then actual area covered by scenes.
  126. // We don't want to draw a bitmap that's as large as quad-tree's area, as it'll be consuming so much memory.
  127. // So instead find the rightMostScene and bottomMostScene and limit the drawed bitmaps size according. /raist.
  128. // TODO: We can even limit to leftMostScene and topMostScene because player-proximity rendering mode will be also containing large empty areas. /raist.
  129. Scene rightMostScene = null;
  130. Scene bottomMostScene = null;
  131. foreach (var scene in this.MasterScenes)
  132. {
  133. if (rightMostScene == null)
  134. rightMostScene = scene;
  135. if (bottomMostScene == null)
  136. bottomMostScene = scene;
  137. if (scene.Bounds.X + scene.Bounds.Width > rightMostScene.Bounds.X + rightMostScene.Bounds.Width)
  138. rightMostScene = scene;
  139. if (scene.Bounds.Y + scene.Bounds.Height > bottomMostScene.Bounds.Y + bottomMostScene.Bounds.Height)
  140. bottomMostScene = scene;
  141. }
  142. if (rightMostScene == null || bottomMostScene == null)
  143. return null;
  144. var maxX = (int) (rightMostScene.Bounds.X + rightMostScene.Bounds.Width) + 1;
  145. var maxY = (int)(bottomMostScene.Bounds.Y + bottomMostScene.Bounds.Height) + 1;
  146. var bitmap = new Bitmap(maxX, maxY, System.Drawing.Imaging.PixelFormat.Format16bppRgb555);
  147. using (var graphics = Graphics.FromImage(bitmap))
  148. {
  149. graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighSpeed;
  150. graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighSpeed;
  151. graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed;
  152. graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default;
  153. graphics.FillRectangle(Brushes.LightGray, 0, 0, bitmap.Width, bitmap.Height);
  154. this.DrawShapes(graphics);
  155. if (this.PrintSceneLabels)
  156. this.DrawLabels(graphics);
  157. graphics.Save();
  158. }
  159. return bitmap;
  160. }
  161. private void DrawShapes(Graphics graphics)
  162. {
  163. if (this.DrawMasterScenes)
  164. {
  165. foreach (var scene in this.MasterScenes)
  166. {
  167. this.DrawScene(graphics, scene);
  168. }
  169. }
  170. if (this.DrawSubScenes)
  171. {
  172. foreach (var scene in this.SubScenes)
  173. {
  174. this.DrawScene(graphics, scene);
  175. }
  176. }
  177. if (this.DrawWalkableCells)
  178. this.DrawWalkables(graphics);
  179. if (this.DrawUnwalkableCells)
  180. this.DrawUnwalkables(graphics);
  181. if (this.DrawMonsters)
  182. {
  183. foreach (var monster in this.Monsters)
  184. {
  185. this.DrawActor(monster, graphics, Brushes.Green, 7);
  186. }
  187. }
  188. if (this.DrawNPCs)
  189. {
  190. foreach (var npc in this.NPCs)
  191. {
  192. this.DrawActor(npc, graphics, Brushes.Orange, 7);
  193. }
  194. }
  195. if (this.DrawPlayers)
  196. {
  197. foreach (var player in this.Players)
  198. {
  199. this.DrawActor(player, graphics, Brushes.DarkViolet, 7);
  200. }
  201. }
  202. if(this.DrawPlayerProximityCircle)
  203. this.DrawProximityCircle(graphics);
  204. if(this.DrawPlayerProximityRectangle)
  205. this.DrawProximityRectangle(graphics);
  206. }
  207. private void DrawScene(Graphics graphics, Scene scene)
  208. {
  209. var rect = new Rectangle((int)scene.Bounds.Left, (int)scene.Bounds.Top, (int)scene.Bounds.Width, (int)scene.Bounds.Height);
  210. graphics.DrawRectangle(scene.Parent == null ? _masterScenePen : _subScenePen, rect);
  211. }
  212. private void DrawWalkables(Graphics graphics)
  213. {
  214. foreach (var cell in this.WalkableCells)
  215. {
  216. var rect = new Rectangle(new System.Drawing.Point((int)cell.Left, (int)cell.Top), new System.Drawing.Size((int)cell.Width, (int)cell.Height));
  217. if (this.FillCells)
  218. graphics.FillRectangle(_walkableBrush, rect);
  219. else
  220. graphics.DrawRectangle(_walkablePen, rect);
  221. }
  222. }
  223. private void DrawUnwalkables(Graphics graphics)
  224. {
  225. foreach (var cell in this.UnWalkableCells)
  226. {
  227. var rect = new Rectangle(new System.Drawing.Point((int)cell.Left, (int)cell.Top), new System.Drawing.Size((int)cell.Width, (int)cell.Height));
  228. if (this.FillCells)
  229. graphics.FillRectangle(_unwalkableBrush, rect);
  230. else
  231. graphics.DrawRectangle(_unwalkablePen, rect);
  232. }
  233. }
  234. private void DrawActor(Actor actor, Graphics graphics, Brush brush, int radius)
  235. {
  236. var rect = new Rectangle((int)actor.Bounds.X, (int)actor.Bounds.Y, (int)actor.Bounds.Width + radius, (int)actor.Bounds.Height + radius);
  237. graphics.FillEllipse(brush, rect);
  238. }
  239. private void DrawProximityCircle(Graphics graphics)
  240. {
  241. if (this.Player == null)
  242. return;
  243. var rect = new RectangleF(this.Player.Position.X - Actor.DefaultQueryProximityRadius,
  244. this.Player.Position.Y - Actor.DefaultQueryProximityRadius,
  245. Actor.DefaultQueryProximityRadius * 2,
  246. Actor.DefaultQueryProximityRadius * 2);
  247. graphics.DrawEllipse(this._playerProximityPen, rect);
  248. }
  249. private void DrawProximityRectangle(Graphics graphics)
  250. {
  251. if (this.Player == null)
  252. return;
  253. graphics.DrawRectangle(this._playerProximityPen,
  254. this.Player.Position.X - Actor.DefaultQueryProximityLenght/2,
  255. this.Player.Position.Y - Actor.DefaultQueryProximityLenght/2,
  256. Actor.DefaultQueryProximityLenght,
  257. Actor.DefaultQueryProximityLenght);
  258. }
  259. private void DrawLabels(Graphics graphics)
  260. {
  261. if (this.DrawMasterScenes)
  262. {
  263. foreach (var scene in this.MasterScenes)
  264. {
  265. this.DrawSceneLabel(graphics, scene);
  266. }
  267. }
  268. if (this.DrawSubScenes)
  269. {
  270. foreach (var scene in this.SubScenes)
  271. {
  272. this.DrawSceneLabel(graphics, scene);
  273. }
  274. }
  275. }
  276. private void DrawSceneLabel(Graphics graphics, Scene scene)
  277. {
  278. var stringRectangle = new RectangleF((float)scene.Bounds.Left, (float)scene.Bounds.Top, (float)scene.Bounds.Width, (float)scene.Bounds.Height);
  279. var drawFormat = new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center };
  280. if (!string.IsNullOrEmpty(scene.SceneSNO.Name))
  281. graphics.DrawString(scene.SceneSNO.Name, _sceneFont, scene.Parent == null ? Brushes.Black : Brushes.Gray, stringRectangle, drawFormat);
  282. }
  283. #endregion
  284. }
  285. }