From 92b159d68206ea4f81ddf75897de210d07b83f9b Mon Sep 17 00:00:00 2001
From: pizzaboxer <41478239+pizzaboxer@users.noreply.github.com>
Date: Sun, 21 Aug 2022 22:41:16 +0100
Subject: [PATCH] Updates and bugfixes for v1.3.0
- Features
- Added integration with rbxfpsunlocker
- Added support for user-applicable mods
- Added ability to disable auto-update checking
- Misc
- Removed Bloxstrap branding from Discord Rich Presence
- Mod presets for old death sound and mouse cursor are now statically stored as base64 strings, eliminating reliance on the website and the old cursors still existing
- Bugfixes
- Fixed vista bootstrapper style not hiding properly and improper behavior when closed
- Fixed forms not being brought to the front when shown
- Code
- Reconsolidated Bootstrapper to a single file, using regions instead of partials
---
Bloxstrap/Bloxstrap.csproj | 15 +-
Bloxstrap/Bootstrapper.cs | 795 ++++++++++++++++++
.../Bootstrapper/Bootstrapper.AppInstall.cs | 125 ---
.../Bootstrapper/Bootstrapper.Properties.cs | 130 ---
.../Bootstrapper.RobloxInstall.cs | 243 ------
.../Bootstrapper.RobloxModifications.cs | 64 --
Bloxstrap/Bootstrapper/Bootstrapper.cs | 187 ----
.../BootstrapperStyleForm.cs | 6 +-
...trapperStyle.cs => IBootstrapperDialog.cs} | 2 +-
.../LegacyDialog2009.Designer.cs | 1 +
.../BootstrapperStyles/LegacyDialog2009.cs | 5 +
.../LegacyDialog2011.Designer.cs | 3 +-
.../BootstrapperStyles/LegacyDialog2011.cs | 5 +
.../ProgressDialog.Designer.cs | 1 +
.../BootstrapperStyles/ProgressDialog.cs | 5 +
.../ProgressDialogDark.Designer.cs | 1 +
.../BootstrapperStyles/ProgressDialogDark.cs | 5 +
.../VistaDialog.Designer.cs | 4 +-
.../Dialogs/BootstrapperStyles/VistaDialog.cs | 1 -
Bloxstrap/Dialogs/Preferences.Designer.cs | 140 ++-
Bloxstrap/Dialogs/Preferences.cs | 147 ++--
Bloxstrap/Dialogs/Preferences.resx | 6 +-
Bloxstrap/Helpers/Directories.cs | 28 +
.../{ => Integrations}/DiscordRichPresence.cs | 36 +-
.../Helpers/Integrations/RbxFpsUnlocker.cs | 95 +++
Bloxstrap/Helpers/Protocol.cs | 15 +-
Bloxstrap/Helpers/RSMM/FileManifest.cs | 2 +
Bloxstrap/Helpers/RSMM/PackageManifest.cs | 2 +
.../Helpers/{UpdateChecker.cs => Updater.cs} | 27 +-
Bloxstrap/Helpers/Utilities.cs | 12 +-
Bloxstrap/Program.cs | 35 +-
Bloxstrap/Settings.cs | 8 +
32 files changed, 1232 insertions(+), 919 deletions(-)
create mode 100644 Bloxstrap/Bootstrapper.cs
delete mode 100644 Bloxstrap/Bootstrapper/Bootstrapper.AppInstall.cs
delete mode 100644 Bloxstrap/Bootstrapper/Bootstrapper.Properties.cs
delete mode 100644 Bloxstrap/Bootstrapper/Bootstrapper.RobloxInstall.cs
delete mode 100644 Bloxstrap/Bootstrapper/Bootstrapper.RobloxModifications.cs
delete mode 100644 Bloxstrap/Bootstrapper/Bootstrapper.cs
rename Bloxstrap/Dialogs/BootstrapperStyles/{IBootstrapperStyle.cs => IBootstrapperDialog.cs} (95%)
create mode 100644 Bloxstrap/Helpers/Directories.cs
rename Bloxstrap/Helpers/{ => Integrations}/DiscordRichPresence.cs (58%)
create mode 100644 Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs
rename Bloxstrap/Helpers/{UpdateChecker.cs => Updater.cs} (80%)
diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj
index cda5ea0..c01e437 100644
--- a/Bloxstrap/Bloxstrap.csproj
+++ b/Bloxstrap/Bloxstrap.csproj
@@ -4,13 +4,14 @@
WinExe
net6.0-windows
enable
- true
+ true
enable
AnyCPU
AnyCPU;x86
Bloxstrap.ico
- 1.2.0
- 1.2.0.0
+ 1.3.0
+ 1.3.0.0
+ True
@@ -27,12 +28,8 @@
-
- Form
-
-
- Form
-
+
+
True
True
diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs
new file mode 100644
index 0000000..f1c2116
--- /dev/null
+++ b/Bloxstrap/Bootstrapper.cs
@@ -0,0 +1,795 @@
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Net.Http;
+
+using Microsoft.Win32;
+
+using Bloxstrap.Enums;
+using Bloxstrap.Dialogs.BootstrapperStyles;
+using Bloxstrap.Helpers;
+using Bloxstrap.Helpers.Integrations;
+using Bloxstrap.Helpers.RSMM;
+
+namespace Bloxstrap
+{
+ public partial class Bootstrapper
+ {
+ #region Properties
+ private string? LaunchCommandLine;
+
+ private string VersionGuid;
+ private PackageManifest VersionPackageManifest;
+ private FileManifest VersionFileManifest;
+ private string VersionFolder;
+
+ private readonly bool FreshInstall;
+
+ private int ProgressIncrement;
+ private bool CancelFired = false;
+
+ private static readonly HttpClient Client = new();
+
+ // in case a new package is added, you can find the corresponding directory
+ // by opening the stock bootstrapper in a hex editor
+ // TODO - there ideally should be a less static way to do this that's not hardcoded?
+ private static readonly IReadOnlyDictionary PackageDirectories = new Dictionary()
+ {
+ { "RobloxApp.zip", @"" },
+ { "shaders.zip", @"shaders\" },
+ { "ssl.zip", @"ssl\" },
+
+ { "content-avatar.zip", @"content\avatar\" },
+ { "content-configs.zip", @"content\configs\" },
+ { "content-fonts.zip", @"content\fonts\" },
+ { "content-sky.zip", @"content\sky\" },
+ { "content-sounds.zip", @"content\sounds\" },
+ { "content-textures2.zip", @"content\textures\" },
+ { "content-models.zip", @"content\models\" },
+
+ { "content-textures3.zip", @"PlatformContent\pc\textures\" },
+ { "content-terrain.zip", @"PlatformContent\pc\terrain\" },
+ { "content-platform-fonts.zip", @"PlatformContent\pc\fonts\" },
+
+ { "extracontent-luapackages.zip", @"ExtraContent\LuaPackages\" },
+ { "extracontent-translations.zip", @"ExtraContent\translations\" },
+ { "extracontent-models.zip", @"ExtraContent\models\" },
+ { "extracontent-textures.zip", @"ExtraContent\textures\" },
+ { "extracontent-places.zip", @"ExtraContent\places\" },
+ };
+
+ private static readonly string AppSettings =
+ "\n" +
+ "\n" +
+ " content\n" +
+ " http://www.roblox.com\n" +
+ "\n";
+
+ private static readonly string ModReadme =
+ "This is where you can modify your Roblox files while preserving modifications\n" +
+ "whenever Roblox updates.\n" +
+ "\n" +
+ "For example, Modifications\\content\\sounds\\ouch.ogg will\n" +
+ "overwrite Versions\\version-xxxxxxxxxxxxxxxx\\content\\sounds\\ouch.ogg\n" +
+ "\n" +
+ "If you remove a file mod from here, Bloxstrap will restore the stock version\n" +
+ "of the file the next time it's launched.\n" +
+ "\n" +
+ "Any files added here to the root modification directory are ignored.\n" +
+ "\n" +
+ "By default, two mod presets are provided for restoring the old death\n" +
+ "sound and the old mouse cursor.\n";
+
+ // TODO: reduce reliance on event handlers for signalling property changes to the bootstrapper dialog
+ // i mean, chances are we can just use IBootstrapperDialog now?
+
+ // public IBootstrapperDialog BootstrapperDialog;
+
+ public event EventHandler CloseDialogEvent;
+ public event EventHandler PromptShutdownEvent;
+ public event ChangeEventHandler ShowSuccessEvent;
+ public event ChangeEventHandler MessageChanged;
+ public event ChangeEventHandler ProgressBarValueChanged;
+ public event ChangeEventHandler ProgressBarStyleChanged;
+ public event ChangeEventHandler CancelEnabledChanged;
+
+ private string _message;
+ private int _progress = 0;
+ private ProgressBarStyle _progressStyle = ProgressBarStyle.Marquee;
+ private bool _cancelEnabled = false;
+
+ public string Message
+ {
+ get => _message;
+
+ private set
+ {
+ if (_message == value)
+ return;
+
+ MessageChanged.Invoke(this, new ChangeEventArgs(value));
+
+ _message = value;
+ }
+ }
+
+ public int Progress
+ {
+ get => _progress;
+
+ private set
+ {
+ if (_progress == value)
+ return;
+
+ ProgressBarValueChanged.Invoke(this, new ChangeEventArgs(value));
+
+ _progress = value;
+ }
+ }
+
+ public ProgressBarStyle ProgressStyle
+ {
+ get => _progressStyle;
+
+ private set
+ {
+ if (_progressStyle == value)
+ return;
+
+ ProgressBarStyleChanged.Invoke(this, new ChangeEventArgs(value));
+
+ _progressStyle = value;
+ }
+ }
+
+ public bool CancelEnabled
+ {
+ get => _cancelEnabled;
+
+ private set
+ {
+ if (_cancelEnabled == value)
+ return;
+
+ CancelEnabledChanged.Invoke(this, new ChangeEventArgs(value));
+
+ _cancelEnabled = value;
+ }
+ }
+ #endregion
+
+ #region Core
+ public Bootstrapper()
+ {
+ FreshInstall = String.IsNullOrEmpty(Program.Settings.VersionGuid);
+ Client.Timeout = TimeSpan.FromMinutes(10);
+ }
+
+ public void Initialize(BootstrapperStyle bootstrapperStyle, string? launchCommandLine = null)
+ {
+ LaunchCommandLine = launchCommandLine;
+
+ switch (bootstrapperStyle)
+ {
+ case BootstrapperStyle.VistaDialog:
+ Application.Run(new VistaDialog(this));
+ break;
+
+ case BootstrapperStyle.LegacyDialog2009:
+ Application.Run(new LegacyDialog2009(this));
+ break;
+
+ case BootstrapperStyle.LegacyDialog2011:
+ Application.Run(new LegacyDialog2011(this));
+ break;
+
+ case BootstrapperStyle.ProgressDialog:
+ Application.Run(new ProgressDialog(this));
+ break;
+
+ case BootstrapperStyle.ProgressDialogDark:
+ Application.Run(new ProgressDialogDark(this));
+ break;
+ }
+ }
+
+ public async Task Run()
+ {
+ /* Message = "hi";
+ Progress = 42;
+ ProgressStyle = ProgressBarStyle.Blocks;
+ CancelEnabled = true;
+
+ BootstrapperDialog.Message = "hi";
+ BootstrapperDialog.ProgressValue = 42;
+ BootstrapperDialog.ProgressStyle = ProgressBarStyle.Blocks;
+ BootstrapperDialog.CancelEnabled = true;
+
+ return; */
+
+ if (LaunchCommandLine == "-uninstall")
+ {
+ Uninstall();
+ return;
+ }
+
+ await CheckLatestVersion();
+
+ if (!Directory.Exists(VersionFolder) || Program.Settings.VersionGuid != VersionGuid)
+ {
+ Debug.WriteLineIf(!Directory.Exists(VersionFolder), $"Installing latest version (!Directory.Exists({VersionFolder}))");
+ Debug.WriteLineIf(Program.Settings.VersionGuid != VersionGuid, $"Installing latest version ({Program.Settings.VersionGuid} != {VersionGuid})");
+
+ await InstallLatestVersion();
+ }
+
+ ApplyModifications();
+
+ if (Program.IsFirstRun)
+ Program.SettingsManager.ShouldSave = true;
+
+ if (Program.IsFirstRun || FreshInstall)
+ Register();
+
+ CheckInstall();
+
+ await RbxFpsUnlocker.CheckInstall();
+
+ await StartRoblox();
+
+ Program.Exit();
+ }
+
+ private async Task CheckLatestVersion()
+ {
+ Message = "Connecting to Roblox...";
+
+ VersionGuid = await Client.GetStringAsync($"{Program.BaseUrlSetup}/version");
+ VersionFolder = Path.Combine(Directories.Versions, VersionGuid);
+ VersionPackageManifest = await PackageManifest.Get(VersionGuid);
+ VersionFileManifest = await FileManifest.Get(VersionGuid);
+ }
+
+ private void CheckIfRunning()
+ {
+ Process[] processes = Process.GetProcessesByName("RobloxPlayerBeta");
+
+ if (processes.Length > 0)
+ PromptShutdown();
+
+ try
+ {
+ // try/catch just in case process was closed before prompt was answered
+
+ foreach (Process process in processes)
+ {
+ process.CloseMainWindow();
+ process.Close();
+ }
+ }
+ catch (Exception) { }
+ }
+
+ private async Task StartRoblox()
+ {
+ string startEventName = Program.ProjectName.Replace(" ", "") + "StartEvent";
+
+ Message = "Starting Roblox...";
+
+ // launch time isn't really required for all launches, but it's usually just safest to do this
+ LaunchCommandLine += " --launchtime=" + DateTimeOffset.Now.ToUnixTimeSeconds() + " -startEvent " + startEventName;
+
+ using (SystemEvent startEvent = new(startEventName))
+ {
+ bool shouldWait = false;
+
+ Process gameClient = Process.Start(Path.Combine(VersionFolder, "RobloxPlayerBeta.exe"), LaunchCommandLine);
+ Process? rbxFpsUnlocker = null;
+ DiscordRichPresence? richPresence = null;
+
+ bool startEventFired = await startEvent.WaitForEvent();
+
+ startEvent.Close();
+
+ if (!startEventFired)
+ return;
+
+ if (Program.Settings.RFUEnabled && Process.GetProcessesByName("rbxfpsunlocker").Length == 0)
+ {
+ ProcessStartInfo startInfo = new();
+ startInfo.FileName = Path.Combine(Directories.Integrations, @"rbxfpsunlocker\rbxfpsunlocker.exe");
+ startInfo.WorkingDirectory = Path.Combine(Directories.Integrations, "rbxfpsunlocker");
+
+ rbxFpsUnlocker = Process.Start(startInfo);
+
+ if (Program.Settings.RFUAutoclose)
+ shouldWait = true;
+ }
+
+ // event fired, wait for 6 seconds then close
+ await Task.Delay(6000);
+
+ // now we move onto handling rich presence
+ // except beta app launch since we have to rely strictly on website launch
+ if (Program.Settings.UseDiscordRichPresence && !LaunchCommandLine.Contains("--app"))
+ {
+ // probably not the most ideal way to do this
+ string? placeId = Utilities.GetKeyValue(LaunchCommandLine, "placeId=", '&');
+
+ if (placeId is not null)
+ {
+ richPresence = new DiscordRichPresence();
+ bool presenceSet = await richPresence.SetPresence(placeId);
+
+ if (presenceSet)
+ shouldWait = true;
+ else
+ richPresence.Dispose();
+ }
+
+ }
+
+ if (!shouldWait)
+ return;
+
+ // keep bloxstrap open in the background
+ CloseDialog();
+ await gameClient.WaitForExitAsync();
+
+ if (richPresence is not null)
+ richPresence.Dispose();
+
+ if (Program.Settings.RFUAutoclose && rbxFpsUnlocker is not null)
+ rbxFpsUnlocker.Kill();
+ }
+ }
+
+ public void CancelButtonClicked()
+ {
+ if (!CancelEnabled)
+ {
+ Program.Exit();
+ return;
+ }
+
+ CancelFired = true;
+
+ try
+ {
+ if (Program.IsFirstRun)
+ Directory.Delete(Directories.Base, true);
+ else if (Directory.Exists(VersionFolder))
+ Directory.Delete(VersionFolder, true);
+ }
+ catch (Exception) { }
+
+ Program.Exit();
+ }
+
+ private void ShowSuccess(string message)
+ {
+ ShowSuccessEvent.Invoke(this, new ChangeEventArgs(message));
+ }
+
+ private void PromptShutdown()
+ {
+ PromptShutdownEvent.Invoke(this, new EventArgs());
+ }
+
+ private void CloseDialog()
+ {
+ CloseDialogEvent.Invoke(this, new EventArgs());
+ }
+ #endregion
+
+ #region App Install
+ public static void Register()
+ {
+ RegistryKey applicationKey = Registry.CurrentUser.CreateSubKey($@"Software\{Program.ProjectName}");
+
+ // new install location selected, delete old one
+ string? oldInstallLocation = (string?)applicationKey.GetValue("OldInstallLocation");
+ if (!String.IsNullOrEmpty(oldInstallLocation) && oldInstallLocation != Directories.Base)
+ {
+ try
+ {
+ if (Directory.Exists(oldInstallLocation))
+ Directory.Delete(oldInstallLocation, true);
+ }
+ catch (Exception) { }
+
+ applicationKey.DeleteValue("OldInstallLocation");
+ }
+
+ applicationKey.SetValue("InstallLocation", Directories.Base);
+ applicationKey.Close();
+
+ // set uninstall key
+ RegistryKey uninstallKey = Registry.CurrentUser.CreateSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{Program.ProjectName}");
+ uninstallKey.SetValue("DisplayIcon", $"{Directories.App},0");
+ uninstallKey.SetValue("DisplayName", Program.ProjectName);
+ uninstallKey.SetValue("InstallDate", DateTime.Now.ToString("yyyyMMdd"));
+ uninstallKey.SetValue("InstallLocation", Directories.Base);
+ uninstallKey.SetValue("NoRepair", 1);
+ uninstallKey.SetValue("Publisher", Program.ProjectName);
+ uninstallKey.SetValue("ModifyPath", $"\"{Directories.App}\" -preferences");
+ uninstallKey.SetValue("UninstallString", $"\"{Directories.App}\" -uninstall");
+ uninstallKey.Close();
+ }
+
+ public static void CheckInstall()
+ {
+ // check if launch uri is set to our bootstrapper
+ // this doesn't go under register, so we check every launch
+ // just in case the stock bootstrapper changes it back
+
+ Protocol.Register("roblox", "Roblox", Directories.App);
+ Protocol.Register("roblox-player", "Roblox", Directories.App);
+
+ // in case the user is reinstalling
+ if (File.Exists(Directories.App) && Program.IsFirstRun)
+ File.Delete(Directories.App);
+
+ // check to make sure bootstrapper is in the install folder
+ if (!File.Exists(Directories.App) && Environment.ProcessPath is not null)
+ File.Copy(Environment.ProcessPath, Directories.App);
+
+ // this SHOULD go under Register(),
+ // but then people who have Bloxstrap v1.0.0 installed won't have this without a reinstall
+ // maybe in a later version?
+ if (!Directory.Exists(Program.StartMenu))
+ {
+ Directory.CreateDirectory(Program.StartMenu);
+
+ ShellLink.Shortcut.CreateShortcut(Directories.App, "", Directories.App, 0)
+ .WriteToFile(Path.Combine(Program.StartMenu, "Play Roblox.lnk"));
+
+ ShellLink.Shortcut.CreateShortcut(Directories.App, "-preferences", Directories.App, 0)
+ .WriteToFile(Path.Combine(Program.StartMenu, $"Configure {Program.ProjectName}.lnk"));
+ }
+ }
+
+ private void Uninstall()
+ {
+ CheckIfRunning();
+
+ Message = $"Uninstalling {Program.ProjectName}...";
+
+ Program.SettingsManager.ShouldSave = false;
+
+ // check if stock bootstrapper is still installed
+ RegistryKey? bootstrapperKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\roblox-player");
+ if (bootstrapperKey is null)
+ {
+ Protocol.Unregister("roblox");
+ Protocol.Unregister("roblox-player");
+ }
+ else
+ {
+ // revert launch uri handler to stock bootstrapper
+
+ string bootstrapperLocation = (string?)bootstrapperKey.GetValue("InstallLocation") + "RobloxPlayerLauncher.exe";
+
+ Protocol.Register("roblox", "Roblox", bootstrapperLocation);
+ Protocol.Register("roblox-player", "Roblox", bootstrapperLocation);
+ }
+
+ try
+ {
+ // delete application key
+ Registry.CurrentUser.DeleteSubKey($@"Software\{Program.ProjectName}");
+
+ // delete start menu folder
+ Directory.Delete(Program.StartMenu, true);
+
+ // delete uninstall key
+ Registry.CurrentUser.DeleteSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{Program.ProjectName}");
+
+ // delete installation folder
+ // (should delete everything except bloxstrap itself)
+ Directory.Delete(Directories.Base, true);
+ }
+ catch (Exception) { }
+
+ ShowSuccess($"{Program.ProjectName} has been uninstalled");
+ }
+ #endregion
+
+ #region Roblox Install
+ private async Task InstallLatestVersion()
+ {
+ CheckIfRunning();
+
+ if (FreshInstall)
+ Message = "Installing Roblox...";
+ else
+ Message = "Upgrading Roblox...";
+
+ Directory.CreateDirectory(Directories.Base);
+
+ CancelEnabled = true;
+
+ // i believe the original bootstrapper bases the progress bar off zip
+ // extraction progress, but here i'm doing package download progress
+
+ ProgressStyle = ProgressBarStyle.Continuous;
+
+ ProgressIncrement = (int)Math.Floor((decimal)1 / VersionPackageManifest.Count * 100);
+
+ Directory.CreateDirectory(Directories.Downloads);
+
+ foreach (Package package in VersionPackageManifest)
+ {
+ // no await, download all the packages at once
+ DownloadPackage(package);
+ }
+
+ do
+ {
+ // wait for download to finish (and also round off the progress bar if needed)
+
+ if (Progress == ProgressIncrement * VersionPackageManifest.Count)
+ Progress = 100;
+
+ await Task.Delay(1000);
+ }
+ while (Progress != 100);
+
+ ProgressStyle = ProgressBarStyle.Marquee;
+
+ Debug.WriteLine("Finished downloading");
+
+ Directory.CreateDirectory(Directories.Versions);
+
+ foreach (Package package in VersionPackageManifest)
+ {
+ // extract all the packages at once (shouldn't be too heavy on cpu?)
+ ExtractPackage(package);
+ }
+
+ Debug.WriteLine("Finished extracting packages");
+
+ Message = "Configuring Roblox...";
+
+ string appSettingsLocation = Path.Combine(VersionFolder, "AppSettings.xml");
+ await File.WriteAllTextAsync(appSettingsLocation, AppSettings);
+
+ if (!FreshInstall)
+ {
+ // let's take this opportunity to delete any packages we don't need anymore
+ foreach (string filename in Directory.GetFiles(Directories.Downloads))
+ {
+ if (!VersionPackageManifest.Exists(package => filename.Contains(package.Signature)))
+ File.Delete(filename);
+ }
+
+ if (VersionGuid != Program.Settings.VersionGuid)
+ {
+ // and also to delete our old version folder
+ Directory.Delete(Path.Combine(Directories.Versions, Program.Settings.VersionGuid), true);
+ }
+ }
+
+ CancelEnabled = false;
+
+ Program.Settings.VersionGuid = VersionGuid;
+ }
+
+ private void ApplyModifications()
+ {
+ string modFolder = Path.Combine(Directories.Modifications);
+ string manifestFile = Path.Combine(Directories.Base, "ModManifest.txt");
+
+ List manifestFiles = new();
+ List modFolderFiles = new();
+
+ if (!Directory.Exists(modFolder))
+ {
+ Directory.CreateDirectory(modFolder);
+ File.WriteAllText(Path.Combine(modFolder, "README.txt"), ModReadme);
+ }
+
+ CheckModPreset(Program.Settings.UseOldDeathSound, @"content\sounds\ouch.ogg", Program.Base64OldDeathSound);
+ CheckModPreset(Program.Settings.UseOldMouseCursor, @"content\textures\Cursors\KeyboardMouse\ArrowCursor.png", Program.Base64OldArrowCursor);
+ CheckModPreset(Program.Settings.UseOldMouseCursor, @"content\textures\Cursors\KeyboardMouse\ArrowFarCursor.png", Program.Base64OldArrowFarCursor);
+
+ foreach (string file in Directory.GetFiles(modFolder, "*.*", SearchOption.AllDirectories))
+ {
+ // get relative directory path
+ string relativeFile = file.Substring(modFolder.Length + 1);
+
+ // ignore files placed in the root directory
+ if (!relativeFile.Contains(@"\"))
+ continue;
+
+ modFolderFiles.Add(relativeFile);
+ }
+
+ // the manifest is primarily here to keep track of what files have been
+ // deleted from the modifications folder, so that we know when to restore the
+ // original files from the downloaded packages
+
+ if (File.Exists(manifestFile))
+ manifestFiles = File.ReadAllLines(manifestFile).ToList();
+ else
+ manifestFiles = modFolderFiles;
+
+ // copy and overwrite
+ foreach (string file in modFolderFiles)
+ {
+ string fileModFolder = Path.Combine(modFolder, file);
+ string fileVersionFolder = Path.Combine(VersionFolder, file);
+
+ if (File.Exists(fileVersionFolder))
+ {
+ if (Utilities.MD5File(fileModFolder) == Utilities.MD5File(fileVersionFolder))
+ continue;
+ }
+
+ File.Copy(fileModFolder, fileVersionFolder, true);
+ }
+
+ // now we check for files that have been deleted from the mod folder
+ foreach (string fileLocation in manifestFiles)
+ {
+ if (modFolderFiles.Contains(fileLocation))
+ continue;
+
+ KeyValuePair packageDirectory;
+
+ try
+ {
+ packageDirectory = PackageDirectories.First(x => x.Key != "RobloxApp.zip" && fileLocation.StartsWith(x.Value));
+ }
+ catch (InvalidOperationException)
+ {
+ // package doesn't exist, likely mistakenly placed file
+ continue;
+ }
+
+ // restore original file
+ string fileName = fileLocation.Substring(packageDirectory.Value.Length);
+ ExtractFileFromPackage(packageDirectory.Key, fileName);
+ }
+
+ File.WriteAllLines(manifestFile, modFolderFiles);
+ }
+
+ private void CheckModPreset(bool condition, string location, string base64Contents)
+ {
+ string modFolderLocation = Path.Combine(Directories.Modifications, location);
+
+ Directory.CreateDirectory(Path.GetDirectoryName(modFolderLocation));
+
+ if (condition)
+ {
+ if (!File.Exists(modFolderLocation))
+ {
+ File.WriteAllBytes(modFolderLocation, Convert.FromBase64String(base64Contents));
+ }
+ }
+ else if (File.Exists(modFolderLocation))
+ {
+ File.Delete(modFolderLocation);
+ }
+ }
+
+ private async void DownloadPackage(Package package)
+ {
+ string packageUrl = $"{Program.BaseUrlSetup}/{VersionGuid}-{package.Name}";
+ string packageLocation = Path.Combine(Directories.Downloads, package.Signature);
+ string robloxPackageLocation = Path.Combine(Program.LocalAppData, "Roblox", "Downloads", package.Signature);
+
+ if (File.Exists(packageLocation))
+ {
+ FileInfo file = new(packageLocation);
+
+ string calculatedMD5 = Utilities.MD5File(packageLocation);
+ if (calculatedMD5 != package.Signature)
+ {
+ Debug.WriteLine($"{package.Name} is corrupted ({calculatedMD5} != {package.Signature})! Deleting and re-downloading...");
+ file.Delete();
+ }
+ else
+ {
+ Debug.WriteLine($"{package.Name} is already downloaded, skipping...");
+ Progress += ProgressIncrement;
+ return;
+ }
+ }
+ else if (File.Exists(robloxPackageLocation))
+ {
+ // let's cheat! if the stock bootstrapper already previously downloaded the file,
+ // then we can just copy the one from there
+
+ Debug.WriteLine($"Found existing version of {package.Name} ({robloxPackageLocation})! Copying to Downloads folder...");
+ File.Copy(robloxPackageLocation, packageLocation);
+ Progress += ProgressIncrement;
+ return;
+ }
+
+ if (!File.Exists(packageLocation))
+ {
+ Debug.WriteLine($"Downloading {package.Name}...");
+
+ var response = await Client.GetAsync(packageUrl);
+
+ if (CancelFired)
+ return;
+
+ using (var fileStream = new FileStream(packageLocation, FileMode.CreateNew))
+ {
+ await response.Content.CopyToAsync(fileStream);
+ }
+
+ Debug.WriteLine($"Finished downloading {package.Name}!");
+ Progress += ProgressIncrement;
+ }
+ }
+
+ private void ExtractPackage(Package package)
+ {
+ if (CancelFired)
+ return;
+
+ string packageLocation = Path.Combine(Directories.Downloads, package.Signature);
+ string packageFolder = Path.Combine(VersionFolder, PackageDirectories[package.Name]);
+ string extractPath;
+
+ Debug.WriteLine($"Extracting {package.Name} to {packageFolder}...");
+
+ using (ZipArchive archive = ZipFile.OpenRead(packageLocation))
+ {
+ foreach (ZipArchiveEntry entry in archive.Entries)
+ {
+ if (CancelFired)
+ return;
+
+ if (entry.FullName.EndsWith(@"\"))
+ continue;
+
+ extractPath = Path.Combine(packageFolder, entry.FullName);
+
+ Debug.WriteLine($"[{package.Name}] Writing {extractPath}...");
+
+ Directory.CreateDirectory(Path.GetDirectoryName(extractPath));
+
+ if (File.Exists(extractPath))
+ File.Delete(extractPath);
+
+ entry.ExtractToFile(extractPath);
+ }
+ }
+ }
+
+ private void ExtractFileFromPackage(string packageName, string fileName)
+ {
+ Package? package = VersionPackageManifest.Find(x => x.Name == packageName);
+
+ if (package is null)
+ return;
+
+ DownloadPackage(package);
+
+ string packageLocation = Path.Combine(Directories.Downloads, package.Signature);
+ string packageFolder = Path.Combine(VersionFolder, PackageDirectories[package.Name]);
+
+ using (ZipArchive archive = ZipFile.OpenRead(packageLocation))
+ {
+ ZipArchiveEntry? entry = archive.Entries.Where(x => x.FullName == fileName).FirstOrDefault();
+
+ if (entry is null)
+ return;
+
+ string fileLocation = Path.Combine(packageFolder, entry.FullName);
+
+ if (File.Exists(fileLocation))
+ File.Delete(fileLocation);
+
+ entry.ExtractToFile(fileLocation);
+ }
+ }
+ #endregion
+ }
+}
diff --git a/Bloxstrap/Bootstrapper/Bootstrapper.AppInstall.cs b/Bloxstrap/Bootstrapper/Bootstrapper.AppInstall.cs
deleted file mode 100644
index 54741ed..0000000
--- a/Bloxstrap/Bootstrapper/Bootstrapper.AppInstall.cs
+++ /dev/null
@@ -1,125 +0,0 @@
-using Microsoft.Win32;
-using Bloxstrap.Helpers;
-
-namespace Bloxstrap
-{
- partial class Bootstrapper
- {
- public static void Register()
- {
- if (Program.BaseDirectory is null)
- return;
-
- RegistryKey applicationKey = Registry.CurrentUser.CreateSubKey($@"Software\{Program.ProjectName}");
-
- // new install location selected, delete old one
- string? oldInstallLocation = (string?)applicationKey.GetValue("OldInstallLocation");
- if (!String.IsNullOrEmpty(oldInstallLocation) && oldInstallLocation != Program.BaseDirectory)
- {
- try
- {
- if (Directory.Exists(oldInstallLocation))
- Directory.Delete(oldInstallLocation, true);
- }
- catch (Exception) { }
-
- applicationKey.DeleteValue("OldInstallLocation");
- }
-
- applicationKey.SetValue("InstallLocation", Program.BaseDirectory);
- applicationKey.Close();
-
- // set uninstall key
- RegistryKey uninstallKey = Registry.CurrentUser.CreateSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{Program.ProjectName}");
- uninstallKey.SetValue("DisplayIcon", $"{Program.FilePath},0");
- uninstallKey.SetValue("DisplayName", Program.ProjectName);
- uninstallKey.SetValue("InstallDate", DateTime.Now.ToString("yyyyMMdd"));
- uninstallKey.SetValue("InstallLocation", Program.BaseDirectory);
- uninstallKey.SetValue("NoRepair", 1);
- uninstallKey.SetValue("Publisher", Program.ProjectName);
- uninstallKey.SetValue("ModifyPath", $"\"{Program.FilePath}\" -preferences");
- uninstallKey.SetValue("UninstallString", $"\"{Program.FilePath}\" -uninstall");
- uninstallKey.Close();
- }
-
- public static void CheckInstall()
- {
- // check if launch uri is set to our bootstrapper
- // this doesn't go under register, so we check every launch
- // just in case the stock bootstrapper changes it back
-
- Protocol.Register("roblox", "Roblox", Program.FilePath);
- Protocol.Register("roblox-player", "Roblox", Program.FilePath);
-
- // in case the user is reinstalling
- if (File.Exists(Program.FilePath) && Program.IsFirstRun)
- File.Delete(Program.FilePath);
-
- // check to make sure bootstrapper is in the install folder
- if (!File.Exists(Program.FilePath) && Environment.ProcessPath is not null)
- File.Copy(Environment.ProcessPath, Program.FilePath);
-
- // this SHOULD go under Register(),
- // but then people who have Bloxstrap v1.0.0 installed won't have this without a reinstall
- // maybe in a later version?
- if (!Directory.Exists(Program.StartMenuDirectory))
- {
- Directory.CreateDirectory(Program.StartMenuDirectory);
-
- ShellLink.Shortcut.CreateShortcut(Program.FilePath, "", Program.FilePath, 0)
- .WriteToFile(Path.Combine(Program.StartMenuDirectory, "Play Roblox.lnk"));
-
- ShellLink.Shortcut.CreateShortcut(Program.FilePath, "-preferences", Program.FilePath, 0)
- .WriteToFile(Path.Combine(Program.StartMenuDirectory, "Configure Bloxstrap.lnk"));
- }
- }
-
- private void Uninstall()
- {
- if (Program.BaseDirectory is null)
- return;
-
- CheckIfRunning();
-
- Message = $"Uninstalling {Program.ProjectName}...";
-
- Program.SettingsManager.ShouldSave = false;
-
- // check if stock bootstrapper is still installed
- RegistryKey? bootstrapperKey = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall\roblox-player");
- if (bootstrapperKey is null)
- {
- Protocol.Unregister("roblox");
- Protocol.Unregister("roblox-player");
- }
- else
- {
- // revert launch uri handler to stock bootstrapper
-
- string bootstrapperLocation = (string?)bootstrapperKey.GetValue("InstallLocation") + "RobloxPlayerLauncher.exe";
-
- Protocol.Register("roblox", "Roblox", bootstrapperLocation);
- Protocol.Register("roblox-player", "Roblox", bootstrapperLocation);
- }
-
- try
- {
- // delete application key
- Registry.CurrentUser.DeleteSubKey($@"Software\{Program.ProjectName}");
-
- // delete start menu folder
- Directory.Delete(Program.StartMenuDirectory, true);
-
- // delete uninstall key
- Registry.CurrentUser.DeleteSubKey($@"Software\Microsoft\Windows\CurrentVersion\Uninstall\{Program.ProjectName}");
-
- // delete installation folder
- // (should delete everything except bloxstrap itself)
- Directory.Delete(Program.BaseDirectory, true);
- }
- catch (Exception) { }
-
- ShowSuccess($"{Program.ProjectName} has been uninstalled");
- }
- }
-}
diff --git a/Bloxstrap/Bootstrapper/Bootstrapper.Properties.cs b/Bloxstrap/Bootstrapper/Bootstrapper.Properties.cs
deleted file mode 100644
index bd36f05..0000000
--- a/Bloxstrap/Bootstrapper/Bootstrapper.Properties.cs
+++ /dev/null
@@ -1,130 +0,0 @@
-using Bloxstrap.Helpers.RSMM;
-
-namespace Bloxstrap
-{
- partial class Bootstrapper
- {
- private string? LaunchCommandLine;
-
- private string VersionGuid;
- private PackageManifest VersionPackageManifest;
- private FileManifest VersionFileManifest;
- private string VersionFolder;
-
- private readonly string DownloadsFolder;
- private readonly bool FreshInstall;
-
- private int ProgressIncrement;
- private bool CancelFired = false;
-
- private static readonly HttpClient Client = new();
-
- // in case a new package is added, you can find the corresponding directory
- // by opening the stock bootstrapper in a hex editor
- // TODO - there ideally should be a less static way to do this that's not hardcoded?
- private static readonly IReadOnlyDictionary PackageDirectories = new Dictionary()
- {
- { "RobloxApp.zip", @"" },
- { "shaders.zip", @"shaders\" },
- { "ssl.zip", @"ssl\" },
-
- { "content-avatar.zip", @"content\avatar\" },
- { "content-configs.zip", @"content\configs\" },
- { "content-fonts.zip", @"content\fonts\" },
- { "content-sky.zip", @"content\sky\" },
- { "content-sounds.zip", @"content\sounds\" },
- { "content-textures2.zip", @"content\textures\" },
- { "content-models.zip", @"content\models\" },
-
- { "content-textures3.zip", @"PlatformContent\pc\textures\" },
- { "content-terrain.zip", @"PlatformContent\pc\terrain\" },
- { "content-platform-fonts.zip", @"PlatformContent\pc\fonts\" },
-
- { "extracontent-luapackages.zip", @"ExtraContent\LuaPackages\" },
- { "extracontent-translations.zip", @"ExtraContent\translations\" },
- { "extracontent-models.zip", @"ExtraContent\models\" },
- { "extracontent-textures.zip", @"ExtraContent\textures\" },
- { "extracontent-places.zip", @"ExtraContent\places\" },
- };
-
- private static readonly string AppSettings =
- "\n" +
- "\n" +
- " content\n" +
- " http://www.roblox.com\n" +
- "\n";
-
- public event EventHandler CloseDialogEvent;
- public event EventHandler PromptShutdownEvent;
- public event ChangeEventHandler ShowSuccessEvent;
- public event ChangeEventHandler MessageChanged;
- public event ChangeEventHandler ProgressBarValueChanged;
- public event ChangeEventHandler ProgressBarStyleChanged;
- public event ChangeEventHandler CancelEnabledChanged;
-
- private string _message;
- private int _progress = 0;
- private ProgressBarStyle _progressStyle = ProgressBarStyle.Marquee;
- private bool _cancelEnabled = false;
-
- public string Message
- {
- get => _message;
-
- private set
- {
- if (_message == value)
- return;
-
- MessageChanged.Invoke(this, new ChangeEventArgs(value));
-
- _message = value;
- }
- }
-
- public int Progress
- {
- get => _progress;
-
- private set
- {
- if (_progress == value)
- return;
-
- ProgressBarValueChanged.Invoke(this, new ChangeEventArgs(value));
-
- _progress = value;
- }
- }
-
- public ProgressBarStyle ProgressStyle
- {
- get => _progressStyle;
-
- private set
- {
- if (_progressStyle == value)
- return;
-
- ProgressBarStyleChanged.Invoke(this, new ChangeEventArgs(value));
-
- _progressStyle = value;
- }
- }
-
- public bool CancelEnabled
- {
- get => _cancelEnabled;
-
- private set
- {
- if (_cancelEnabled == value)
- return;
-
- CancelEnabledChanged.Invoke(this, new ChangeEventArgs(value));
-
- _cancelEnabled = value;
- }
- }
- }
-}
diff --git a/Bloxstrap/Bootstrapper/Bootstrapper.RobloxInstall.cs b/Bloxstrap/Bootstrapper/Bootstrapper.RobloxInstall.cs
deleted file mode 100644
index 151a40d..0000000
--- a/Bloxstrap/Bootstrapper/Bootstrapper.RobloxInstall.cs
+++ /dev/null
@@ -1,243 +0,0 @@
-using System.Diagnostics;
-using System.IO.Compression;
-
-using Bloxstrap.Helpers;
-using Bloxstrap.Helpers.RSMM;
-
-namespace Bloxstrap
-{
- partial class Bootstrapper
- {
- private async Task CheckLatestVersion()
- {
- if (Program.BaseDirectory is null)
- return;
-
- Message = "Connecting to Roblox...";
-
- VersionGuid = await Client.GetStringAsync($"{Program.BaseUrlSetup}/version");
- VersionFolder = Path.Combine(Program.BaseDirectory, "Versions", VersionGuid);
- VersionPackageManifest = await PackageManifest.Get(VersionGuid);
- VersionFileManifest = await FileManifest.Get(VersionGuid);
- }
-
- private async Task InstallLatestVersion()
- {
- if (Program.BaseDirectory is null)
- return;
-
- CheckIfRunning();
-
- if (FreshInstall)
- Message = "Installing Roblox...";
- else
- Message = "Upgrading Roblox...";
-
- Directory.CreateDirectory(Program.BaseDirectory);
-
- CancelEnabled = true;
-
- // i believe the original bootstrapper bases the progress bar off zip
- // extraction progress, but here i'm doing package download progress
-
- ProgressStyle = ProgressBarStyle.Continuous;
-
- ProgressIncrement = (int)Math.Floor((decimal)1 / VersionPackageManifest.Count * 100);
-
- Directory.CreateDirectory(Path.Combine(Program.BaseDirectory, "Downloads"));
-
- foreach (Package package in VersionPackageManifest)
- {
- // no await, download all the packages at once
- DownloadPackage(package);
- }
-
- do
- {
- // wait for download to finish (and also round off the progress bar if needed)
-
- if (Progress == ProgressIncrement * VersionPackageManifest.Count)
- Progress = 100;
-
- await Task.Delay(1000);
- }
- while (Progress != 100);
-
- ProgressStyle = ProgressBarStyle.Marquee;
-
- Debug.WriteLine("Finished downloading");
-
- Directory.CreateDirectory(Path.Combine(Program.BaseDirectory, "Versions"));
-
- foreach (Package package in VersionPackageManifest)
- {
- // extract all the packages at once (shouldn't be too heavy on cpu?)
- ExtractPackage(package);
- }
-
- Debug.WriteLine("Finished extracting packages");
-
- Message = "Configuring Roblox...";
-
- string appSettingsLocation = Path.Combine(VersionFolder, "AppSettings.xml");
- await File.WriteAllTextAsync(appSettingsLocation, AppSettings);
-
- if (!FreshInstall)
- {
- // let's take this opportunity to delete any packages we don't need anymore
- foreach (string filename in Directory.GetFiles(DownloadsFolder))
- {
- if (!VersionPackageManifest.Exists(package => filename.Contains(package.Signature)))
- File.Delete(filename);
- }
-
- if (VersionGuid != Program.Settings.VersionGuid)
- {
- // and also to delete our old version folder
- Directory.Delete(Path.Combine(Program.BaseDirectory, "Versions", Program.Settings.VersionGuid), true);
- }
- }
-
- CancelEnabled = false;
-
- Program.Settings.VersionGuid = VersionGuid;
- }
-
- private async void ApplyModifications()
- {
- // i guess we can just assume that if the hash does not match the manifest, then it's a mod
- // probably not the best way to do this? don't think file corruption is that much of a worry here
-
- // TODO - i'm thinking i could have a manifest on my website like rbxManifest.txt
- // for integrity checking and to quickly fix/alter stuff (like ouch.ogg being renamed)
- // but that probably wouldn't be great to check on every run in case my webserver ever goes down
- // interesting idea nonetheless, might add it sometime
-
- // TODO - i'm hoping i can take this idea of content mods much further
- // for stuff like easily installing (community-created?) texture/shader/audio mods
- // but for now, let's just keep it at this
-
- await ModifyDeathSound();
- await ModifyMouseCursor();
- }
-
- private async void DownloadPackage(Package package)
- {
- string packageUrl = $"{Program.BaseUrlSetup}/{VersionGuid}-{package.Name}";
- string packageLocation = Path.Combine(DownloadsFolder, package.Signature);
- string robloxPackageLocation = Path.Combine(Program.LocalAppData, "Roblox", "Downloads", package.Signature);
-
- if (File.Exists(packageLocation))
- {
- FileInfo file = new(packageLocation);
-
- string calculatedMD5 = Utilities.CalculateMD5(packageLocation);
- if (calculatedMD5 != package.Signature)
- {
- Debug.WriteLine($"{package.Name} is corrupted ({calculatedMD5} != {package.Signature})! Deleting and re-downloading...");
- file.Delete();
- }
- else
- {
- Debug.WriteLine($"{package.Name} is already downloaded, skipping...");
- Progress += ProgressIncrement;
- return;
- }
- }
- else if (File.Exists(robloxPackageLocation))
- {
- // let's cheat! if the stock bootstrapper already previously downloaded the file,
- // then we can just copy the one from there
-
- Debug.WriteLine($"Found existing version of {package.Name} ({robloxPackageLocation})! Copying to Downloads folder...");
- File.Copy(robloxPackageLocation, packageLocation);
- Progress += ProgressIncrement;
- return;
- }
-
- if (!File.Exists(packageLocation))
- {
- Debug.WriteLine($"Downloading {package.Name}...");
-
- var response = await Client.GetAsync(packageUrl);
-
- if (CancelFired)
- return;
-
- using (var fileStream = new FileStream(packageLocation, FileMode.CreateNew))
- {
- await response.Content.CopyToAsync(fileStream);
- }
-
- Debug.WriteLine($"Finished downloading {package.Name}!");
- Progress += ProgressIncrement;
- }
- }
-
- private void ExtractPackage(Package package)
- {
- if (CancelFired)
- return;
-
- string packageLocation = Path.Combine(DownloadsFolder, package.Signature);
- string packageFolder = Path.Combine(VersionFolder, PackageDirectories[package.Name]);
- string extractPath;
-
- Debug.WriteLine($"Extracting {package.Name} to {packageFolder}...");
-
- using (ZipArchive archive = ZipFile.OpenRead(packageLocation))
- {
- foreach (ZipArchiveEntry entry in archive.Entries)
- {
- if (CancelFired)
- return;
-
- if (entry.FullName.EndsWith(@"\"))
- continue;
-
- extractPath = Path.Combine(packageFolder, entry.FullName);
-
- Debug.WriteLine($"[{package.Name}] Writing {extractPath}...");
-
- Directory.CreateDirectory(Path.GetDirectoryName(extractPath));
-
- if (File.Exists(extractPath))
- File.Delete(extractPath);
-
- entry.ExtractToFile(extractPath);
- }
- }
- }
-
- private void ExtractFilesFromPackage(string packageName, string[] files)
- {
- Package? package = VersionPackageManifest.Find(x => x.Name == packageName);
-
- if (package is null)
- return;
-
- DownloadPackage(package);
-
- string packageLocation = Path.Combine(DownloadsFolder, package.Signature);
- string packageFolder = Path.Combine(VersionFolder, PackageDirectories[package.Name]);
-
- using (ZipArchive archive = ZipFile.OpenRead(packageLocation))
- {
- foreach (string fileName in files)
- {
- ZipArchiveEntry? entry = archive.Entries.Where(x => x.FullName == fileName).FirstOrDefault();
-
- if (entry is null)
- return;
-
- string fileLocation = Path.Combine(packageFolder, entry.FullName);
-
- if (File.Exists(fileLocation))
- File.Delete(fileLocation);
-
- entry.ExtractToFile(fileLocation);
- }
- }
- }
- }
-}
diff --git a/Bloxstrap/Bootstrapper/Bootstrapper.RobloxModifications.cs b/Bloxstrap/Bootstrapper/Bootstrapper.RobloxModifications.cs
deleted file mode 100644
index b5545d5..0000000
--- a/Bloxstrap/Bootstrapper/Bootstrapper.RobloxModifications.cs
+++ /dev/null
@@ -1,64 +0,0 @@
-using Bloxstrap.Helpers;
-
-namespace Bloxstrap
-{
- partial class Bootstrapper
- {
- private async Task ModifyDeathSound()
- {
- string fileContentName = "ouch.ogg";
- string fileContentLocation = "content\\sounds\\ouch.ogg";
- string fileLocation = Path.Combine(VersionFolder, fileContentLocation);
-
- string officialHash = VersionFileManifest[fileContentLocation];
- string currentHash = Utilities.CalculateMD5(fileLocation);
-
- if (Program.Settings.UseOldDeathSound && currentHash == officialHash)
- {
- // let's get the old one!
-
- var response = await Client.GetAsync($"{Program.BaseUrlApplication}/mods/{fileContentLocation}");
-
- if (File.Exists(fileLocation))
- File.Delete(fileLocation);
-
- using (var fileStream = new FileStream(fileLocation, FileMode.CreateNew))
- {
- await response.Content.CopyToAsync(fileStream);
- }
- }
- else if (!Program.Settings.UseOldDeathSound && currentHash != officialHash)
- {
- // who's lame enough to ever do this?
- // well, we need to re-extract the one that's in the content-sounds.zip package
-
- string[] files = { fileContentName };
- ExtractFilesFromPackage("content-sounds.zip", files);
- }
- }
-
- private async Task ModifyMouseCursor()
- {
- string baseFolder = Path.Combine(VersionFolder, "content\\textures\\");
-
- string arrowCursor = "Cursors\\KeyboardMouse\\ArrowCursor.png";
- string arrowFarCursor = "Cursors\\KeyboardMouse\\ArrowFarCursor.png";
-
- string officialHash = VersionFileManifest["content\\textures\\Cursors\\KeyboardMouse\\ArrowCursor.png"];
- string currentHash = Utilities.CalculateMD5(Path.Combine(baseFolder, arrowCursor));
-
- if (Program.Settings.UseOldMouseCursor && currentHash == officialHash)
- {
- // the old cursors are actually still in the content\textures\ folder, so we can just get them from there
-
- File.Copy(Path.Combine(baseFolder, "ArrowCursor.png"), Path.Combine(baseFolder, arrowCursor), true);
- File.Copy(Path.Combine(baseFolder, "ArrowFarCursor.png"), Path.Combine(baseFolder, arrowFarCursor), true);
- }
- else if (!Program.Settings.UseOldMouseCursor && currentHash != officialHash)
- {
- string[] files = { arrowCursor, arrowFarCursor };
- ExtractFilesFromPackage("content-textures2.zip", files);
- }
- }
- }
-}
diff --git a/Bloxstrap/Bootstrapper/Bootstrapper.cs b/Bloxstrap/Bootstrapper/Bootstrapper.cs
deleted file mode 100644
index 3fa20e4..0000000
--- a/Bloxstrap/Bootstrapper/Bootstrapper.cs
+++ /dev/null
@@ -1,187 +0,0 @@
-using System.Diagnostics;
-
-using Bloxstrap.Enums;
-using Bloxstrap.Dialogs.BootstrapperStyles;
-using Bloxstrap.Helpers;
-using Bloxstrap.Helpers.RSMM;
-
-namespace Bloxstrap
-{
- public partial class Bootstrapper
- {
- public Bootstrapper()
- {
- if (Program.BaseDirectory is null)
- return;
-
- FreshInstall = String.IsNullOrEmpty(Program.Settings.VersionGuid);
- DownloadsFolder = Path.Combine(Program.BaseDirectory, "Downloads");
- Client.Timeout = TimeSpan.FromMinutes(10);
- }
-
- public void Initialize(BootstrapperStyle bootstrapperStyle, string? launchCommandLine = null)
- {
- LaunchCommandLine = launchCommandLine;
-
- switch (bootstrapperStyle)
- {
- case BootstrapperStyle.VistaDialog:
- Application.Run(new VistaDialog(this));
- break;
-
- case BootstrapperStyle.LegacyDialog2009:
- Application.Run(new LegacyDialog2009(this));
- break;
-
- case BootstrapperStyle.LegacyDialog2011:
- Application.Run(new LegacyDialog2011(this));
- break;
-
- case BootstrapperStyle.ProgressDialog:
- Application.Run(new ProgressDialog(this));
- break;
-
- case BootstrapperStyle.ProgressDialogDark:
- Application.Run(new ProgressDialogDark(this));
- break;
- }
- }
-
- public async Task Run()
- {
- if (LaunchCommandLine == "-uninstall")
- {
- Uninstall();
- return;
- }
-
- await CheckLatestVersion();
-
- if (!Directory.Exists(VersionFolder) || Program.Settings.VersionGuid != VersionGuid)
- {
- Debug.WriteLineIf(!Directory.Exists(VersionFolder), $"Installing latest version (!Directory.Exists({VersionFolder}))");
- Debug.WriteLineIf(Program.Settings.VersionGuid != VersionGuid, $"Installing latest version ({Program.Settings.VersionGuid} != {VersionGuid})");
-
- await InstallLatestVersion();
- }
-
- // yes, doing this for every start is stupid, but the death sound mod is dynamically toggleable after all
- ApplyModifications();
-
- if (Program.IsFirstRun)
- Program.SettingsManager.ShouldSave = true;
-
- if (Program.IsFirstRun || FreshInstall)
- Register();
-
- CheckInstall();
-
- await StartRoblox();
-
- Program.Exit();
- }
-
- private void CheckIfRunning()
- {
- Process[] processes = Process.GetProcessesByName("RobloxPlayerBeta");
-
- if (processes.Length > 0)
- PromptShutdown();
-
- try
- {
- // try/catch just in case process was closed before prompt was answered
-
- foreach (Process process in processes)
- {
- process.CloseMainWindow();
- process.Close();
- }
- }
- catch (Exception) { }
- }
-
- private async Task StartRoblox()
- {
- string startEventName = Program.ProjectName.Replace(" ", "") + "StartEvent";
-
- Message = "Starting Roblox...";
-
- // launch time isn't really required for all launches, but it's usually just safest to do this
- LaunchCommandLine += " --launchtime=" + DateTimeOffset.Now.ToUnixTimeSeconds() + " -startEvent " + startEventName;
-
- using (SystemEvent startEvent = new(startEventName))
- {
- Process gameClient = Process.Start(Path.Combine(VersionFolder, "RobloxPlayerBeta.exe"), LaunchCommandLine);
-
- bool startEventFired = await startEvent.WaitForEvent();
-
- startEvent.Close();
-
- if (!startEventFired)
- return;
-
- // event fired, wait for 6 seconds then close
- await Task.Delay(6000);
-
- // now we move onto handling rich presence
- // except beta app launch since we have to rely strictly on website launch
- if (!Program.Settings.UseDiscordRichPresence || LaunchCommandLine.Contains("--app"))
- return;
-
- // probably not the most ideal way to do this
- string? placeId = Utilities.GetKeyValue(LaunchCommandLine, "placeId=", '&');
-
- if (placeId is null)
- return;
-
- // keep bloxstrap open to handle rich presence
- using (DiscordRichPresence richPresence = new())
- {
- bool presenceSet = await richPresence.SetPresence(placeId);
-
- if (!presenceSet)
- return;
-
- CloseDialog();
-
- await gameClient.WaitForExitAsync();
- }
- }
- }
-
- public void CancelButtonClicked()
- {
- if (Program.BaseDirectory is null)
- return;
-
- CancelFired = true;
-
- try
- {
- if (Program.IsFirstRun)
- Directory.Delete(Program.BaseDirectory, true);
- else if (Directory.Exists(VersionFolder))
- Directory.Delete(VersionFolder, true);
- }
- catch (Exception) { }
-
- Program.Exit();
- }
-
- private void ShowSuccess(string message)
- {
- ShowSuccessEvent.Invoke(this, new ChangeEventArgs(message));
- }
-
- private void PromptShutdown()
- {
- PromptShutdownEvent.Invoke(this, new EventArgs());
- }
-
- private void CloseDialog()
- {
- CloseDialogEvent.Invoke(this, new EventArgs());
- }
- }
-}
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs b/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs
index 9f9f2a8..912fd24 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/BootstrapperStyleForm.cs
@@ -1,11 +1,9 @@
-using System.Diagnostics;
-
-using Bloxstrap.Helpers;
+using Bloxstrap.Helpers;
using Bloxstrap.Helpers.RSMM;
namespace Bloxstrap.Dialogs.BootstrapperStyles
{
- public class BootstrapperStyleForm : Form, IBootstrapperStyle
+ public class BootstrapperStyleForm : Form, IBootstrapperDialog
{
public Bootstrapper? Bootstrapper { get; set; }
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/IBootstrapperStyle.cs b/Bloxstrap/Dialogs/BootstrapperStyles/IBootstrapperDialog.cs
similarity index 95%
rename from Bloxstrap/Dialogs/BootstrapperStyles/IBootstrapperStyle.cs
rename to Bloxstrap/Dialogs/BootstrapperStyles/IBootstrapperDialog.cs
index 25cbe63..de43d71 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/IBootstrapperStyle.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/IBootstrapperDialog.cs
@@ -2,7 +2,7 @@
namespace Bloxstrap.Dialogs.BootstrapperStyles
{
- interface IBootstrapperStyle
+ public interface IBootstrapperDialog
{
Bootstrapper? Bootstrapper { get; set; }
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.Designer.cs b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.Designer.cs
index 7e4e43c..9e57fcc 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.Designer.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.Designer.cs
@@ -80,6 +80,7 @@
this.Name = "LegacyDialog2009";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "LegacyDialog2009";
+ this.Load += new System.EventHandler(this.LegacyDialog2009_Load);
this.ResumeLayout(false);
}
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.cs b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.cs
index 23d7ca4..101d528 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2009.cs
@@ -37,5 +37,10 @@ namespace Bloxstrap.Dialogs.BootstrapperStyles
SetupDialog();
}
+
+ private void LegacyDialog2009_Load(object sender, EventArgs e)
+ {
+ this.Activate();
+ }
}
}
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.Designer.cs b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.Designer.cs
index d131290..d552f0d 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.Designer.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.Designer.cs
@@ -75,7 +75,7 @@
this.buttonCancel.Visible = false;
this.buttonCancel.Click += new System.EventHandler(this.ButtonCancel_Click);
//
- // LegacyDialog
+ // LegacyDialog2011
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 17F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
@@ -93,6 +93,7 @@
this.Name = "LegacyDialog2011";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "LegacyDialog2011";
+ this.Load += new System.EventHandler(this.LegacyDialog2011_Load);
((System.ComponentModel.ISupportInitialize)(this.IconBox)).EndInit();
this.ResumeLayout(false);
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.cs b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.cs
index f0144b6..fde89c0 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/LegacyDialog2011.cs
@@ -41,5 +41,10 @@ namespace Bloxstrap.Dialogs.BootstrapperStyles
SetupDialog();
}
+
+ private void LegacyDialog2011_Load(object sender, EventArgs e)
+ {
+ this.Activate();
+ }
}
}
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.Designer.cs b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.Designer.cs
index e53820a..d884efb 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.Designer.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.Designer.cs
@@ -108,6 +108,7 @@
this.Name = "ProgressDialog";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "ProgressDialog";
+ this.Load += new System.EventHandler(this.ProgressDialog_Load);
((System.ComponentModel.ISupportInitialize)(this.IconBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.buttonCancel)).EndInit();
this.panel1.ResumeLayout(false);
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.cs b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.cs
index 2dccbfc..00e4d7d 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialog.cs
@@ -50,5 +50,10 @@ namespace Bloxstrap.Dialogs.BootstrapperStyles
{
this.buttonCancel.Image = Properties.Resources.CancelButton;
}
+
+ private void ProgressDialog_Load(object sender, EventArgs e)
+ {
+ this.Activate();
+ }
}
}
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.Designer.cs b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.Designer.cs
index 59b989b..f08c732 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.Designer.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.Designer.cs
@@ -109,6 +109,7 @@
this.Name = "ProgressDialogDark";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "ProgressDialog";
+ this.Load += new System.EventHandler(this.ProgressDialogDark_Load);
((System.ComponentModel.ISupportInitialize)(this.IconBox)).EndInit();
((System.ComponentModel.ISupportInitialize)(this.buttonCancel)).EndInit();
this.panel1.ResumeLayout(false);
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.cs b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.cs
index 76e3399..3a8b82c 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/ProgressDialogDark.cs
@@ -50,5 +50,10 @@ namespace Bloxstrap.Dialogs.BootstrapperStyles
{
this.buttonCancel.Image = Properties.Resources.DarkCancelButton;
}
+
+ private void ProgressDialogDark_Load(object sender, EventArgs e)
+ {
+ this.Activate();
+ }
}
}
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.Designer.cs b/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.Designer.cs
index b11f2c8..defd569 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.Designer.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.Designer.cs
@@ -30,15 +30,17 @@
{
this.SuspendLayout();
//
- // TestDialog
+ // VistaDialog
//
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(0, 0);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "VistaDialog";
+ this.Opacity = 0D;
this.ShowInTaskbar = false;
this.Text = "VistaDialog";
+ this.WindowState = System.Windows.Forms.FormWindowState.Minimized;
this.Load += new System.EventHandler(this.TestDialog_Load);
this.ResumeLayout(false);
diff --git a/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.cs b/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.cs
index e36b065..5a97ea5 100644
--- a/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.cs
+++ b/Bloxstrap/Dialogs/BootstrapperStyles/VistaDialog.cs
@@ -163,7 +163,6 @@ namespace Bloxstrap.Dialogs.BootstrapperStyles
private void TestDialog_Load(object sender, EventArgs e)
{
- this.Hide();
TaskDialog.ShowDialog(Dialog);
}
}
diff --git a/Bloxstrap/Dialogs/Preferences.Designer.cs b/Bloxstrap/Dialogs/Preferences.Designer.cs
index b505db7..0ac8886 100644
--- a/Bloxstrap/Dialogs/Preferences.Designer.cs
+++ b/Bloxstrap/Dialogs/Preferences.Designer.cs
@@ -32,6 +32,10 @@
this.label1 = new System.Windows.Forms.Label();
this.Tabs = new System.Windows.Forms.TabControl();
this.DialogTab = new System.Windows.Forms.TabPage();
+ this.groupBox1 = new System.Windows.Forms.GroupBox();
+ this.RFUWebsite = new System.Windows.Forms.LinkLabel();
+ this.ToggleRFUAutoclose = new System.Windows.Forms.CheckBox();
+ this.ToggleRFUEnabled = new System.Windows.Forms.CheckBox();
this.groupBox5 = new System.Windows.Forms.GroupBox();
this.ToggleRPCButtons = new System.Windows.Forms.CheckBox();
this.ToggleDiscordRichPresence = new System.Windows.Forms.CheckBox();
@@ -42,6 +46,8 @@
this.StyleSelection = new System.Windows.Forms.ListBox();
this.InstallationTab = new System.Windows.Forms.TabPage();
this.groupBox4 = new System.Windows.Forms.GroupBox();
+ this.LabelModFolderInstall = new System.Windows.Forms.Label();
+ this.ButtonOpenModFolder = new System.Windows.Forms.Button();
this.ToggleMouseCursor = new System.Windows.Forms.CheckBox();
this.ToggleDeathSound = new System.Windows.Forms.CheckBox();
this.GroupBoxInstallLocation = new System.Windows.Forms.GroupBox();
@@ -49,11 +55,13 @@
this.InstallLocation = new System.Windows.Forms.TextBox();
this.SaveButton = new System.Windows.Forms.Button();
this.panel1 = new System.Windows.Forms.Panel();
+ this.ToggleCheckForUpdates = new System.Windows.Forms.CheckBox();
this.PreviewButton = new System.Windows.Forms.Button();
this.InstallLocationBrowseDialog = new System.Windows.Forms.FolderBrowserDialog();
this.InfoTooltip = new System.Windows.Forms.ToolTip(this.components);
this.Tabs.SuspendLayout();
this.DialogTab.SuspendLayout();
+ this.groupBox1.SuspendLayout();
this.groupBox5.SuspendLayout();
this.groupBox3.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.IconPreview)).BeginInit();
@@ -86,6 +94,7 @@
//
// DialogTab
//
+ this.DialogTab.Controls.Add(this.groupBox1);
this.DialogTab.Controls.Add(this.groupBox5);
this.DialogTab.Controls.Add(this.groupBox3);
this.DialogTab.Controls.Add(this.groupBox2);
@@ -97,13 +106,70 @@
this.DialogTab.Text = "Bootstrapper";
this.DialogTab.UseVisualStyleBackColor = true;
//
+ // groupBox1
+ //
+ this.groupBox1.Controls.Add(this.RFUWebsite);
+ this.groupBox1.Controls.Add(this.ToggleRFUAutoclose);
+ this.groupBox1.Controls.Add(this.ToggleRFUEnabled);
+ this.groupBox1.Location = new System.Drawing.Point(192, 146);
+ this.groupBox1.Name = "groupBox1";
+ this.groupBox1.Size = new System.Drawing.Size(235, 67);
+ this.groupBox1.TabIndex = 8;
+ this.groupBox1.TabStop = false;
+ this.groupBox1.Text = "FPS Unlocker";
+ //
+ // RFUWebsite
+ //
+ this.RFUWebsite.BackColor = System.Drawing.Color.White;
+ this.RFUWebsite.Cursor = System.Windows.Forms.Cursors.Hand;
+ this.RFUWebsite.LinkBehavior = System.Windows.Forms.LinkBehavior.HoverUnderline;
+ this.RFUWebsite.Location = new System.Drawing.Point(174, 0);
+ this.RFUWebsite.Margin = new System.Windows.Forms.Padding(0);
+ this.RFUWebsite.Name = "RFUWebsite";
+ this.RFUWebsite.Size = new System.Drawing.Size(55, 18);
+ this.RFUWebsite.TabIndex = 2;
+ this.RFUWebsite.TabStop = true;
+ this.RFUWebsite.Tag = "";
+ this.RFUWebsite.Text = "(website)";
+ this.RFUWebsite.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.RFUWebsite_LinkClicked);
+ //
+ // ToggleRFUAutoclose
+ //
+ this.ToggleRFUAutoclose.AutoSize = true;
+ this.ToggleRFUAutoclose.Checked = true;
+ this.ToggleRFUAutoclose.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.ToggleRFUAutoclose.Location = new System.Drawing.Point(9, 40);
+ this.ToggleRFUAutoclose.Name = "ToggleRFUAutoclose";
+ this.ToggleRFUAutoclose.Size = new System.Drawing.Size(209, 19);
+ this.ToggleRFUAutoclose.TabIndex = 1;
+ this.ToggleRFUAutoclose.Text = "Automatically close on Roblox exit";
+ this.InfoTooltip.SetToolTip(this.ToggleRFUAutoclose, "If enabled, rbxfpsunlocker will automatically close when Roblox is closed.");
+ this.ToggleRFUAutoclose.UseVisualStyleBackColor = true;
+ this.ToggleRFUAutoclose.CheckedChanged += new System.EventHandler(this.ToggleRFUAutoclose_CheckedChanged);
+ //
+ // ToggleRFUEnabled
+ //
+ this.ToggleRFUEnabled.AutoSize = true;
+ this.ToggleRFUEnabled.Checked = true;
+ this.ToggleRFUEnabled.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.ToggleRFUEnabled.Location = new System.Drawing.Point(9, 19);
+ this.ToggleRFUEnabled.Name = "ToggleRFUEnabled";
+ this.ToggleRFUEnabled.Size = new System.Drawing.Size(127, 19);
+ this.ToggleRFUEnabled.TabIndex = 0;
+ this.ToggleRFUEnabled.Text = "Use rbxfpsunlocker";
+ this.InfoTooltip.SetToolTip(this.ToggleRFUEnabled, "If enabled, rbxfpsunlocker is downloaded.\r\nWhen Roblox is started, rbxfpsunlocker" +
+ " will automatically start too, \r\nbeing minimized to your system tray by default." +
+ "");
+ this.ToggleRFUEnabled.UseVisualStyleBackColor = true;
+ this.ToggleRFUEnabled.CheckedChanged += new System.EventHandler(this.ToggleRFUEnabled_CheckedChanged);
+ //
// groupBox5
//
this.groupBox5.Controls.Add(this.ToggleRPCButtons);
this.groupBox5.Controls.Add(this.ToggleDiscordRichPresence);
this.groupBox5.Location = new System.Drawing.Point(5, 146);
this.groupBox5.Name = "groupBox5";
- this.groupBox5.Size = new System.Drawing.Size(422, 67);
+ this.groupBox5.Size = new System.Drawing.Size(179, 67);
this.groupBox5.TabIndex = 7;
this.groupBox5.TabStop = false;
this.groupBox5.Text = "Discord Rich Presence";
@@ -113,9 +179,11 @@
this.ToggleRPCButtons.AutoSize = true;
this.ToggleRPCButtons.Location = new System.Drawing.Point(9, 40);
this.ToggleRPCButtons.Name = "ToggleRPCButtons";
- this.ToggleRPCButtons.Size = new System.Drawing.Size(196, 19);
+ this.ToggleRPCButtons.Size = new System.Drawing.Size(155, 19);
this.ToggleRPCButtons.TabIndex = 1;
- this.ToggleRPCButtons.Text = "Hide activity interaction buttons";
+ this.ToggleRPCButtons.Text = "Hide interaction buttons";
+ this.InfoTooltip.SetToolTip(this.ToggleRPCButtons, "Choose whether the buttons to play/view game details should be hidden from your a" +
+ "ctivity status.");
this.ToggleRPCButtons.UseVisualStyleBackColor = true;
this.ToggleRPCButtons.CheckedChanged += new System.EventHandler(this.ToggleRPCButtons_CheckedChanged);
//
@@ -129,6 +197,9 @@
this.ToggleDiscordRichPresence.Size = new System.Drawing.Size(129, 19);
this.ToggleDiscordRichPresence.TabIndex = 0;
this.ToggleDiscordRichPresence.Text = "Show game activity";
+ this.InfoTooltip.SetToolTip(this.ToggleDiscordRichPresence, "Choose whether to show what game you\'re playing on your Discord activity status.\r" +
+ "\nThis will only work when you launch a game from the website, and is not support" +
+ "ed in the Beta App.");
this.ToggleDiscordRichPresence.UseVisualStyleBackColor = true;
this.ToggleDiscordRichPresence.CheckedChanged += new System.EventHandler(this.ToggleDiscordRichPresence_CheckedChanged);
//
@@ -161,6 +232,7 @@
this.IconSelection.Name = "IconSelection";
this.IconSelection.Size = new System.Drawing.Size(100, 109);
this.IconSelection.TabIndex = 4;
+ this.InfoTooltip.SetToolTip(this.IconSelection, "Choose what icon the bootstrapper should use.");
this.IconSelection.SelectedIndexChanged += new System.EventHandler(this.IconSelection_SelectedIndexChanged);
//
// groupBox2
@@ -181,6 +253,8 @@
this.StyleSelection.Name = "StyleSelection";
this.StyleSelection.Size = new System.Drawing.Size(161, 109);
this.StyleSelection.TabIndex = 3;
+ this.InfoTooltip.SetToolTip(this.StyleSelection, "Choose how the bootstrapper dialog should look.\r\nYou can use the \'Preview\' button" +
+ " to preview the bootstrapper look.");
this.StyleSelection.SelectedIndexChanged += new System.EventHandler(this.StyleSelection_SelectedIndexChanged);
//
// InstallationTab
@@ -197,15 +271,40 @@
//
// groupBox4
//
+ this.groupBox4.Controls.Add(this.LabelModFolderInstall);
+ this.groupBox4.Controls.Add(this.ButtonOpenModFolder);
this.groupBox4.Controls.Add(this.ToggleMouseCursor);
this.groupBox4.Controls.Add(this.ToggleDeathSound);
this.groupBox4.Location = new System.Drawing.Point(5, 60);
this.groupBox4.Name = "groupBox4";
- this.groupBox4.Size = new System.Drawing.Size(422, 65);
+ this.groupBox4.Size = new System.Drawing.Size(422, 95);
this.groupBox4.TabIndex = 2;
this.groupBox4.TabStop = false;
this.groupBox4.Text = "Modifications";
//
+ // LabelModFolderInstall
+ //
+ this.LabelModFolderInstall.AutoSize = true;
+ this.LabelModFolderInstall.Location = new System.Drawing.Point(6, 67);
+ this.LabelModFolderInstall.Margin = new System.Windows.Forms.Padding(0);
+ this.LabelModFolderInstall.Name = "LabelModFolderInstall";
+ this.LabelModFolderInstall.Size = new System.Drawing.Size(329, 15);
+ this.LabelModFolderInstall.TabIndex = 7;
+ this.LabelModFolderInstall.Text = "Other modifications can be added once Bloxstrap is installed.";
+ this.LabelModFolderInstall.Visible = false;
+ //
+ // ButtonOpenModFolder
+ //
+ this.ButtonOpenModFolder.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
+ this.ButtonOpenModFolder.Location = new System.Drawing.Point(8, 62);
+ this.ButtonOpenModFolder.Name = "ButtonOpenModFolder";
+ this.ButtonOpenModFolder.Size = new System.Drawing.Size(122, 25);
+ this.ButtonOpenModFolder.TabIndex = 6;
+ this.ButtonOpenModFolder.Text = "Open Mod Folder";
+ this.InfoTooltip.SetToolTip(this.ButtonOpenModFolder, "Open the folder for applying Roblox client modifications.");
+ this.ButtonOpenModFolder.UseVisualStyleBackColor = true;
+ this.ButtonOpenModFolder.Click += new System.EventHandler(this.ButtonOpenModFolder_Click);
+ //
// ToggleMouseCursor
//
this.ToggleMouseCursor.AutoSize = true;
@@ -246,9 +345,9 @@
// InstallLocationBrowseButton
//
this.InstallLocationBrowseButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
- this.InstallLocationBrowseButton.Location = new System.Drawing.Point(328, 20);
+ this.InstallLocationBrowseButton.Location = new System.Drawing.Point(335, 20);
this.InstallLocationBrowseButton.Name = "InstallLocationBrowseButton";
- this.InstallLocationBrowseButton.Size = new System.Drawing.Size(86, 25);
+ this.InstallLocationBrowseButton.Size = new System.Drawing.Size(79, 25);
this.InstallLocationBrowseButton.TabIndex = 5;
this.InstallLocationBrowseButton.Text = "Browse...";
this.InstallLocationBrowseButton.UseVisualStyleBackColor = true;
@@ -260,8 +359,10 @@
this.InstallLocation.Location = new System.Drawing.Point(9, 21);
this.InstallLocation.MaxLength = 255;
this.InstallLocation.Name = "InstallLocation";
- this.InstallLocation.Size = new System.Drawing.Size(312, 23);
+ this.InstallLocation.Size = new System.Drawing.Size(319, 23);
this.InstallLocation.TabIndex = 4;
+ this.InfoTooltip.SetToolTip(this.InstallLocation, "Choose where Bloxstrap should install to.\r\nThis is useful if you typically instal" +
+ "l all your games to a separate storage drive.");
//
// SaveButton
//
@@ -279,6 +380,7 @@
this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.panel1.BackColor = System.Drawing.SystemColors.Control;
+ this.panel1.Controls.Add(this.ToggleCheckForUpdates);
this.panel1.Controls.Add(this.PreviewButton);
this.panel1.Controls.Add(this.SaveButton);
this.panel1.Location = new System.Drawing.Point(-1, 298);
@@ -286,6 +388,19 @@
this.panel1.Size = new System.Drawing.Size(466, 42);
this.panel1.TabIndex = 6;
//
+ // ToggleCheckForUpdates
+ //
+ this.ToggleCheckForUpdates.AutoSize = true;
+ this.ToggleCheckForUpdates.Checked = true;
+ this.ToggleCheckForUpdates.CheckState = System.Windows.Forms.CheckState.Checked;
+ this.ToggleCheckForUpdates.Location = new System.Drawing.Point(14, 12);
+ this.ToggleCheckForUpdates.Name = "ToggleCheckForUpdates";
+ this.ToggleCheckForUpdates.Size = new System.Drawing.Size(179, 19);
+ this.ToggleCheckForUpdates.TabIndex = 7;
+ this.ToggleCheckForUpdates.Text = "Check for updates on startup";
+ this.ToggleCheckForUpdates.UseVisualStyleBackColor = true;
+ this.ToggleCheckForUpdates.CheckedChanged += new System.EventHandler(this.ToggleCheckForUpdates_CheckedChanged);
+ //
// PreviewButton
//
this.PreviewButton.Font = new System.Drawing.Font("Segoe UI", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point);
@@ -318,8 +433,11 @@
this.Name = "Preferences";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Preferences";
+ this.Load += new System.EventHandler(this.Preferences_Load);
this.Tabs.ResumeLayout(false);
this.DialogTab.ResumeLayout(false);
+ this.groupBox1.ResumeLayout(false);
+ this.groupBox1.PerformLayout();
this.groupBox5.ResumeLayout(false);
this.groupBox5.PerformLayout();
this.groupBox3.ResumeLayout(false);
@@ -331,6 +449,7 @@
this.GroupBoxInstallLocation.ResumeLayout(false);
this.GroupBoxInstallLocation.PerformLayout();
this.panel1.ResumeLayout(false);
+ this.panel1.PerformLayout();
this.ResumeLayout(false);
}
@@ -360,5 +479,12 @@
private ToolTip InfoTooltip;
private CheckBox ToggleMouseCursor;
private CheckBox ToggleRPCButtons;
+ private GroupBox groupBox1;
+ private LinkLabel RFUWebsite;
+ private CheckBox ToggleRFUAutoclose;
+ private CheckBox ToggleRFUEnabled;
+ private CheckBox ToggleCheckForUpdates;
+ private Button ButtonOpenModFolder;
+ private Label LabelModFolderInstall;
}
}
\ No newline at end of file
diff --git a/Bloxstrap/Dialogs/Preferences.cs b/Bloxstrap/Dialogs/Preferences.cs
index e4577f5..139e11b 100644
--- a/Bloxstrap/Dialogs/Preferences.cs
+++ b/Bloxstrap/Dialogs/Preferences.cs
@@ -1,8 +1,12 @@
-using Microsoft.Win32;
+using System.IO;
+using System.Diagnostics;
+
+using Microsoft.Win32;
-using Bloxstrap.Helpers;
-using Bloxstrap.Enums;
using Bloxstrap.Dialogs.BootstrapperStyles;
+using Bloxstrap.Enums;
+using Bloxstrap.Helpers;
+using Bloxstrap.Helpers.Integrations;
namespace Bloxstrap.Dialogs
{
@@ -30,10 +34,6 @@ namespace Bloxstrap.Dialogs
private BootstrapperStyle? _selectedStyle;
private BootstrapperIcon? _selectedIcon;
- private bool _useDiscordRichPresence = true;
- private bool _hideRPCButtons = false;
- private bool _useOldDeathSound = true;
- private bool _useOldMouseCursor = false;
private BootstrapperStyle SelectedStyle
{
@@ -68,67 +68,6 @@ namespace Bloxstrap.Dialogs
}
}
- private bool UseDiscordRichPresence
- {
- get => _useDiscordRichPresence;
-
- set
- {
- if (_useDiscordRichPresence == value)
- return;
-
- _useDiscordRichPresence = value;
-
- this.ToggleDiscordRichPresence.Checked = value;
- this.ToggleRPCButtons.Enabled = value;
- }
- }
-
- private bool HideRPCButtons
- {
- get => _hideRPCButtons;
-
- set
- {
- if (_hideRPCButtons == value)
- return;
-
- _hideRPCButtons = value;
-
- this.ToggleRPCButtons.Checked = value;
- }
- }
-
- private bool UseOldDeathSound
- {
- get => _useOldDeathSound;
-
- set
- {
- if (_useOldDeathSound == value)
- return;
-
- _useOldDeathSound = value;
-
- this.ToggleDeathSound.Checked = value;
- }
- }
-
- private bool UseOldMouseCursor
- {
- get => _useOldMouseCursor;
-
- set
- {
- if (_useOldMouseCursor == value)
- return;
-
- _useOldMouseCursor = value;
-
- this.ToggleMouseCursor.Checked = value;
- }
- }
-
public Preferences()
{
InitializeComponent();
@@ -142,6 +81,8 @@ namespace Bloxstrap.Dialogs
{
this.SaveButton.Text = "Install";
this.InstallLocation.Text = Path.Combine(Program.LocalAppData, Program.ProjectName);
+ this.ButtonOpenModFolder.Visible = false;
+ this.LabelModFolderInstall.Visible = true;
}
else
{
@@ -158,18 +99,22 @@ namespace Bloxstrap.Dialogs
this.IconSelection.Items.Add(icon.Key);
}
- this.InfoTooltip.SetToolTip(this.StyleSelection, "Choose how the bootstrapper dialog should look.\nYou can use the 'Preview' button to preview the bootstrapper look.");
- this.InfoTooltip.SetToolTip(this.IconSelection, "Choose what icon the bootstrapper should use.");
- this.InfoTooltip.SetToolTip(this.GroupBoxInstallLocation, "Choose where Bloxstrap should install to.\nThis is useful if you typically install all your games to a separate storage drive.");
- this.InfoTooltip.SetToolTip(this.ToggleDiscordRichPresence, "Choose whether to show what game you're playing on your Discord activity status.\nThis will only work when you launch a game from the website, and is not supported in the Beta App.");
- this.InfoTooltip.SetToolTip(this.ToggleRPCButtons, "Choose whether the buttons to play/view game info should be hidden from activity status.");
+ if (!Environment.Is64BitOperatingSystem)
+ this.ToggleRFUEnabled.Enabled = false;
SelectedStyle = Program.Settings.BootstrapperStyle;
SelectedIcon = Program.Settings.BootstrapperIcon;
- UseDiscordRichPresence = Program.Settings.UseDiscordRichPresence;
- HideRPCButtons = Program.Settings.HideRPCButtons;
- UseOldDeathSound = Program.Settings.UseOldDeathSound;
- UseOldMouseCursor = Program.Settings.UseOldMouseCursor;
+
+ this.ToggleCheckForUpdates.Checked = Program.Settings.CheckForUpdates;
+
+ this.ToggleDiscordRichPresence.Checked = Program.Settings.UseDiscordRichPresence;
+ this.ToggleRPCButtons.Checked = Program.Settings.HideRPCButtons;
+
+ this.ToggleRFUEnabled.Checked = Program.Settings.RFUEnabled;
+ this.ToggleRFUAutoclose.Checked = Program.Settings.RFUAutoclose;
+
+ this.ToggleDeathSound.Checked = Program.Settings.UseOldDeathSound;
+ this.ToggleMouseCursor.Checked = Program.Settings.UseOldMouseCursor;
}
private void InstallLocationBrowseButton_Click(object sender, EventArgs e)
@@ -239,7 +184,7 @@ namespace Bloxstrap.Dialogs
{
Program.SettingsManager.ShouldSave = true;
- if (Program.BaseDirectory != installLocation)
+ if (Program.BaseDirectory is not null && Program.BaseDirectory != installLocation)
{
Program.ShowMessageBox(MessageBoxIcon.Information, $"{Program.ProjectName} will install to the new location you've set the next time it runs.");
@@ -262,18 +207,12 @@ namespace Bloxstrap.Dialogs
Program.Settings.BootstrapperStyle = SelectedStyle;
Program.Settings.BootstrapperIcon = SelectedIcon;
- Program.Settings.UseDiscordRichPresence = UseDiscordRichPresence;
- Program.Settings.HideRPCButtons = HideRPCButtons;
- Program.Settings.UseOldDeathSound = UseOldDeathSound;
- Program.Settings.UseOldMouseCursor = UseOldMouseCursor;
this.Close();
}
private void PreviewButton_Click(object sender, EventArgs e)
{
- // small hack to get the icon to show in the preview without saving to settings
- BootstrapperIcon savedIcon = Program.Settings.BootstrapperIcon;
Program.Settings.BootstrapperIcon = SelectedIcon;
this.Visible = false;
@@ -301,29 +240,57 @@ namespace Bloxstrap.Dialogs
break;
}
- Program.Settings.BootstrapperIcon = savedIcon;
-
this.Visible = true;
}
private void ToggleDiscordRichPresence_CheckedChanged(object sender, EventArgs e)
{
- UseDiscordRichPresence = this.ToggleDiscordRichPresence.Checked;
+ Program.Settings.UseDiscordRichPresence = this.ToggleRPCButtons.Enabled = this.ToggleDiscordRichPresence.Checked;
}
private void ToggleRPCButtons_CheckedChanged(object sender, EventArgs e)
{
- HideRPCButtons = this.ToggleRPCButtons.Checked;
+ Program.Settings.HideRPCButtons = this.ToggleRPCButtons.Checked;
+ }
+
+ private void ToggleRFUEnabled_CheckedChanged(object sender, EventArgs e)
+ {
+ Program.Settings.RFUEnabled = this.ToggleRFUAutoclose.Enabled = this.ToggleRFUEnabled.Checked;
+ }
+
+ private void ToggleRFUAutoclose_CheckedChanged(object sender, EventArgs e)
+ {
+ Program.Settings.RFUAutoclose = this.ToggleRFUAutoclose.Checked;
}
private void ToggleDeathSound_CheckedChanged(object sender, EventArgs e)
{
- UseOldDeathSound = this.ToggleDeathSound.Checked;
+ Program.Settings.UseOldDeathSound = this.ToggleDeathSound.Checked;
}
private void ToggleMouseCursor_CheckedChanged(object sender, EventArgs e)
{
- UseOldMouseCursor = this.ToggleMouseCursor.Checked;
+ Program.Settings.UseOldMouseCursor = this.ToggleMouseCursor.Checked;
+ }
+
+ private void ToggleCheckForUpdates_CheckedChanged(object sender, EventArgs e)
+ {
+ Program.Settings.CheckForUpdates = this.ToggleCheckForUpdates.Checked;
+ }
+
+ private void RFUWebsite_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
+ {
+ Utilities.OpenWebsite($"https://github.com/{RbxFpsUnlocker.ProjectRepository}");
+ }
+
+ private void ButtonOpenModFolder_Click(object sender, EventArgs e)
+ {
+ Process.Start("explorer.exe", Directories.Modifications);
+ }
+
+ private void Preferences_Load(object sender, EventArgs e)
+ {
+ this.Activate();
}
}
}
diff --git a/Bloxstrap/Dialogs/Preferences.resx b/Bloxstrap/Dialogs/Preferences.resx
index 453d499..b2b5813 100644
--- a/Bloxstrap/Dialogs/Preferences.resx
+++ b/Bloxstrap/Dialogs/Preferences.resx
@@ -57,10 +57,10 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
-
- 17, 17
-
222, 17
+
+ 17, 17
+
\ No newline at end of file
diff --git a/Bloxstrap/Helpers/Directories.cs b/Bloxstrap/Helpers/Directories.cs
new file mode 100644
index 0000000..3d49b0f
--- /dev/null
+++ b/Bloxstrap/Helpers/Directories.cs
@@ -0,0 +1,28 @@
+using System.IO;
+
+namespace Bloxstrap.Helpers
+{
+ internal class Directories
+ {
+ public static string Base { get; private set; } = "";
+ public static string Downloads { get; private set; } = "";
+ public static string Integrations { get; private set; } = "";
+ public static string Versions { get; private set; } = "";
+ public static string Modifications { get; private set; } = "";
+
+ public static string App { get; private set; } = "";
+
+ public static bool Initialized { get => String.IsNullOrEmpty(Base); }
+
+ public static void Initialize(string baseDirectory)
+ {
+ Base = baseDirectory;
+ Downloads = Path.Combine(Base, "Downloads");
+ Integrations = Path.Combine(Base, "Integrations");
+ Versions = Path.Combine(Base, "Versions");
+ Modifications = Path.Combine(Base, "Modifications");
+
+ App = Path.Combine(Base, $"{Program.ProjectName}.exe");
+ }
+ }
+}
diff --git a/Bloxstrap/Helpers/DiscordRichPresence.cs b/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs
similarity index 58%
rename from Bloxstrap/Helpers/DiscordRichPresence.cs
rename to Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs
index e57fe53..32dc300 100644
--- a/Bloxstrap/Helpers/DiscordRichPresence.cs
+++ b/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs
@@ -1,39 +1,35 @@
-using Newtonsoft.Json;
-using Newtonsoft.Json.Linq;
+using Newtonsoft.Json.Linq;
using DiscordRPC;
-namespace Bloxstrap.Helpers
+namespace Bloxstrap.Helpers.Integrations
{
internal class DiscordRichPresence : IDisposable
{
readonly DiscordRpcClient RichPresence = new("1005469189907173486");
public async Task SetPresence(string placeId)
- {
+ {
string placeName;
string placeThumbnail;
string creatorName;
// null checking could probably be a lot more concrete here
- using (HttpClient client = new())
- {
- JObject placeInfo = await Utilities.GetJson($"https://economy.roblox.com/v2/assets/{placeId}/details");
+ JObject placeInfo = await Utilities.GetJson($"https://economy.roblox.com/v2/assets/{placeId}/details");
- placeName = placeInfo["Name"].Value();
- creatorName = placeInfo["Creator"]["Name"].Value();
+ placeName = placeInfo["Name"].Value();
+ creatorName = placeInfo["Creator"]["Name"].Value();
- JObject thumbnailInfo = await Utilities.GetJson($"https://thumbnails.roblox.com/v1/places/gameicons?placeIds={placeId}&returnPolicy=PlaceHolder&size=512x512&format=Png&isCircular=false");
+ JObject thumbnailInfo = await Utilities.GetJson($"https://thumbnails.roblox.com/v1/places/gameicons?placeIds={placeId}&returnPolicy=PlaceHolder&size=512x512&format=Png&isCircular=false");
- if (thumbnailInfo["data"] is null)
- return false;
+ if (thumbnailInfo["data"] is null)
+ return false;
- placeThumbnail = thumbnailInfo["data"][0]["imageUrl"].Value();
- }
+ placeThumbnail = thumbnailInfo["data"][0]["imageUrl"].Value();
DiscordRPC.Button[]? buttons = null;
if (!Program.Settings.HideRPCButtons)
- {
+ {
buttons = new DiscordRPC.Button[]
{
new DiscordRPC.Button()
@@ -57,16 +53,14 @@ namespace Bloxstrap.Helpers
Details = placeName,
State = $"by {creatorName}",
Timestamps = new Timestamps() { Start = DateTime.UtcNow },
-
+ Buttons = buttons,
Assets = new Assets()
{
LargeImageKey = placeThumbnail,
LargeImageText = placeName,
- SmallImageKey = "bloxstrap",
- SmallImageText = "Rich Presence provided by Bloxstrap"
- },
-
- Buttons = buttons
+ SmallImageKey = "roblox",
+ SmallImageText = "Roblox"
+ }
});
return true;
diff --git a/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs
new file mode 100644
index 0000000..4d48181
--- /dev/null
+++ b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs
@@ -0,0 +1,95 @@
+using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
+using System.Net.Http;
+
+using Newtonsoft.Json.Linq;
+
+namespace Bloxstrap.Helpers.Integrations
+{
+ internal class RbxFpsUnlocker
+ {
+ public const string ProjectRepository = "axstin/rbxfpsunlocker";
+
+ // default settings but with QuickStart set to true and CheckForUpdates set to false
+ private static readonly string Settings =
+ "UnlockClient=true\n" +
+ "UnlockStudio=false\n" +
+ "FPSCapValues=[30.000000, 60.000000, 75.000000, 120.000000, 144.000000, 165.000000, 240.000000, 360.000000]\n" +
+ "FPSCapSelection=0\n" +
+ "FPSCap=0.000000\n" +
+ "CheckForUpdates=false\n" +
+ "NonBlockingErrors=true\n" +
+ "SilentErrors=false\n" +
+ "QuickStart=true\n";
+
+ public static async Task CheckInstall()
+ {
+ if (Program.BaseDirectory is null)
+ return;
+
+ string folderLocation = Path.Combine(Program.BaseDirectory, "Integrations", "rbxfpsunlocker");
+ string fileLocation = Path.Combine(folderLocation, "rbxfpsunlocker.exe");
+ string settingsLocation = Path.Combine(folderLocation, "settings");
+
+ if (!Program.Settings.RFUEnabled)
+ {
+ if (Directory.Exists(folderLocation))
+ {
+ Directory.Delete(folderLocation, true);
+ }
+
+ return;
+ }
+
+ DateTime lastReleasePublish;
+ string downloadUrl;
+
+ try
+ {
+ JObject releaseInfo = await Utilities.GetJson($"https://api.github.com/repos/{ProjectRepository}/releases/latest");
+
+ // so... rbxfpsunlocker does not actually have any version info for the executable
+ // meaning the best way we can check for a new version is comparing time last download to time last release published
+ lastReleasePublish = DateTime.Parse(releaseInfo["created_at"].Value());
+ downloadUrl = releaseInfo["assets"][0]["browser_download_url"].Value();
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"Failed to fetch latest version info! ({ex.Message})");
+ return;
+ }
+
+ Directory.CreateDirectory(folderLocation);
+
+ if (File.Exists(fileLocation))
+ {
+ DateTime lastDownload = File.GetCreationTimeUtc(fileLocation);
+
+ // no new release published, return
+ if (lastDownload > lastReleasePublish)
+ return;
+
+ File.Delete(fileLocation);
+ }
+
+ Debug.WriteLine("Installing/Updating rbxfpsunlocker...");
+
+ using (HttpClient client = new())
+ {
+ byte[] bytes = await client.GetByteArrayAsync(downloadUrl);
+
+ using (MemoryStream zipStream = new MemoryStream(bytes))
+ {
+ ZipArchive zip = new ZipArchive(zipStream);
+ zip.ExtractToDirectory(folderLocation, true);
+ }
+ }
+
+ if (!File.Exists(settingsLocation))
+ {
+ await File.WriteAllTextAsync(settingsLocation, Settings);
+ }
+ }
+ }
+}
diff --git a/Bloxstrap/Helpers/Protocol.cs b/Bloxstrap/Helpers/Protocol.cs
index a64a9f9..e24330d 100644
--- a/Bloxstrap/Helpers/Protocol.cs
+++ b/Bloxstrap/Helpers/Protocol.cs
@@ -1,4 +1,5 @@
-using System.Web;
+using System.Text;
+using System.Web;
using Microsoft.Win32;
namespace Bloxstrap.Helpers
@@ -9,11 +10,11 @@ namespace Bloxstrap.Helpers
private static readonly IReadOnlyDictionary UriKeyArgMap = new Dictionary()
{
// excluding roblox-player, browsertrackerid and channel
- { "launchmode", "--" },
+ { "launchmode", "--" },
{ "gameinfo", "-t " },
{ "placelauncherurl", "-j "},
- // { "launchtime", "--launchtime=" }, we'll set this when launching the game client
- { "robloxLocale", "--rloc " },
+ // { "launchtime", "--launchtime=" }, we'll set this when launching the game client
+ { "robloxLocale", "--rloc " },
{ "gameLocale", "--gloc " },
};
@@ -22,7 +23,7 @@ namespace Bloxstrap.Helpers
string[] keyvalPair;
string key;
string val;
- string commandLine = "";
+ StringBuilder commandLine = new();
foreach (var parameter in protocol.Split('+'))
{
@@ -39,10 +40,10 @@ namespace Bloxstrap.Helpers
if (key == "placelauncherurl")
val = HttpUtility.UrlDecode(val).Replace("browserTrackerId", "lol");
- commandLine += UriKeyArgMap[key] + val + " ";
+ commandLine.Append(UriKeyArgMap[key] + val + " ");
}
- return commandLine;
+ return commandLine.ToString();
}
public static void Register(string key, string name, string handler)
diff --git a/Bloxstrap/Helpers/RSMM/FileManifest.cs b/Bloxstrap/Helpers/RSMM/FileManifest.cs
index 4905a4f..4ca5aab 100644
--- a/Bloxstrap/Helpers/RSMM/FileManifest.cs
+++ b/Bloxstrap/Helpers/RSMM/FileManifest.cs
@@ -1,5 +1,7 @@
// https://github.com/MaximumADHD/Roblox-Studio-Mod-Manager/blob/main/ProjectSrc/Bootstrapper/FileManifest.cs
+using System.IO;
+using System.Net.Http;
using System.Runtime.Serialization;
namespace Bloxstrap.Helpers.RSMM
diff --git a/Bloxstrap/Helpers/RSMM/PackageManifest.cs b/Bloxstrap/Helpers/RSMM/PackageManifest.cs
index b770852..29e7035 100644
--- a/Bloxstrap/Helpers/RSMM/PackageManifest.cs
+++ b/Bloxstrap/Helpers/RSMM/PackageManifest.cs
@@ -1,5 +1,7 @@
// https://github.com/MaximumADHD/Roblox-Studio-Mod-Manager/blob/main/ProjectSrc/Bootstrapper/PackageManifest.cs
+using System.IO;
+using System.Net.Http;
namespace Bloxstrap.Helpers.RSMM
{
diff --git a/Bloxstrap/Helpers/UpdateChecker.cs b/Bloxstrap/Helpers/Updater.cs
similarity index 80%
rename from Bloxstrap/Helpers/UpdateChecker.cs
rename to Bloxstrap/Helpers/Updater.cs
index e02be98..2327fac 100644
--- a/Bloxstrap/Helpers/UpdateChecker.cs
+++ b/Bloxstrap/Helpers/Updater.cs
@@ -1,18 +1,20 @@
using System.Diagnostics;
+using System.IO;
+
using Newtonsoft.Json.Linq;
namespace Bloxstrap.Helpers
{
- public class UpdateChecker
+ public class Updater
{
- public static void CheckInstalledVersion()
+ public static bool CheckInstalledVersion()
{
- if (Environment.ProcessPath is null || !File.Exists(Program.FilePath))
- return;
+ if (Environment.ProcessPath is null || !File.Exists(Directories.App) || Environment.ProcessPath == Directories.App)
+ return false;
// if downloaded version doesn't match, replace installed version with downloaded version
FileVersionInfo currentVersionInfo = FileVersionInfo.GetVersionInfo(Environment.ProcessPath);
- FileVersionInfo installedVersionInfo = FileVersionInfo.GetVersionInfo(Program.FilePath);
+ FileVersionInfo installedVersionInfo = FileVersionInfo.GetVersionInfo(Directories.App);
if (installedVersionInfo.ProductVersion != currentVersionInfo.ProductVersion)
{
@@ -25,10 +27,13 @@ namespace Bloxstrap.Helpers
if (result == DialogResult.Yes)
{
- File.Delete(Program.FilePath);
- File.Copy(Environment.ProcessPath, Program.FilePath);
+ File.Delete(Directories.App);
+ File.Copy(Environment.ProcessPath, Directories.App);
+ return true;
}
}
+
+ return false;
}
public static async Task Check()
@@ -36,6 +41,12 @@ namespace Bloxstrap.Helpers
if (Environment.ProcessPath is null)
return;
+ if (!Program.IsFirstRun && CheckInstalledVersion())
+ return;
+
+ if (!Program.Settings.CheckForUpdates)
+ return;
+
FileVersionInfo currentVersionInfo = FileVersionInfo.GetVersionInfo(Environment.ProcessPath);
string currentVersion = $"Bloxstrap v{currentVersionInfo.ProductVersion}";
string latestVersion;
@@ -67,7 +78,7 @@ namespace Bloxstrap.Helpers
if (result == DialogResult.Yes)
{
- Process.Start(new ProcessStartInfo { FileName = $"https://github.com/{Program.ProjectRepository}/releases/latest", UseShellExecute = true });
+ Utilities.OpenWebsite($"https://github.com/{Program.ProjectRepository}/releases/latest");
Program.Exit();
}
}
diff --git a/Bloxstrap/Helpers/Utilities.cs b/Bloxstrap/Helpers/Utilities.cs
index 894cc71..12360d0 100644
--- a/Bloxstrap/Helpers/Utilities.cs
+++ b/Bloxstrap/Helpers/Utilities.cs
@@ -1,4 +1,7 @@
-using System.Security.Cryptography;
+using System.Diagnostics;
+using System.IO;
+using System.Net.Http;
+using System.Security.Cryptography;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -7,6 +10,11 @@ namespace Bloxstrap.Helpers
{
public class Utilities
{
+ public static void OpenWebsite(string website)
+ {
+ Process.Start(new ProcessStartInfo { FileName = website, UseShellExecute = true });
+ }
+
public static async Task GetJson(string url)
{
using (HttpClient client = new())
@@ -18,7 +26,7 @@ namespace Bloxstrap.Helpers
}
}
- public static string CalculateMD5(string filename)
+ public static string MD5File(string filename)
{
using (MD5 md5 = MD5.Create())
{
diff --git a/Bloxstrap/Program.cs b/Bloxstrap/Program.cs
index 1ea0dca..401f681 100644
--- a/Bloxstrap/Program.cs
+++ b/Bloxstrap/Program.cs
@@ -1,4 +1,6 @@
using System.Diagnostics;
+using System.IO;
+
using Microsoft.Win32;
using Bloxstrap.Helpers;
@@ -8,26 +10,29 @@ namespace Bloxstrap
{
public const StringComparison StringFormat = StringComparison.InvariantCulture;
- // ideally for the application website, i would prefer something other than my own hosted website?
- // i don't really have many other options though - github doesn't make much sense for something like this
-
public const string ProjectName = "Bloxstrap";
public const string ProjectRepository = "pizzaboxer/bloxstrap";
- public const string BaseUrlApplication = "https://bloxstrap.pizzaboxer.xyz";
public const string BaseUrlSetup = "https://s3.amazonaws.com/setup.roblox.com";
-
+
+ #region base64 stuff
+ // TODO: using IPFS as a reliable method for static asset storage instead of base64?
+ public const string Base64OldDeathSound = "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EEIIIYSMMeeggxBCCKWUUkopGWPOQQghhBBKKKWEEjrnoIMQQgmllFJKKaV0zjkIIYQQSimllFJK6SCEEEIIpZRSSimllNJBCCGEUEoppZRSSiklhBBCCKWUUkoppZRSSgghhBBKKaWUUkoppZQQQgillFJKKaWUUkopIYQQSimllFJKKaWUUkIIpZRSSimllFJKKaWEEEoppZRSSimllFJKCaGUUkoppZRSSimllBJKKaWUUkoppZRSSikllFJKKaWUUkoppZRSSiillFJKKaWUUkoppZRQSimllFJKKaWUUkopoZRSSimllFJKKaWUUgoAADpwAAAIMKLSQuw048ojcEQhwwRUaMhKACAcAABABDoIIYQQQggRcxBCCCGEEEKImIMQQgghhBBCCCGEEEIIpZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppRQAdZnhABg9YeMMK0lnhaPBhYasBADSAgAAYxhjjCnIpLMWY60NYxBCB52EFGqoJaaGMQghdFBKSi22WHMGoaRSSkktxliDzT2DUEoppaQWY605F+NBSCWl1GKrteccjO4glJJSSjHWmnPuvWjQSUmptVpz7j0HXzwIpaTWWow9Bx+MMKKUlmKssdYcfBFGGFFKSy3GmnvNvRhjhEopxlp7zrnnXIwRPqUWY6659x58LsL44mLMOffigw8+CGGMkDHm2HPwvRdjjA/CyFxzLsIY44swwvggbK25B1+MEUYYY3zvNfigezHCCCOMMcII3XPRRfhijDFGGF+EAQC5EQ4AiAtGElJnGVYaceMJGCKQQkNWAQAxAAAEMcYgpJBSSinFGGOMMcYYY4wxxhhjjDHGnGPOOeecAADABAcAgAAr2JVZWrVR3NRJXvRB4BM6YjMy5FIqZnIi6JEaarES7NAKbvACsNCQlQAAGQAA5KSUlFotGkLKQWk1iMgg5STFJCJjkILSgqeQMYhJyh1jCiEFqXbQMYUUoxpSCplSCmqqOYaOMagxJ+FSCaUGAABAEAAgICQAwABBwQwAMDhAGDkQ6AggcGgDAAxEyExgUAgNDjIB4AEiQioASExQlC50QQgRpIsgiwcu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";
+ public const string Base64OldArrowCursor = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfdBwoWHS0d8XaOAAAAeUlEQVRo3u3WyQmAUBAEUUMx/yRdEFH/dhG6EKsieKeZniYzMzMzMzMzs5ctWzBgZgk7ACUcAJBwAjDCBYAIdwBCeAIAQgmIE2pAmNACRAltQJDQA8QIfUCIMAJECGNAgFAforI/nWL4GcHvGB4k8CSDRyk8y83s860lExWMmEMyvAAAAABJRU5ErkJggg==";
+ public const string Base64OldArrowFarCursor = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAQAAAAAYLlVAAAAAmJLR0QA/4ePzL8AAAAJcEhZcwAACxMAAAsTAQCanBgAAAAHdElNRQfdBwoWHwRtdYxgAAAAfElEQVRo3u3WwQmAMBQEUetPtXYQERE10VyEHcSZNPBOPztNZmZmZmZmZmYvK7VUGDCzhBWAEjYASNgBGOEAQIQzACFcAQChBcQJPSBMuANECfeAIOEJECM8A0KEESBCGAMChP4Qte9Ppxj+jODvGB4k8CSDRyk8y83s8y1ZdnQ0Empj3AAAAABJRU5ErkJggg==";
+ #endregion
+
public static string? BaseDirectory;
- public static string LocalAppData { get; private set; }
- public static string FilePath { get; private set; }
- public static string StartMenuDirectory { get; private set; }
public static bool IsFirstRun { get; private set; } = false;
+ public static string LocalAppData { get; private set; } = "";
+ public static string StartMenu { get; private set; } = "";
+
public static SettingsFormat Settings;
public static SettingsManager SettingsManager = new();
public static void ShowMessageBox(MessageBoxIcon icon, string message)
{
- MessageBox.Show(message, Program.ProjectName, MessageBoxButtons.OK, icon);
+ MessageBox.Show(message, ProjectName, MessageBoxButtons.OK, icon);
}
public static void Exit()
@@ -52,9 +57,8 @@ namespace Bloxstrap
return;
}
- UpdateChecker.Check().Wait();
-
LocalAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ StartMenu = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs", ProjectName);
// check if installed
RegistryKey? registryKey = Registry.CurrentUser.OpenSubKey($@"Software\{ProjectName}");
@@ -76,19 +80,20 @@ namespace Bloxstrap
if (BaseDirectory is null)
return;
- SettingsManager.SaveLocation = Path.Combine(BaseDirectory, "Settings.json");
- FilePath = Path.Combine(BaseDirectory, $"{ProjectName}.exe");
- StartMenuDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.StartMenu), "Programs", ProjectName);
+ Directories.Initialize(BaseDirectory);
+
+ SettingsManager.SaveLocation = Path.Combine(Directories.Base, "Settings.json");
// we shouldn't save settings on the first run until the first installation is finished,
// just in case the user decides to cancel the install
if (!IsFirstRun)
{
- UpdateChecker.CheckInstalledVersion();
Settings = SettingsManager.Settings;
SettingsManager.ShouldSave = true;
}
+ Updater.Check().Wait();
+
string commandLine = "";
if (args.Length > 0)
diff --git a/Bloxstrap/Settings.cs b/Bloxstrap/Settings.cs
index 4d4f573..fff91bc 100644
--- a/Bloxstrap/Settings.cs
+++ b/Bloxstrap/Settings.cs
@@ -1,5 +1,7 @@
using System.Diagnostics;
+using System.IO;
using System.Text.Json;
+
using Bloxstrap.Enums;
namespace Bloxstrap
@@ -8,10 +10,16 @@ namespace Bloxstrap
{
public string VersionGuid { get; set; }
+ public bool CheckForUpdates { get; set; } = true;
+
public BootstrapperStyle BootstrapperStyle { get; set; } = BootstrapperStyle.ProgressDialog;
public BootstrapperIcon BootstrapperIcon { get; set; } = BootstrapperIcon.IconBloxstrap;
+
public bool UseDiscordRichPresence { get; set; } = true;
public bool HideRPCButtons { get; set; } = false;
+ public bool RFUEnabled { get; set; } = false;
+ public bool RFUAutoclose { get; set; } = false;
+
public bool UseOldDeathSound { get; set; } = true;
public bool UseOldMouseCursor { get; set; } = false;
}