From 1479e23ed99def7488e4c5b62d947fb42cf92595 Mon Sep 17 00:00:00 2001
From: MaxED <j.maxed@gmail.com>
Date: Mon, 25 Jan 2016 14:39:55 +0000
Subject: [PATCH] Merged changes from DB2 R2482.

---
 Source/Core/General/MapManager.cs             | 198 +++++++++++-------
 Source/Core/Plugins/Plug.cs                   |   7 +
 Source/Core/Plugins/PluginManager.cs          |   3 +-
 Source/Plugins/NodesViewer/NodesForm.cs       |   2 +-
 Source/Plugins/NodesViewer/NodesViewerMode.cs |  24 +--
 5 files changed, 132 insertions(+), 102 deletions(-)

diff --git a/Source/Core/General/MapManager.cs b/Source/Core/General/MapManager.cs
index e029e828d..4a2449bc7 100644
--- a/Source/Core/General/MapManager.cs
+++ b/Source/Core/General/MapManager.cs
@@ -634,7 +634,93 @@ namespace CodeImp.DoomBuilder
 		/// </summary>
 		public bool ExportToFile(string filepathname) 
 		{
-			return SaveMap(filepathname, SavePurpose.Testing);
+			General.Plugins.OnMapSaveBegin(SavePurpose.Testing);
+			bool result = SaveMap(filepathname, SavePurpose.Testing);
+			General.Plugins.OnMapSaveEnd(SavePurpose.Testing);
+			return result;
+		}
+
+		/// <summary>
+		/// This writes the map structures to the temporary file.
+		/// </summary>
+		private bool WriteMapToTempFile()
+		{
+			StatusInfo oldstatus = General.MainWindow.Status;
+
+			// Make a copy of the map data
+			MapSet outputset = map.Clone();
+
+			// Remove all flags from all 3D Start things
+			foreach(Thing t in outputset.Things)
+			{
+				if(t.Type == config.Start3DModeThingType)
+				{
+					// We're not using SetFlag here, this doesn't have to be undone.
+					// Please note that this is totally exceptional!
+					List<string> flagkeys = new List<string>(t.Flags.Keys);
+					foreach(string k in flagkeys) t.Flags[k] = false;
+				}
+			}
+
+			// Do we need sidedefs compression?
+			if(map.Sidedefs.Count > io.MaxSidedefs)
+			{
+				// Compress sidedefs
+				General.MainWindow.DisplayStatus(StatusType.Busy, "Compressing sidedefs...");
+				outputset.CompressSidedefs();
+
+				// Check if it still doesnt fit
+				if(outputset.Sidedefs.Count > io.MaxSidedefs)
+				{
+					// Problem! Can't save the map like this!
+					General.ShowErrorMessage("Unable to save the map: There are too many unique sidedefs!", MessageBoxButtons.OK);
+					General.MainWindow.DisplayStatus(oldstatus);
+					return false;
+				}
+			}
+
+			// Check things
+			if(map.Things.Count > io.MaxThings)
+			{
+				General.ShowErrorMessage("Unable to save the map: There are too many things!", MessageBoxButtons.OK);
+				General.MainWindow.DisplayStatus(oldstatus);
+				return false;
+			}
+
+			// Check sectors
+			if(map.Sectors.Count > io.MaxSectors)
+			{
+				General.ShowErrorMessage("Unable to save the map: There are too many sectors!", MessageBoxButtons.OK);
+				General.MainWindow.DisplayStatus(oldstatus);
+				return false;
+			}
+
+			// Check linedefs
+			if(map.Linedefs.Count > io.MaxLinedefs)
+			{
+				General.ShowErrorMessage("Unable to save the map: There are too many linedefs!", MessageBoxButtons.OK);
+				General.MainWindow.DisplayStatus(oldstatus);
+				return false;
+			}
+
+			// Check vertices
+			if(map.Vertices.Count > io.MaxVertices)
+			{
+				General.ShowErrorMessage("Unable to save the map: There are too many vertices!", MessageBoxButtons.OK);
+				General.MainWindow.DisplayStatus(oldstatus);
+				return false;
+			}
+
+			// TODO: Check for more limitations
+
+			// Write to temporary file
+			General.WriteLogLine("Writing map data structures to file...");
+			int index = Math.Max(0, tempwad.FindLumpIndex(TEMP_MAP_HEADER));
+			io.Write(outputset, TEMP_MAP_HEADER, index);
+			outputset.Dispose();
+
+			General.MainWindow.DisplayStatus(oldstatus);
+			return true;
 		}
 
 		// Initializes for an existing map
