diff --git a/Build/Updater.exe b/Build/Updater.exe
index 4ad1e3bb05cf3121b314ba391730189578d94c47..d28f4c9bcdeff89fff65dbe83b674a2ca482ab2a 100644
Binary files a/Build/Updater.exe and b/Build/Updater.exe differ
diff --git a/Source/Tools/Tools.sln b/Source/Tools/Tools.sln
new file mode 100644
index 0000000000000000000000000000000000000000..9c384d7604503d20090dc638247d9c5acc867e85
--- /dev/null
+++ b/Source/Tools/Tools.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 10.00
+# Visual Studio 2008
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Updater", "Updater\Updater.csproj", "{2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+EndGlobal
diff --git a/Source/Tools/Updater/Helpers/EmbeddedAssembly.cs b/Source/Tools/Updater/Helpers/EmbeddedAssembly.cs
new file mode 100644
index 0000000000000000000000000000000000000000..43d3d44227d5f2db1dd19e14370418aa7f17e607
--- /dev/null
+++ b/Source/Tools/Updater/Helpers/EmbeddedAssembly.cs
@@ -0,0 +1,75 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Security.Cryptography;
+
+//Source: http://www.codeproject.com/Articles/528178/Load-DLL-From-Embedded-Resource
+namespace mxd.GZDBUpdater
+{
+	public static class EmbeddedAssembly
+	{
+		private static Dictionary<string, Assembly> dic = new Dictionary<string, Assembly>();
+
+		public static void Load(string embeddedResource, string filename)
+		{
+			byte[] ba;
+			Assembly asm;
+			Assembly curAsm = Assembly.GetExecutingAssembly();
+
+			using(Stream stm = curAsm.GetManifestResourceStream(embeddedResource))
+			{
+				// Either the file is not existed or it is not mark as embedded resource
+				if(stm == null) throw new Exception(embeddedResource + " is not found in Embedded Resources.");
+
+				// Get byte[] from the file from embedded resource
+				ba = new byte[(int)stm.Length];
+				stm.Read(ba, 0, (int)stm.Length);
+				try
+				{
+					asm = Assembly.Load(ba);
+
+					// Add the assembly/dll into dictionary
+					dic.Add(asm.FullName, asm);
+					return;
+				}
+				catch
+				{
+					// Purposely do nothing
+					// Unmanaged dll or assembly cannot be loaded directly from byte[]
+					// Let the process fall through for next part
+				}
+			}
+
+			bool fileOk = false;
+			string tempFile;
+
+			using(SHA1CryptoServiceProvider sha1 = new SHA1CryptoServiceProvider())
+			{
+				string fileHash = BitConverter.ToString(sha1.ComputeHash(ba)).Replace("-", string.Empty);
+				tempFile = Path.GetTempPath() + filename;
+
+				if(File.Exists(tempFile))
+				{
+					byte[] bb = File.ReadAllBytes(tempFile);
+					string fileHash2 = BitConverter.ToString(sha1.ComputeHash(bb)).Replace("-", string.Empty);
+					fileOk = (fileHash == fileHash2);
+				}
+			}
+
+			if(!fileOk)
+			{
+				File.WriteAllBytes(tempFile, ba);
+			}
+
+			asm = Assembly.LoadFile(tempFile);
+			dic.Add(asm.FullName, asm);
+		}
+
+		public static Assembly Get(string assemblyFullName)
+		{
+			if(dic == null || dic.Count == 0) return null;
+			return (dic.ContainsKey(assemblyFullName) ? dic[assemblyFullName] : null);
+		}
+	}
+}
diff --git a/Source/Tools/Updater/Helpers/TaskbarProgress.cs b/Source/Tools/Updater/Helpers/TaskbarProgress.cs
new file mode 100644
index 0000000000000000000000000000000000000000..bb53ee35e61b276dca54ac15bcfc2ef4204cc88a
--- /dev/null
+++ b/Source/Tools/Updater/Helpers/TaskbarProgress.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace mxd.GZDBUpdater
+{
+	// http://stackoverflow.com/questions/1295890/windows-7-progress-bar-in-taskbar-in-c
+	public static class TaskbarProgress
+	{
+		public enum TaskbarStates
+		{
+			NoProgress = 0,
+			Indeterminate = 0x1,
+			Normal = 0x2,
+			Error = 0x4,
+			Paused = 0x8
+		}
+
+		[ComImportAttribute()]
+		[GuidAttribute("ea1afb91-9e28-4b86-90e9-9e9f8a5eefaf")]
+		[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
+		private interface ITaskbarList3
+		{
+			// ITaskbarList
+			[PreserveSig]
+			void HrInit();
+			[PreserveSig]
+			void AddTab(IntPtr hwnd);
+			[PreserveSig]
+			void DeleteTab(IntPtr hwnd);
+			[PreserveSig]
+			void ActivateTab(IntPtr hwnd);
+			[PreserveSig]
+			void SetActiveAlt(IntPtr hwnd);
+
+			// ITaskbarList2
+			[PreserveSig]
+			void MarkFullscreenWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.Bool)] bool fFullscreen);
+
+			// ITaskbarList3
+			[PreserveSig]
+			void SetProgressValue(IntPtr hwnd, UInt64 ullCompleted, UInt64 ullTotal);
+			[PreserveSig]
+			void SetProgressState(IntPtr hwnd, TaskbarStates state);
+		}
+
+		[GuidAttribute("56FDF344-FD6D-11d0-958A-006097C9A090")]
+		[ClassInterfaceAttribute(ClassInterfaceType.None)]
+		[ComImportAttribute()]
+		private class TaskbarInstance
+		{
+		}
+
+		private static ITaskbarList3 taskbarInstance = (ITaskbarList3)new TaskbarInstance();
+		private static bool taskbarSupported = Environment.OSVersion.Version >= new Version(6, 1);
+
+		public static void SetState(IntPtr windowHandle, TaskbarStates taskbarState)
+		{
+			if(taskbarSupported) taskbarInstance.SetProgressState(windowHandle, taskbarState);
+		}
+
+		public static void SetValue(IntPtr windowHandle, double progressValue, double progressMax)
+		{
+			if(taskbarSupported) taskbarInstance.SetProgressValue(windowHandle, (ulong)progressValue, (ulong)progressMax);
+		}
+	}
+}
diff --git a/Source/Tools/Updater/Helpers/Webdata.cs b/Source/Tools/Updater/Helpers/Webdata.cs
new file mode 100644
index 0000000000000000000000000000000000000000..cb4ac7b98782e89879a1c340f3ce838cac118f4a
--- /dev/null
+++ b/Source/Tools/Updater/Helpers/Webdata.cs
@@ -0,0 +1,104 @@
+using System;
+using System.Net;
+using System.IO;
+
+namespace mxd.GZDBUpdater
+{
+    public delegate void BytesDownloadedEventHandler(ByteArgs e);
+
+    public class ByteArgs : EventArgs
+    {
+	    public int Downloaded;
+	    public int Total;
+    }
+
+    static class Webdata
+    {
+        public static event BytesDownloadedEventHandler BytesDownloaded;
+
+        public static bool SaveWebFile(string url, string file, string targetFolder)
+        {
+            try
+            {
+	            MemoryStream memoryStream = DownloadWebFile(Path.Combine(url, file));
+	            if(memoryStream == null) return false;
+
+                //Convert the downloaded stream to a byte array
+                byte[] downloadedData = memoryStream.ToArray();
+
+                //Release resources
+                memoryStream.Close();
+
+                //Write bytes to the specified file
+                FileStream newFile = new FileStream(targetFolder + file, FileMode.Create);
+                newFile.Write(downloadedData, 0, downloadedData.Length);
+                newFile.Close();
+
+                return !MainForm.AppClosing;
+            }
+            catch(Exception e)
+            {
+                //We may not be connected to the internet
+                //Or the URL may be incorrect
+				MainForm.ErrorDescription = "Failed to download the update...\n" + e.Message;
+                return false;
+            }
+        }
+
+		public static MemoryStream DownloadWebFile(string url)
+		{
+			//open a data stream from the supplied URL
+			WebRequest webReq = WebRequest.Create(url);
+			WebResponse webResponse = webReq.GetResponse();
+			Stream dataStream = webResponse.GetResponseStream();
+
+			//Download the data in chuncks
+			byte[] dataBuffer = new byte[1024];
+
+			//Get the total size of the download
+			int dataLength = (int)webResponse.ContentLength;
+
+			//lets declare our downloaded bytes event args
+			ByteArgs byteArgs = new ByteArgs();
+
+			byteArgs.Downloaded = 0;
+			byteArgs.Total = dataLength;
+
+			//we need to test for a null as if an event is not consumed we will get an exception
+			if(BytesDownloaded != null) BytesDownloaded(byteArgs);
+
+			//Download the data
+			MemoryStream memoryStream = new MemoryStream();
+			while(!MainForm.AppClosing)
+			{
+				//Let's try and read the data
+				int bytesFromStream = dataStream.Read(dataBuffer, 0, dataBuffer.Length);
+				if(bytesFromStream == 0)
+				{
+					byteArgs.Downloaded = dataLength;
+					byteArgs.Total = dataLength;
+					if(BytesDownloaded != null) BytesDownloaded(byteArgs);
+
+					//Download complete
+					break;
+				}
+				else 
+				{
+					//Write the downloaded data
+					memoryStream.Write(dataBuffer, 0, bytesFromStream);
+
+					byteArgs.Downloaded += bytesFromStream;
+					byteArgs.Total = dataLength;
+					if(BytesDownloaded != null) BytesDownloaded(byteArgs);
+				}
+			}
+
+			//Release resources
+			dataStream.Close();
+
+			// Rewind and return the stream
+			memoryStream.Position = 0;
+			return (MainForm.AppClosing ? null : memoryStream);
+		}
+    }
+}
diff --git a/Source/Tools/Updater/MainForm.Designer.cs b/Source/Tools/Updater/MainForm.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..a39ac6f8be66052022e42b003cdb739ae5ea3967
--- /dev/null
+++ b/Source/Tools/Updater/MainForm.Designer.cs
@@ -0,0 +1,89 @@
+namespace mxd.GZDBUpdater
+{
+    partial class MainForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+			this.progressbar = new System.Windows.Forms.ProgressBar();
+			this.label1 = new System.Windows.Forms.Label();
+			this.cancel = new System.Windows.Forms.Button();
+			this.SuspendLayout();
+			// 
+			// progressBar1
+			// 
+			this.progressbar.Location = new System.Drawing.Point(10, 43);
+			this.progressbar.Name = "progressbar";
+			this.progressbar.Size = new System.Drawing.Size(230, 23);
+			this.progressbar.TabIndex = 0;
+			// 
+			// line1
+			// 
+			this.label1.AutoSize = true;
+			this.label1.Location = new System.Drawing.Point(7, 17);
+			this.label1.Name = "label1";
+			this.label1.Size = new System.Drawing.Size(64, 13);
+			this.label1.TabIndex = 3;
+			this.label1.Text = " Initializing...";
+			// 
+			// cancel
+			// 
+			this.cancel.Location = new System.Drawing.Point(246, 43);
+			this.cancel.Name = "cancel";
+			this.cancel.Size = new System.Drawing.Size(75, 23);
+			this.cancel.TabIndex = 4;
+			this.cancel.Text = "Cancel";
+			this.cancel.UseVisualStyleBackColor = true;
+			this.cancel.Click += new System.EventHandler(this.cancel_Click);
+			// 
+			// Updater
+			// 
+			this.AutoScaleDimensions = new System.Drawing.SizeF(96F, 96F);
+			this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi;
+			this.ClientSize = new System.Drawing.Size(333, 76);
+			this.Controls.Add(this.cancel);
+			this.Controls.Add(this.label1);
+			this.Controls.Add(this.progressbar);
+			this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog;
+			this.MaximizeBox = false;
+			this.Name = "MainForm";
+			this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+			this.Text = "GZDoom Builder Updater";
+			this.Load += new System.EventHandler(this.MainForm_Load);
+			this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.MainForm_FormClosing);
+			this.ResumeLayout(false);
+			this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.ProgressBar progressbar;
+		private System.Windows.Forms.Label label1;
+		private System.Windows.Forms.Button cancel;
+    }
+}
+
diff --git a/Source/Tools/Updater/MainForm.cs b/Source/Tools/Updater/MainForm.cs
new file mode 100644
index 0000000000000000000000000000000000000000..8ba570179328520b1171d5929c309e9886933b30
--- /dev/null
+++ b/Source/Tools/Updater/MainForm.cs
@@ -0,0 +1,474 @@
+#region ======================== Namespaces
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Reflection;
+using System.Windows.Forms;
+using System.IO;
+using System.Diagnostics;
+using System.Threading;
+using SharpCompress.Archive;
+using SharpCompress.Common;
+using SharpCompress.Reader;
+using System.Security.AccessControl;
+using System.Security.Principal;
+
+#endregion
+
+namespace mxd.GZDBUpdater
+{
+    public partial class MainForm : Form
+	{
+		#region ======================== Variables
+
+		private string processToEnd = string.Empty;
+		private string downloadFile = string.Empty;
+		private const string revisionwildcard = "[REVNUM]";
+		private string URL = string.Empty;
+        private readonly string updateFolder = Application.StartupPath + @"\_update\";
+		private string appFileName = string.Empty;
+	    private static BackgroundWorker worker;
+	    private static bool appclosing;
+	    private static MainForm me;
+	    private const string ERROR_TITLE = "Updater";
+
+		#endregion
+
+		#region ======================== Delegates
+
+		private delegate void SetLabelCallback(Label label, string text);
+		private delegate void UpdateProgressBarCallback(ByteArgs args, int step, int totalsteps);
+		private delegate void CloseDelegate();
+
+		#endregion
+
+		#region ======================== Properties
+
+		public static string ErrorDescription;
+	    public static bool AppClosing { get { return appclosing; } }
+
+		#endregion
+
+		#region ======================== Constructor
+
+		public MainForm()
+        {
+            if(!CheckPremissions(Application.StartupPath))
+            {
+                ErrorDescription = "Update failed: your account does not have write access to the destination folder \"" + Application.StartupPath + "\"";
+                InvokeClose();
+            }
+            else if(!File.Exists("Updater.ini"))
+			{
+				ErrorDescription = "Unable to locate 'Updater.ini'...";
+				InvokeClose();
+			}
+            else if(!LoadConfig("Updater.ini"))
+			{
+				InvokeClose();
+			}
+    		else
+			{
+				me = this;
+				InitializeComponent();
+			}
+		}
+
+		#endregion
+
+		#region ======================== Updater thread
+
+	    private void BackgroundWorker(object sender, DoWorkEventArgs e)
+        {
+			UpdateLabel(label1, "1/6: Checking revisions...");
+			if(!UpdateRequired())
+			{
+				e.Cancel = true;
+				return;
+			}
+            PreDownload();
+
+			UpdateLabel(label1, "2/6: Downloading Update...");
+			Webdata.BytesDownloaded += WebdataOnBytesDownloaded;
+            if(!Webdata.SaveWebFile(URL, downloadFile, updateFolder))
+            {
+                e.Cancel = true;
+				Webdata.BytesDownloaded -= WebdataOnBytesDownloaded;
+				return;
+            }
+
+			// Check if the editor is running...
+			try
+			{
+				Process[] processes = Process.GetProcesses();
+				List<Process> toclose = new List<Process>();
+				
+				// Gather all running editor processes...
+				foreach(Process process in processes)
+				{
+					if(process.ProcessName == processToEnd 
+						&& Path.GetDirectoryName(process.MainModule.FileName) == Application.StartupPath)
+					{
+						toclose.Add(process);
+					}
+				}
+
+				// Close them
+				if(toclose.Count > 0)
+				{
+					TaskbarProgress.SetState(this.Handle, TaskbarProgress.TaskbarStates.Paused);
+					if(MessageBox.Show(this, "The editor needs to be closed.\n\nPress OK to close it and proceed with update.\nPress Cancel to cancel update.",
+						ERROR_TITLE, MessageBoxButtons.OKCancel) == DialogResult.OK)
+					{
+						UpdateLabel(label1, "3/6: Stopping " + processToEnd);
+						Thread.Sleep(500);
+
+						foreach(Process p in toclose)
+						{
+							if(p != null) p.Kill();
+						}
+					}
+					else
+					{
+						e.Cancel = true;
+						return;
+					}
+				}
+			}
+			catch(Exception ex)
+			{
+				ErrorDescription = "Failed to stop the main process...\n" + ex.Message;
+				e.Cancel = true;
+				return;
+			}
+
+			UpdateLabel(label1, "4/6: Decompressing package...");
+            Thread.Sleep(500);
+			if(!Unpack(updateFolder + downloadFile, Application.StartupPath))
+			{
+				e.Cancel = true;
+				return;
+			}
+
+			UpdateLabel(label1, "5/6: Moving files...");
+            Thread.Sleep(500);
+            MoveFiles();
+            
+			UpdateLabel(label1, "6/6: Wrapping up...");
+            Thread.Sleep(500);
+			PostDownload();
+		}
+
+	    private static void StopBackgroundWorker()
+		{
+			if(worker != null && !worker.CancellationPending)
+			{
+				me.UpdateLabel(me.label1, "Stopping Background Thread...");
+				worker.CancelAsync();
+				while(worker.IsBusy) Application.DoEvents();
+			}
+		}
+
+		private void WorkerOnRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+		{
+			InvokeClose();
+		}
+
+		#endregion
+
+		#region ======================== Methods
+
+		private void UpdateLabel(Label label, string text)
+		{
+			if(label.InvokeRequired)
+			{
+				SetLabelCallback d = UpdateLabel;
+				label.Invoke(d, new object[] { label, text });
+			}
+			else
+			{
+				label.Text = text;
+				label.Refresh();
+				Invalidate();
+			}
+		}
+
+		private void InvokeClose()
+		{
+			if(this.Disposing || this.IsDisposed) return;
+			if(this.InvokeRequired)
+			{
+				CloseDelegate d = Close;
+				this.Invoke(d);
+			}
+			else
+			{
+				if(!appclosing && !string.IsNullOrEmpty(ErrorDescription))
+				{
+					if(!string.IsNullOrEmpty(URL))
+					{
+						ErrorDescription += Environment.NewLine + Environment.NewLine + "Would you like to download the update manually?";
+						TaskbarProgress.SetState(this.Handle, TaskbarProgress.TaskbarStates.Error);
+						if(MessageBox.Show(this, ErrorDescription, ERROR_TITLE, MessageBoxButtons.YesNo) == DialogResult.Yes)
+							Process.Start(URL);
+					}
+					else
+					{
+						MessageBox.Show(this, ErrorDescription, ERROR_TITLE, MessageBoxButtons.OK);
+					}
+				}
+
+				WrapUp();
+				Close();
+			}
+		}
+		
+		private bool UpdateRequired()
+		{
+			// Get local revision number
+			int localrev = -1;
+			if(File.Exists(appFileName))
+			{
+				var info = FileVersionInfo.GetVersionInfo(appFileName);
+				localrev = info.ProductPrivatePart;
+			}
+			
+			// Get remote revision number
+			int remoterev;
+			using(MemoryStream stream = Webdata.DownloadWebFile(Path.Combine(URL, "Version.txt")))
+			{
+				if(stream == null)
+				{
+					ErrorDescription = "Failed to retrieve remote revision info.";
+					return false;
+				}
+
+				string s;
+				using(StreamReader reader = new StreamReader(stream))
+				{
+					s = reader.ReadToEnd();
+				}
+
+				if(!int.TryParse(s, out remoterev))
+				{
+					ErrorDescription = "Failed to retrieve remote revision number.";
+					return false;
+				}
+			}
+
+			// Replace wildcard with remoterev
+			downloadFile = downloadFile.Replace(revisionwildcard, remoterev.ToString());
+
+			if(remoterev > 0 && remoterev <= localrev)
+			{
+				URL = string.Empty;
+				ErrorDescription = "Your version is up to date!";
+			}
+			return remoterev > localrev;
+		}
+
+		private bool LoadConfig(string filename)
+		{
+			string[] lines = File.ReadAllLines(filename);
+			foreach (string line in lines)
+			{
+				if(line.StartsWith("URL"))
+				{
+					URL = line.Substring(3).Trim();
+				} 
+				else if(line.StartsWith("FileName"))
+				{
+					appFileName = line.Substring(8).Trim();
+					processToEnd = Path.GetFileNameWithoutExtension(appFileName);
+				}
+				else if(line.StartsWith("UpdateName"))
+				{
+					downloadFile = line.Substring(10).Trim();
+				}
+			}
+
+			// Sanity cheks
+			if(string.IsNullOrEmpty(URL))
+			{
+				ErrorDescription = "URL is not specified in " + filename + "!";
+				return false;
+			}
+
+			if(string.IsNullOrEmpty(appFileName) || string.IsNullOrEmpty(processToEnd))
+			{
+				ErrorDescription = "FileName is not specified in " + filename + "!";
+				return false;
+			}
+
+			if(string.IsNullOrEmpty(downloadFile) || !downloadFile.Contains(revisionwildcard))
+			{
+				ErrorDescription = "UpdateName is invalid or not specified in " + filename + "!";
+				return false;
+			}
+
+			return true;
+		}
+
+        private bool Unpack(string file, string unZipTo)
+        {
+            try
+            {
+				using(IArchive arc = ArchiveFactory.Open(file))
+				{
+					if(!arc.IsComplete)
+					{
+						ErrorDescription = "Update failed: downloaded file is not complete...";
+						return false;
+					}
+
+					IReader reader = arc.ExtractAllEntries();
+
+					// Get number of files...
+					int curentry = 0;
+					int totalentries = 0;
+					foreach(var entry in arc.Entries) totalentries++;
+
+					string ourname = Path.GetFileName(Process.GetCurrentProcess().MainModule.FileName);
+
+					// Unpack all
+					while(reader.MoveToNextEntry())
+					{
+						if(appclosing) break;
+						if(reader.Entry.IsDirectory || Path.GetFileName(reader.Entry.Key) == ourname) continue; // Don't try to overrite ourselves...
+						reader.WriteEntryToDirectory(unZipTo, ExtractOptions.ExtractFullPath | ExtractOptions.Overwrite);
+						UpdateProgressBar(new ByteArgs { Downloaded = curentry++, Total = totalentries }, 1, 2);
+					}
+				}
+            } 
+			catch(Exception e) 
+			{ 
+				ErrorDescription = "Update failed: failed to unpack the update...\n" + e.Message;
+				return false;
+			}
+
+	        return true;
+        }
+
+        private static bool CheckPremissions(string path)
+        {
+            try
+            {
+                DirectoryInfo di = new DirectoryInfo(path);
+                DirectorySecurity acl = di.GetAccessControl();
+                AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));
+
+                WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
+                WindowsPrincipal principal = new WindowsPrincipal(currentUser);
+                foreach(AuthorizationRule rule in rules)
+                {
+                    FileSystemAccessRule fsAccessRule = rule as FileSystemAccessRule;
+                    if(fsAccessRule == null) continue;
+
+                    if((fsAccessRule.FileSystemRights & FileSystemRights.WriteData) > 0)
+                    {
+                        NTAccount ntAccount = rule.IdentityReference as NTAccount;
+                        if(ntAccount == null) continue;
+                        if(principal.IsInRole(ntAccount.Value)) return true;
+                    }
+                }
+            }
+            catch(UnauthorizedAccessException) { }
+
+            return false;
+        }
+
+	    private void PreDownload()
+        {
+            if(!Directory.Exists(updateFolder)) Directory.CreateDirectory(updateFolder);
+        }
+
+        private void PostDownload()
+        {
+            if(!File.Exists(appFileName))
+            {
+	            ErrorDescription = "Unable to located updated executable ('" + appFileName + "')";
+				return;
+            }
+
+			if(appclosing) return;
+			Process.Start(new ProcessStartInfo { FileName = appFileName });
+        }
+
+        private void WrapUp()
+        {
+			if(Directory.Exists(updateFolder)) Directory.Delete(updateFolder, true);
+        }
+
+        private void MoveFiles()
+        {
+			DirectoryInfo di = new DirectoryInfo(updateFolder);
+            FileInfo[] files = di.GetFiles();
+
+            foreach (FileInfo fi in files)
+            {
+				if(fi.Name != downloadFile) File.Copy(updateFolder + fi.Name, Application.StartupPath + fi.Name, true);
+            }
+        }
+
+		private void UpdateProgressBar(ByteArgs e, int step, int totalsteps)
+        {
+			if(progressbar.InvokeRequired)
+			{
+				UpdateProgressBarCallback d = UpdateProgressBar;
+				progressbar.Invoke(d, new object[] { e, step, totalsteps });
+			} 
+			else 
+			{
+				int stepsize = (int)Math.Round((float)progressbar.Maximum / totalsteps);
+				float ratio = (float)e.Downloaded / e.Total;
+				int val = (int)Math.Floor(stepsize * step + stepsize * ratio);
+
+				if(val <= progressbar.Maximum)
+				{
+					progressbar.Value = val;
+					TaskbarProgress.SetValue(this.Handle, progressbar.Value, progressbar.Maximum);
+				}
+				progressbar.Refresh();
+				Invalidate();
+			}
+		}
+
+		#endregion
+
+		#region ======================== Events
+
+		private void MainForm_Load(object sender, EventArgs e)
+		{
+			Version version = Assembly.GetEntryAssembly().GetName().Version;
+			this.Text += " v" + version.Major + "." + version.Minor;
+
+			worker = new BackgroundWorker();
+			worker.DoWork += BackgroundWorker;
+			worker.RunWorkerCompleted += WorkerOnRunWorkerCompleted;
+			worker.WorkerSupportsCancellation = true;
+			worker.RunWorkerAsync();
+		}
+
+		private void cancel_Click(object sender, EventArgs e)
+		{
+			ErrorDescription = string.Empty;
+			appclosing = true;
+			StopBackgroundWorker();
+			InvokeClose();
+		}
+
+		private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
+		{
+			appclosing = true;
+			StopBackgroundWorker();
+		}
+
+		private void WebdataOnBytesDownloaded(ByteArgs ba)
+		{
+			UpdateProgressBar(ba, 0, 2);
+		}
+
+		#endregion
+	}
+}
\ No newline at end of file
diff --git a/Source/Tools/Updater/MainForm.resx b/Source/Tools/Updater/MainForm.resx
new file mode 100644
index 0000000000000000000000000000000000000000..ff31a6db56e23b5a334f34387830ba5b4bd33eb8
--- /dev/null
+++ b/Source/Tools/Updater/MainForm.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/Source/Tools/Updater/Program.cs b/Source/Tools/Updater/Program.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6b5693a522b2815dc46eb49624734379f73f5141
--- /dev/null
+++ b/Source/Tools/Updater/Program.cs
@@ -0,0 +1,29 @@
+using System;
+using System.Reflection;
+using System.Windows.Forms;
+
+namespace mxd.GZDBUpdater
+{
+    static class Program
+    {
+        /// <summary>
+        /// The main entry point for the application.
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+			EmbeddedAssembly.Load("mxd.GZDBUpdater.Resources.SharpCompress.dll", "SharpCompress.dll");
+			AppDomain.CurrentDomain.AssemblyResolve += AssemblyResolve;
+
+			Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+			MainForm form = new MainForm();
+			if(!form.IsDisposed) Application.Run(form);
+        }
+
+	    private static Assembly AssemblyResolve(object sender, ResolveEventArgs args)
+		{
+			return EmbeddedAssembly.Get(args.Name);
+		}
+    }
+}
\ No newline at end of file
diff --git a/Source/Tools/Updater/Properties/AssemblyInfo.cs b/Source/Tools/Updater/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000000000000000000000000000000000..14f97f67131f27ad47130e54cc7c08683447aae0
--- /dev/null
+++ b/Source/Tools/Updater/Properties/AssemblyInfo.cs
@@ -0,0 +1,33 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following 
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("GZDoom Builder Updater")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("GZDoom Builder Updater")]
+[assembly: AssemblyCopyright("Copyright © MaxED 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible 
+// to COM components.  If you need to access a type in this assembly from 
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("cc4d2cfe-28a3-46e9-8dc3-83e551752985")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version 
+//      Build Number
+//      Revision
+//
+[assembly: AssemblyVersion("1.1.0.0")]
+[assembly: AssemblyFileVersion("1.1.0.0")]
diff --git a/Source/Tools/Updater/Properties/Resources.Designer.cs b/Source/Tools/Updater/Properties/Resources.Designer.cs
new file mode 100644
index 0000000000000000000000000000000000000000..7a6ddd996192e9c6defd9eaf3fa56d088a565ecc
--- /dev/null
+++ b/Source/Tools/Updater/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:2.0.50727.5466
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace mxd.GZDBUpdater.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("mxd.GZDBUpdater.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+    }
+}
diff --git a/Source/Tools/Updater/Properties/Resources.resx b/Source/Tools/Updater/Properties/Resources.resx
new file mode 100644
index 0000000000000000000000000000000000000000..5ea0895e324fa7a86681adc56938bad2f2367ba0
--- /dev/null
+++ b/Source/Tools/Updater/Properties/Resources.resx
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>
\ No newline at end of file
diff --git a/Source/Tools/Updater/Resources/GZDBU.ico b/Source/Tools/Updater/Resources/GZDBU.ico
new file mode 100644
index 0000000000000000000000000000000000000000..5091522de9a9038be6149189e15a1cc9bc4a0ad6
Binary files /dev/null and b/Source/Tools/Updater/Resources/GZDBU.ico differ
diff --git a/Source/Tools/Updater/Resources/SharpCompress.dll b/Source/Tools/Updater/Resources/SharpCompress.dll
new file mode 100644
index 0000000000000000000000000000000000000000..3052a3925a62def37fcc5ce8599e787eb16f3969
Binary files /dev/null and b/Source/Tools/Updater/Resources/SharpCompress.dll differ
diff --git a/Source/Tools/Updater/Updater.csproj b/Source/Tools/Updater/Updater.csproj
new file mode 100644
index 0000000000000000000000000000000000000000..e8b02942c914ecbf52d31554cc6861ea360f79a8
--- /dev/null
+++ b/Source/Tools/Updater/Updater.csproj
@@ -0,0 +1,138 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{2A0BA1B2-A0F1-479F-9083-2EC11D6B70DF}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>mxd.GZDBUpdater</RootNamespace>
+    <AssemblyName>Updater</AssemblyName>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <OldToolsVersion>2.0</OldToolsVersion>
+    <UpgradeBackupLocation>
+    </UpgradeBackupLocation>
+    <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <ApplicationIcon>Resources\GZDBU.ico</ApplicationIcon>
+    <PublishUrl>publish\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>false</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>false</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <ApplicationRevision>0</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <BootstrapperEnabled>true</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>..\..\..\Build\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>none</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>..\..\..\Build\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <PlatformTarget>x86</PlatformTarget>
+    <UseVSHostingProcess>false</UseVSHostingProcess>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="SharpCompress, Version=0.11.5.0, Culture=neutral, processorArchitecture=x86">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>Resources\SharpCompress.dll</HintPath>
+      <Private>False</Private>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Core">
+      <RequiredTargetFramework>3.5</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Helpers\EmbeddedAssembly.cs" />
+    <Compile Include="MainForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="MainForm.Designer.cs">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="MainForm.resx">
+      <SubType>Designer</SubType>
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+      <DesignTime>True</DesignTime>
+    </Compile>
+    <None Include="Updater.ini">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <Compile Include="Helpers\TaskbarProgress.cs" />
+    <Compile Include="Helpers\Webdata.cs" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.2.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 2.0 %28x86%29</ProductName>
+      <Install>true</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.0">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.0 %28x86%29</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="Resources\GZDBU.ico" />
+    <EmbeddedResource Include="Resources\SharpCompress.dll" />
+  </ItemGroup>
+  <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>
\ No newline at end of file
diff --git a/Source/Tools/Updater/Updater.ini b/Source/Tools/Updater/Updater.ini
new file mode 100644
index 0000000000000000000000000000000000000000..ecf1e5c03b14fd6edc5f20edd252147abbd0aef0
--- /dev/null
+++ b/Source/Tools/Updater/Updater.ini
@@ -0,0 +1,3 @@
+URL http://devbuilds.drdteam.org/doombuilder2-gzdb/
+FileName Builder.exe
+UpdateName GZDoom_Builder-r[REVNUM].7z
\ No newline at end of file