/// <inheritdoc />
 public bool UpdateToVersion(int major, int minor)
 {
     lock (ByondLock)
     {
         if (!BusyCheck())
         {
             updateStat      = ByondStatus.Starting;
             RevisionStaging = new Thread(new ParameterizedThreadStart(UpdateToVersionImpl))
             {
                 IsBackground = true                         //don't slow me down
             };
             RevisionStaging.Start(String.Format("{0}.{1}", major, minor));
             return(true);
         }
         return(false);
     }
 }
 /// <summary>
 /// Attempts to move the staged update from <see cref="StagingDirectory"/> to <see cref="ByondDirectory"/>. Sets <see cref="lastError"/> on failure
 /// </summary>
 /// <returns><see langword="true"/> on success, <see langword="false"/> on failure</returns>
 bool ApplyStagedUpdate()
 {
     lock (CompilerLock)
     {
         if (compilerCurrentStatus == CompilerStatus.Compiling)
         {
             return(false);
         }
         lock (ByondLock)
         {
             if (updateStat != ByondStatus.Staged)
             {
                 return(false);
             }
             updateStat = ByondStatus.Updating;
         }
         try
         {
             var rbd = RelativePath(ByondDirectory);
             Helpers.DeleteDirectory(rbd);
             Directory.Move(RelativePath(StagingDirectoryInner), rbd);
             Helpers.DeleteDirectory(RelativePath(StagingDirectory));
             lastError = null;
             SendMessage("BYOND: Update completed!", MessageType.DeveloperInfo);
             WriteInfo(String.Format("BYOND update {0} completed!", GetVersion(ByondVersion.Installed)), EventID.BYONDUpdateComplete);
             return(true);
         }
         catch (Exception e)
         {
             lastError = e.ToString();
             SendMessage("BYOND: Update failed!", MessageType.DeveloperInfo);
             WriteError("BYOND update failed! Error: " + e.ToString(), EventID.BYONDUpdateFail);
             return(false);
         }
         finally
         {
             lock (ByondLock) {
                 updateStat = ByondStatus.Idle;
             }
         }
     }
 }
        /// <summary>
        /// Downloads and unzips a BYOND revision. Calls <see cref="ApplyStagedUpdate"/> afterwards if the <see cref="Instance"/> isn't running, otherwise, calls <see cref="RequestRestart"/>. Sets <see cref="lastError"/> on failure
        /// </summary>
        /// <param name="param">Stringified BYOND revision</param>
        public void UpdateToVersionImpl(object param)
        {
            lock (ByondLock) {
                if (updateStat != ByondStatus.Starting)
                {
                    return;
                }
                updateStat = ByondStatus.Downloading;
            }
            bool staged = false;

            try
            {
                CleanByondStaging();

                var vi    = ((string)param).Split('.');
                var major = Convert.ToInt32(vi[0]);
                var minor = Convert.ToInt32(vi[1]);
                var rrdp  = RelativePath(RevisionDownloadPath);
                using (var client = new WebClient())
                {
                    SendMessage(String.Format("BYOND: Updating to version {0}.{1}...", major, minor), MessageType.DeveloperInfo);

                    //DOWNLOADING

                    try
                    {
                        client.DownloadFile(String.Format(ByondRevisionsURL, major, minor), rrdp);
                    }
                    catch
                    {
                        SendMessage("BYOND: Update download failed. Does the specified version exist?", MessageType.DeveloperInfo);
                        lastError = String.Format("Download of BYOND version {0}.{1} failed! Does it exist?", major, minor);
                        WriteWarning(String.Format("Failed to update BYOND to version {0}.{1}!", major, minor), EventID.BYONDUpdateFail);
                        lock (ByondLock)
                        {
                            updateStat = ByondStatus.Idle;
                        }
                        return;
                    }
                }
                lock (ByondLock)
                {
                    updateStat = ByondStatus.Staging;
                }

                //STAGING

                ZipFile.ExtractToDirectory(rrdp, RelativePath(StagingDirectory));
                lock (ByondLock)
                {
                    File.WriteAllText(RelativePath(StagingDirectoryInner + VersionFile), String.Format("{0}.{1}", major, minor));
                    //IMPORTANT: SET THE BYOND CONFIG TO NOT PROMPT FOR TRUSTED MODE REEE
                    Directory.CreateDirectory(RelativePath(ByondConfigDir));
                    File.WriteAllText(RelativePath(ByondDDConfig), ByondNoPromptTrustedMode);
                }
                File.Delete(RevisionDownloadPath);

                lock (ByondLock)
                {
                    updateStat = ByondStatus.Staged;
                }

                switch (DaemonStatus())
                {
                case DreamDaemonStatus.Offline:
                    if (ApplyStagedUpdate())
                    {
                        lastError = null;
                    }
                    else
                    {
                        lastError = "Failed to apply update!";
                    }
                    break;

                default:
                    //Compile() will call RequestRestart()
                    lastError = "Update staged. Awaiting server restart...";
                    SendMessage(String.Format("BYOND: Staging complete. Awaiting server restart...", major, minor), MessageType.DeveloperInfo);
                    WriteInfo(String.Format("BYOND update {0}.{1} staged", major, minor), EventID.BYONDUpdateStaged);
                    staged = true;
                    break;
                }
            }
            catch (ThreadAbortException)
            {
                return;
            }
            catch (Exception e)
            {
                WriteError("Revision staging errror: " + e.ToString(), EventID.BYONDUpdateFail);
                lock (ByondLock)
                {
                    updateStat      = ByondStatus.Idle;
                    lastError       = e.ToString();
                    RevisionStaging = null;
                }
            }
            if (staged)
            {
                lock (ByondLock)
                {
                    //Some fuckery to trick the compiler into starting even though we're staged
                    //Won't f**k up the actual compiler thread though
                    updateStat = ByondStatus.Idle;
                    Compile();
                    updateStat = ByondStatus.Staged;
                }
            }
        }
        /// <summary>
        /// Downloads and unzips a BYOND revision. Calls <see cref="ApplyStagedUpdate"/> afterwards if the <see cref="Instance"/> isn't running, otherwise, calls <see cref="RequestRestart"/>. Sets <see cref="lastError"/> on failure
        /// </summary>
        /// <param name="param">Stringified BYOND revision</param>
        public void UpdateToVersionImpl(object param)
        {
            lock (ByondLock) {
                if (updateStat != ByondStatus.Starting)
                {
                    return;
                }
                updateStat = ByondStatus.Downloading;
            }
            bool staged = false;

            try
            {
                CleanByondStaging();

                var vi    = ((string)param).Split('.');
                var major = Convert.ToInt32(vi[0]);
                var minor = Convert.ToInt32(vi[1]);
                var rrdp  = RelativePath(RevisionDownloadPath);
                using (var client = new WebClient())
                {
                    SendMessage(String.Format("BYOND: Updating to version {0}.{1}...", major, minor), MessageType.DeveloperInfo);

                    //DOWNLOADING

                    try
                    {
                        client.DownloadFile(String.Format(ByondRevisionsURL, major, minor), rrdp);
                    }
                    catch
                    {
                        SendMessage("BYOND: Update download failed. Does the specified version exist?", MessageType.DeveloperInfo);
                        lastError = String.Format("Download of BYOND version {0}.{1} failed! Does it exist?", major, minor);
                        WriteWarning(String.Format("Failed to update BYOND to version {0}.{1}!", major, minor), EventID.BYONDUpdateFail);
                        lock (ByondLock)
                        {
                            updateStat = ByondStatus.Idle;
                        }
                        return;
                    }
                }
                lock (ByondLock)
                {
                    updateStat = ByondStatus.Staging;
                }

                //STAGING

                ZipFile.ExtractToDirectory(rrdp, RelativePath(StagingDirectory));
                File.Delete(rrdp);
                //IMPORTANT: SET THE BYOND CONFIG TO NOT PROMPT FOR TRUSTED MODE REEE
                Directory.CreateDirectory(RelativePath(ByondConfigDir));
                File.WriteAllText(RelativePath(ByondDDConfig), ByondNoPromptTrustedMode);

                if (major >= 512 && minor >= 1427)
                {
                    if (Monitor.TryEnter(DirectXInstallLock))
                    {
                        try
                        {
                            //always install it, it's pretty fast and will do better redundancy checking than us
                            using (var p = new Process())
                            {
                                p.StartInfo.Arguments = "/silent";
                                var rbdx = RelativePath(ByondDXDir);
                                p.StartInfo.FileName         = rbdx + "/DXSETUP.exe";
                                p.StartInfo.UseShellExecute  = false;
                                p.StartInfo.WorkingDirectory = rbdx;
                                p.Start();
                                try
                                {
                                    p.WaitForExit();
                                }
                                finally
                                {
                                    try
                                    {
                                        p.Kill();
                                        p.WaitForExit();
                                    }
                                    catch (InvalidOperationException) { }
                                }

                                if (p.ExitCode != 0)
                                {
                                    throw new Exception("Failed to install included DirectX! Exit code: " + p.ExitCode);
                                }
                            }
                        }
                        finally
                        {
                            Monitor.Exit(DirectXInstallLock);
                        }
                    }
                }

                lock (ByondLock)
                    File.WriteAllText(RelativePath(StagingDirectoryInner + VersionFile), String.Format("{0}.{1}", major, minor));

                lock (ByondLock)
                {
                    updateStat = ByondStatus.Staged;
                }

                switch (DaemonStatus())
                {
                case DreamDaemonStatus.Offline:
                    if (ApplyStagedUpdate())
                    {
                        lastError = null;
                    }
                    else
                    {
                        lastError = "Failed to apply update!";
                    }
                    break;

                default:
                    //Compile() will call RequestRestart()
                    lastError = "Update staged. Awaiting server restart...";
                    SendMessage(String.Format("BYOND: Staging complete. Awaiting server restart...", major, minor), MessageType.DeveloperInfo);
                    WriteInfo(String.Format("BYOND update {0}.{1} staged", major, minor), EventID.BYONDUpdateStaged);
                    staged = true;
                    break;
                }
            }
            catch (ThreadAbortException)
            {
                return;
            }
            catch (Exception e)
            {
                WriteError("Revision staging errror: " + e.ToString(), EventID.BYONDUpdateFail);
                lock (ByondLock)
                {
                    updateStat      = ByondStatus.Idle;
                    lastError       = e.ToString();
                    RevisionStaging = null;
                }
            }
            if (staged)
            {
                lock (ByondLock)
                {
                    //Some fuckery to trick the compiler into starting even though we're staged
                    //Won't f**k up the actual compiler thread though
                    updateStat = ByondStatus.Idle;
                    Compile();
                    updateStat = ByondStatus.Staged;
                }
            }
        }