@@ -642,7 +728,6 @@ namespace CodeImp.DoomBuilder
 		{
 			string settingsfile;
 			WAD targetwad;
-			int index;
 			bool includenodes;
 
 			General.WriteLogLine("Saving map to file: " + newfilepathname);
@@ -673,82 +758,14 @@ namespace CodeImp.DoomBuilder
 			// (not when only scripts have changed)
 			if(changed) 
 			{
-				// Make a copy of the map data
-				MapSet outputset = map.Clone();
-
-				// Remove all flags from all 3D Start things
-				foreach(Thing t in outputset.Things) 
-				{
-					if(t.Type == config.Start3DModeThingType) 
-					{
-						// We're not using SetFlag here, this doesn't have to be undone.
-						// Please note that this is totally exceptional!
-						List<string> flagkeys = new List<string>(t.Flags.Keys);
-						foreach(string k in flagkeys) t.Flags[k] = false;
-					}
-				}
-
-				// Do we need sidedefs compression?
-				StatusInfo oldstatus;
-				if(map.Sidedefs.Count > io.MaxSidedefs) 
-				{
-					// Compress sidedefs
-					oldstatus = General.MainWindow.Status;
-					General.MainWindow.DisplayStatus(StatusType.Busy, "Compressing sidedefs...");
-					outputset.CompressSidedefs();
-					General.MainWindow.DisplayStatus(oldstatus);
-
-					// Check if it still doesnt fit
-					if(outputset.Sidedefs.Count > io.MaxSidedefs) 
-					{
-						// Problem! Can't save the map like this!
-						General.ShowErrorMessage("Unable to save the map: There are too many unique sidedefs!", MessageBoxButtons.OK);
-						return false;
-					}
-				}
-
-				// Check things
-				if(map.Things.Count > io.MaxThings) 
-				{
-					General.ShowErrorMessage("Unable to save the map: There are too many things!", MessageBoxButtons.OK);
-					return false;
-				}
-
-				// Check sectors
-				if(map.Sectors.Count > io.MaxSectors) 
-				{
-					General.ShowErrorMessage("Unable to save the map: There are too many sectors!", MessageBoxButtons.OK);
-					return false;
-				}
-
-				// Check linedefs
-				if(map.Linedefs.Count > io.MaxLinedefs) 
-				{
-					General.ShowErrorMessage("Unable to save the map: There are too many linedefs!", MessageBoxButtons.OK);
-					return false;
-				}
-
-				// Check vertices
-				if(map.Vertices.Count > io.MaxVertices) 
-				{
-					General.ShowErrorMessage("Unable to save the map: There are too many vertices!", MessageBoxButtons.OK);
-					return false;
-				}
-
-				// TODO: Check for more limitations
-
-				// Write to temporary file
-				General.WriteLogLine("Writing map data structures to file...");
-				index = tempwad.FindLumpIndex(TEMP_MAP_HEADER);
-				if(index == -1) index = 0;
-				io.Write(outputset, TEMP_MAP_HEADER, index);
-				outputset.Dispose();
+				// Write the current map structures to the temp file
+				if(!WriteMapToTempFile()) return false;
 
 				// Get the corresponding nodebuilder
 				string nodebuildername = (purpose == SavePurpose.Testing) ? configinfo.NodebuilderTest : configinfo.NodebuilderSave;
 
 				// Build the nodes
-				oldstatus = General.MainWindow.Status;
+				StatusInfo oldstatus = General.MainWindow.Status;
 				General.MainWindow.DisplayStatus(StatusType.Busy, "Building map nodes...");
 				includenodes = (!string.IsNullOrEmpty(nodebuildername) && BuildNodes(nodebuildername, true));
 				General.MainWindow.DisplayStatus(oldstatus);
@@ -896,7 +913,7 @@ namespace CodeImp.DoomBuilder
 					targetwad = new WAD(newfilepathname);
 				}
 			} 
