diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs
index 9233cd2..e33b473 100644
--- a/Bloxstrap/Bootstrapper.cs
+++ b/Bloxstrap/Bootstrapper.cs
@@ -18,6 +18,8 @@ using Microsoft.Win32;
using Bloxstrap.AppData;
+using ICSharpCode.SharpZipLib.Zip;
+
namespace Bloxstrap
{
public class Bootstrapper
@@ -32,6 +34,7 @@ namespace Bloxstrap
" http://www.roblox.com\r\n" +
"\r\n";
+ private readonly FastZipEvents _fastZipEvents = new();
private readonly CancellationTokenSource _cancelTokenSource = new();
private readonly IAppData AppData;
@@ -48,6 +51,8 @@ namespace Bloxstrap
private bool _mustUpgrade => String.IsNullOrEmpty(AppData.State.VersionGuid) || File.Exists(AppData.LockFilePath) || !File.Exists(AppData.ExecutablePath);
private bool _noConnection = false;
+ private int _appPid = 0;
+
public IBootstrapperDialog? Dialog = null;
public bool IsStudioLaunch => _launchMode != LaunchMode.Player;
@@ -56,6 +61,16 @@ namespace Bloxstrap
#region Core
public Bootstrapper()
{
+ // this is now always enabled as of v2.8.0
+ if (Dialog is not null)
+ Dialog.CancelEnabled = true;
+
+ // https://github.com/icsharpcode/SharpZipLib/blob/master/src/ICSharpCode.SharpZipLib/Zip/FastZip.cs/#L669-L680
+ // exceptions don't get thrown if we define events without actually binding to the failure events. probably a bug. ¯\_(ツ)_/¯
+ _fastZipEvents.FileFailure += (_, e) => throw e.Exception;
+ _fastZipEvents.DirectoryFailure += (_, e) => throw e.Exception;
+ _fastZipEvents.ProcessFile += (_, e) => e.ContinueRunning = !_cancelTokenSource.IsCancellationRequested;
+
AppData = IsStudioLaunch ? new RobloxStudioData() : new RobloxPlayerData();
}
@@ -182,6 +197,9 @@ namespace Bloxstrap
if (AppData.State.VersionGuid != _latestVersionGuid || _mustUpgrade)
await UpgradeRoblox();
+ if (_cancelTokenSource.IsCancellationRequested)
+ return;
+
// we require deployment details for applying modifications for a worst case scenario,
// where we'd need to restore files from a package that isn't present on disk and needs to be redownloaded
await ApplyModifications();
@@ -297,7 +315,6 @@ namespace Bloxstrap
return;
}
- int gameClientPid;
bool startEventSignalled;
// TODO: figure out why this is causing roblox to block for some users
@@ -306,12 +323,19 @@ namespace Bloxstrap
startEvent.Reset();
// v2.2.0 - byfron will trip if we keep a process handle open for over a minute, so we're doing this now
- using (var process = Process.Start(startInfo)!)
+ try
{
- gameClientPid = process.Id;
+ using var process = Process.Start(startInfo)!;
+ _appPid = process.Id;
+ }
+ catch (Exception)
+ {
+ // attempt a reinstall on next launch
+ File.Delete(AppData.ExecutablePath);
+ throw;
}
- App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {gameClientPid}), waiting for start event");
+ App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {_appPid}), waiting for start event");
startEventSignalled = startEvent.WaitOne(TimeSpan.FromSeconds(30));
}
@@ -335,6 +359,7 @@ namespace Bloxstrap
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
int pid = 0;
+
try
{
var process = Process.Start(new ProcessStartInfo
@@ -357,7 +382,7 @@ namespace Bloxstrap
autoclosePids.Add(pid);
}
- string args = gameClientPid.ToString();
+ string args = _appPid.ToString();
if (autoclosePids.Any())
args += $";{String.Join(',', autoclosePids)}";
@@ -378,13 +403,6 @@ namespace Bloxstrap
{
const string LOG_IDENT = "Bootstrapper::Cancel";
- if (!_isInstalling)
- {
- // TODO: this sucks and needs to be done better
- App.Terminate(ErrorCode.ERROR_CANCELLED);
- return;
- }
-
if (_cancelTokenSource.IsCancellationRequested)
return;
@@ -392,6 +410,9 @@ namespace Bloxstrap
_cancelTokenSource.Cancel();
+ if (Dialog is not null)
+ Dialog.CancelEnabled = false;
+
if (_isInstalling)
{
try
@@ -404,12 +425,26 @@ namespace Bloxstrap
{
App.Logger.WriteLine(LOG_IDENT, "Could not fully clean up installation!");
App.Logger.WriteException(LOG_IDENT, ex);
+
+ // assurance to make sure the next launch does a fresh install
+ // we probably shouldn't be using the lockfile to do this, but meh
+ var lockFile = new FileInfo(AppData.LockFilePath);
+ lockFile.Create().Dispose();
}
}
+ else if (_appPid != 0)
+ {
+ try
+ {
+ using var process = Process.GetProcessById(_appPid);
+ process.Kill();
+ }
+ catch (Exception) { }
+ }
Dialog?.CloseBootstrapper();
- App.Terminate(ErrorCode.ERROR_CANCELLED);
+ App.SoftTerminate(ErrorCode.ERROR_CANCELLED);
}
#endregion
@@ -443,6 +478,9 @@ namespace Bloxstrap
return false;
}
+ if (Dialog is not null)
+ Dialog.CancelEnabled = false;
+
string version = releaseInfo.TagName;
#else
string version = App.Version;
@@ -581,8 +619,6 @@ namespace Bloxstrap
if (Dialog is not null)
{
- // TODO: cancelling needs to always be enabled
- Dialog.CancelEnabled = true;
Dialog.ProgressStyle = ProgressBarStyle.Continuous;
Dialog.ProgressMaximum = ProgressBarMaximum;
@@ -733,9 +769,6 @@ namespace Bloxstrap
lockFile.Delete();
- if (Dialog is not null)
- Dialog.CancelEnabled = false;
-
_isInstalling = false;
}
@@ -807,6 +840,9 @@ namespace Bloxstrap
foreach (string file in Directory.GetFiles(Paths.Modifications, "*.*", SearchOption.AllDirectories))
{
+ if (_cancelTokenSource.IsCancellationRequested)
+ return;
+
// get relative directory path
string relativeFile = file.Substring(Paths.Modifications.Length + 1);
@@ -886,6 +922,9 @@ namespace Bloxstrap
if (package is not null)
{
+ if (_cancelTokenSource.IsCancellationRequested)
+ return;
+
await DownloadPackage(package);
ExtractPackage(package, entry.Value);
}
@@ -1056,7 +1095,7 @@ namespace Bloxstrap
string packageFolder = Path.Combine(AppData.Directory, AppData.PackageDirectoryMap[package.Name]);
string? fileFilter = null;
- // for sharpziplib, each file in the filter
+ // for sharpziplib, each file in the filter needs to be a regex
if (files is not null)
{
var regexList = new List();
@@ -1069,7 +1108,8 @@ namespace Bloxstrap
App.Logger.WriteLine(LOG_IDENT, $"Extracting {package.Name}...");
- var fastZip = new ICSharpCode.SharpZipLib.Zip.FastZip();
+ var fastZip = new FastZip(_fastZipEvents);
+
fastZip.ExtractZip(package.DownloadPath, packageFolder, fileFilter);
App.Logger.WriteLine(LOG_IDENT, $"Finished extracting {package.Name}");