-			catch (IOException) 
+			catch(IOException) 
 			{
 				General.ShowErrorMessage("IO Error while writing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
 				if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up
@@ -904,7 +921,7 @@ namespace CodeImp.DoomBuilder
 				General.WriteLogLine("Map saving failed");
 				return false;
 			} 
-			catch (UnauthorizedAccessException) 
+			catch(UnauthorizedAccessException) 
 			{
 				General.ShowErrorMessage("Error while accessing target file: " + newfilepathname + ". Please make sure the location is accessible and not in use by another program.", MessageBoxButtons.OK);
 				if(!string.IsNullOrEmpty(origwadfile) && File.Exists(origwadfile)) File.Delete(origwadfile); //mxd. Clean-up
@@ -924,7 +941,7 @@ namespace CodeImp.DoomBuilder
 					General.WriteLogLine("Changing map name from '" + options.PreviousName + "' to '" + options.CurrentName + "'");
 
 					// Find the map header in target
-					index = targetwad.FindLumpIndex(options.PreviousName);
+					int index = targetwad.FindLumpIndex(options.PreviousName);
 					if(index > -1) 
 					{
 						// Rename the map lump name
@@ -967,7 +984,7 @@ namespace CodeImp.DoomBuilder
 					settingsfile = newfilepathname.Substring(0, newfilepathname.Length - 4) + ".dbs";
 					options.WriteConfiguration(settingsfile);
 				} 
-				catch (Exception e) 
+				catch(Exception e) 
 				{
 					// Warning only
 					General.ErrorLogger.Add(ErrorType.Warning, "Could not write the map settings configuration file. " + e.GetType().Name + ": " + e.Message);
@@ -1056,6 +1073,30 @@ namespace CodeImp.DoomBuilder
 
 		#region ================== Nodebuild
 
+		/// <summary>
+		/// This stores the current structures in memory to the temporary file and rebuilds the nodes.
+		/// The 'nodebuildername' must be a valid nodebuilder configuration profile.
+		/// Returns True on success, False when failed.
+		/// </summary>
+		public bool RebuildNodes(string nodebuildername, bool failaswarning)
+		{
+			bool result;
+
+			// Write the current map structures to the temp file
+			if(!WriteMapToTempFile()) return false;
+
+			// Build the nodes
+			StatusInfo oldstatus = General.MainWindow.Status;
+			General.MainWindow.DisplayStatus(StatusType.Busy, "Building map nodes...");
+			if(!string.IsNullOrEmpty(nodebuildername))
+				result = BuildNodes(nodebuildername, failaswarning);
+			else
+				result = false;
+			General.MainWindow.DisplayStatus(oldstatus);
+
+			return result;
+		}
+
 		// This builds the nodes in the temproary file with the given configuration name
 		private bool BuildNodes(string nodebuildername, bool failaswarning) 
 		{
@@ -1178,6 +1219,9 @@ namespace CodeImp.DoomBuilder
 				// Clean up
 				compiler.Dispose();
 
+				// Let the plugins know
+				if(lumpscomplete) General.Plugins.OnMapNodesRebuilt();
+
 				// Return result
 				return lumpscomplete;
 			}
diff --git a/Source/Core/Plugins/Plug.cs b/Source/Core/Plugins/Plug.cs
index 9edf7b989..cbffaf5c8 100644
--- a/Source/Core/Plugins/Plug.cs
+++ b/Source/Core/Plugins/Plug.cs
@@ -308,6 +308,13 @@ namespace CodeImp.DoomBuilder.Plugins
 		/// </summary>
 		public virtual void OnEditAccept() { }
 
+		/// <summary>
+		/// Called just after the nodes have been (re)built. This allows a plugin to intervene with
+		/// the nodebuilder output using GetLumpData and SetLumpData. If the map is being saved, this
+		/// is called after the nodes are rebuilt and just before they are stored in the target file.
+		/// </summary>
+		public virtual void OnMapNodesRebuilt() { }
+
 		// Interface events
 		public virtual void OnEditMouseClick(MouseEventArgs e) { }
 		public virtual void OnEditMouseDoubleClick(MouseEventArgs e) { }
diff --git a/Source/Core/Plugins/PluginManager.cs b/Source/Core/Plugins/PluginManager.cs
index d89052926..2e2b41a61 100644
--- a/Source/Core/Plugins/PluginManager.cs
+++ b/Source/Core/Plugins/PluginManager.cs
@@ -301,8 +301,9 @@ namespace CodeImp.DoomBuilder.Plugins
 		public void OnEditRedrawDisplayBegin() { foreach(Plugin p in plugins) p.Plug.OnEditRedrawDisplayBegin(); }
 		public void OnEditRedrawDisplayEnd() { foreach(Plugin p in plugins) p.Plug.OnEditRedrawDisplayEnd(); }
 		public void OnPresentDisplayBegin() { foreach(Plugin p in plugins) p.Plug.OnPresentDisplayBegin(); }
+		public void OnMapNodesRebuilt() { foreach(Plugin p in plugins) p.Plug.OnMapNodesRebuilt(); }
 
-		//mxd. Hilight events
+		//mxd. Highlight events
 		public void OnHighlightSector(Sector s) { foreach(Plugin p in plugins) p.Plug.OnHighlightSector(s); }
 		public void OnHighlightLinedef(Linedef l) { foreach(Plugin p in plugins) p.Plug.OnHighlightLinedef(l); }
 		public void OnHighlightThing(Thing t) { foreach(Plugin p in plugins) p.Plug.OnHighlightThing(t); }
diff --git a/Source/Plugins/NodesViewer/NodesForm.cs b/Source/Plugins/NodesViewer/NodesForm.cs
index 641a5beb3..c42d8f42f 100644
--- a/Source/Plugins/NodesViewer/NodesForm.cs
+++ b/Source/Plugins/NodesViewer/NodesForm.cs
@@ -160,7 +160,7 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
 		// (Re)build the nodes
 		private void buildnodesbutton_Click(object sender, EventArgs e)
 		{
-			mode.BuildNodes();
+			General.Map.RebuildNodes(General.Map.ConfigSettings.NodebuilderSave, true);
 
 			// Restart the mode so that the new structures are loaded in.
 			// This will automatically close and re-open this window.
diff --git a/Source/Plugins/NodesViewer/NodesViewerMode.cs b/Source/Plugins/NodesViewer/NodesViewerMode.cs
index 5d4a61072..c99a18a17 100644
--- a/Source/Plugins/NodesViewer/NodesViewerMode.cs
+++ b/Source/Plugins/NodesViewer/NodesViewerMode.cs
@@ -85,20 +85,6 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
 
 		#region ================== Methods
 
-		/// <summary>
-		/// This (re)builds the nodes for the whole map.
-		/// </summary>
-		public void BuildNodes()
-		{
-			// There is no API available to do this directly, but we export the map which will
-			// cause the DB core to build the nodes (with testing parameters)
-			General.Interface.DisplayStatus(StatusType.Busy, "Building map nodes...");
-			string tempfile = BuilderPlug.MakeTempFilename(".wad");
-			General.Map.IsChanged = true;
-			General.Map.ExportToFile(tempfile);
-			File.Delete(tempfile);
-		}
-
 		/// <summary>
 		/// This loads all nodes structures data from the lumps
 		/// </summary>
@@ -810,14 +796,6 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
 			Cursor.Current = Cursors.WaitCursor;
 			base.OnEngage();
 
-			//mxd. General.Map.ExportToFile in BuildNodes() won't do the trick if the map was never saved
-			if(string.IsNullOrEmpty(General.Map.FilePathName)) 
-			{
-				MessageBox.Show("Please save the map before running Nodes Viewer mode.", "Nodes Viewer mode", MessageBoxButtons.OK, MessageBoxIcon.Error);
-				General.Editing.CancelMode();
-				return;
-			}
-
 			//mxd
 			bool haveNodes = General.Map.LumpExists("NODES");
 			bool haveZnodes = General.Map.LumpExists("ZNODES");
@@ -828,7 +806,7 @@ namespace CodeImp.DoomBuilder.Plugins.NodesViewer
 			if(General.Map.IsChanged || !(haveZnodes || (haveNodes || haveSectors || haveSegs || haveVerts)))
 			{
 				// We need to build the nodes!
-				BuildNodes();
+				if(!General.Map.RebuildNodes(General.Map.ConfigSettings.NodebuilderSave, true)) return;
 
 				//mxd. Update nodes availability
 				haveNodes = General.Map.LumpExists("NODES");
-- 
GitLab