diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index 3d2e4f6..0000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -ko_fi: boxerpizza diff --git a/Bloxstrap/App.xaml.cs b/Bloxstrap/App.xaml.cs index 5dced57..4fd8b79 100644 --- a/Bloxstrap/App.xaml.cs +++ b/Bloxstrap/App.xaml.cs @@ -42,6 +42,8 @@ namespace Bloxstrap public static bool IsProductionBuild => IsActionBuild && BuildMetadata.CommitRef.StartsWith("tag", StringComparison.Ordinal); + public static bool IsStudioVisible => !String.IsNullOrEmpty(App.State.Prop.Studio.VersionGuid); + public static readonly MD5 MD5Provider = MD5.Create(); public static readonly Logger Logger = new(); diff --git a/Bloxstrap/AppData/CommonAppData.cs b/Bloxstrap/AppData/CommonAppData.cs index 54aaaa0..1e1b425 100644 --- a/Bloxstrap/AppData/CommonAppData.cs +++ b/Bloxstrap/AppData/CommonAppData.cs @@ -42,13 +42,13 @@ namespace Bloxstrap.AppData }; public virtual string ExecutableName { get; } = null!; - - public virtual string Directory { get; } = null!; - public string LockFilePath => Path.Combine(Directory, "Bloxstrap.lock"); - + public string Directory => Path.Combine(Paths.Versions, State.VersionGuid); + public string ExecutablePath => Path.Combine(Directory, ExecutableName); - + + public virtual AppState State { get; } = null!; + public virtual IReadOnlyDictionary PackageDirectoryMap { get; set; } diff --git a/Bloxstrap/AppData/IAppData.cs b/Bloxstrap/AppData/IAppData.cs index 63a6b48..b19aa95 100644 --- a/Bloxstrap/AppData/IAppData.cs +++ b/Bloxstrap/AppData/IAppData.cs @@ -12,10 +12,6 @@ string Directory { get; } - string OldDirectory { get; } - - string LockFilePath { get; } - string ExecutablePath { get; } AppState State { get; } diff --git a/Bloxstrap/AppData/RobloxPlayerData.cs b/Bloxstrap/AppData/RobloxPlayerData.cs index 6ec09a1..3c4f728 100644 --- a/Bloxstrap/AppData/RobloxPlayerData.cs +++ b/Bloxstrap/AppData/RobloxPlayerData.cs @@ -16,11 +16,7 @@ namespace Bloxstrap.AppData public override string ExecutableName => "RobloxPlayerBeta.exe"; - public override string Directory => Path.Combine(Paths.Roblox, "Player"); - - public string OldDirectory => Path.Combine(Paths.Roblox, "Player.old"); - - public AppState State => App.State.Prop.Player; + public override AppState State => App.State.Prop.Player; public override IReadOnlyDictionary PackageDirectoryMap { get; set; } = new Dictionary() { diff --git a/Bloxstrap/AppData/RobloxStudioData.cs b/Bloxstrap/AppData/RobloxStudioData.cs index 886e630..2ada1c2 100644 --- a/Bloxstrap/AppData/RobloxStudioData.cs +++ b/Bloxstrap/AppData/RobloxStudioData.cs @@ -10,11 +10,7 @@ public override string ExecutableName => "RobloxStudioBeta.exe"; - public override string Directory => Path.Combine(Paths.Roblox, "Studio"); - - public string OldDirectory => Path.Combine(Paths.Roblox, "Studio.old"); - - public AppState State => App.State.Prop.Studio; + public override AppState State => App.State.Prop.Studio; public override IReadOnlyDictionary PackageDirectoryMap { get; set; } = new Dictionary() { diff --git a/Bloxstrap/Bloxstrap.csproj b/Bloxstrap/Bloxstrap.csproj index 9f1b69a..9ca54f8 100644 --- a/Bloxstrap/Bloxstrap.csproj +++ b/Bloxstrap/Bloxstrap.csproj @@ -7,8 +7,8 @@ true True Bloxstrap.ico - 2.8.1 - 2.8.1 + 2.8.2 + 2.8.2 app.manifest true false diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 207c4a4..7a7cfc7 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -50,6 +50,7 @@ namespace Bloxstrap private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs; private string _latestVersionGuid = null!; + private string _latestVersionDirectory = null!; private PackageManifest _versionPackageManifest = null!; private bool _isInstalling = false; @@ -58,7 +59,7 @@ namespace Bloxstrap private double _taskbarProgressMaximum; private long _totalDownloadedBytes = 0; - private bool _mustUpgrade => String.IsNullOrEmpty(AppData.State.VersionGuid) || File.Exists(AppData.LockFilePath) || !File.Exists(AppData.ExecutablePath); + private bool _mustUpgrade => String.IsNullOrEmpty(AppData.State.VersionGuid) || !File.Exists(AppData.ExecutablePath); private bool _noConnection = false; private AsyncMutex? _mutex; @@ -313,6 +314,7 @@ namespace Bloxstrap key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel); _latestVersionGuid = clientVersion.VersionGuid; + _latestVersionDirectory = Path.Combine(Paths.Versions, _latestVersionGuid); string pkgManifestUrl = Deployment.GetLocation($"/{_latestVersionGuid}-rbxPkgManifest.txt"); var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl); @@ -357,8 +359,11 @@ namespace Bloxstrap string? logFileName = null; - string rbxLogDir = Path.Combine(Paths.LocalAppData, "Roblox\\logs"); + string rbxDir = Path.Combine(Paths.LocalAppData, "Roblox"); + if (!Directory.Exists(rbxDir)) + Directory.CreateDirectory(rbxDir); + string rbxLogDir = Path.Combine(rbxDir, "logs"); if (!Directory.Exists(rbxLogDir)) Directory.CreateDirectory(rbxLogDir); @@ -510,18 +515,13 @@ namespace Bloxstrap try { // clean up install - if (Directory.Exists(AppData.Directory)) - Directory.Delete(AppData.Directory, true); + if (Directory.Exists(_latestVersionDirectory)) + Directory.Delete(_latestVersionDirectory, true); } catch (Exception ex) { App.Logger.WriteLine(LOG_IDENT, "Could not fully clean up installation!"); App.Logger.WriteException(LOG_IDENT, ex); - - // assurance to make sure the next launch does a fresh install - // we probably shouldn't be using the lockfile to do this, but meh - var lockFile = new FileInfo(AppData.LockFilePath); - lockFile.Create().Dispose(); } } else if (_appPid != 0) @@ -646,9 +646,51 @@ namespace Bloxstrap return false; } -#endregion + #endregion #region Roblox Install + private void CleanupVersionsFolder() + { + const string LOG_IDENT = "Bootstrapper::CleanupVersionsFolder"; + + foreach (string dir in Directory.GetDirectories(Paths.Versions)) + { + string dirName = Path.GetFileName(dir); + + if (dirName != App.State.Prop.Player.VersionGuid && dirName != App.State.Prop.Studio.VersionGuid) + { + try + { + Directory.Delete(dir, true); + } + catch (IOException ex) + { + App.Logger.WriteLine(LOG_IDENT, $"Failed to delete {dir}"); + App.Logger.WriteException(LOG_IDENT, ex); + } + } + } + } + + private void MigrateCompatibilityFlags() + { + const string LOG_IDENT = "Bootstrapper::MigrateCompatibilityFlags"; + + string oldClientLocation = Path.Combine(Paths.Versions, AppData.State.VersionGuid, AppData.ExecutableName); + string newClientLocation = Path.Combine(_latestVersionDirectory, AppData.ExecutableName); + + // move old compatibility flags for the old location + using RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"); + string? appFlags = appFlagsKey.GetValue(oldClientLocation) as string; + + if (appFlags is not null) + { + App.Logger.WriteLine(LOG_IDENT, $"Migrating app compatibility flags from {oldClientLocation} to {newClientLocation}..."); + appFlagsKey.SetValueSafe(newClientLocation, appFlags); + appFlagsKey.DeleteValueSafe(oldClientLocation); + } + } + private async Task UpgradeRoblox() { const string LOG_IDENT = "Bootstrapper::UpgradeRoblox"; @@ -660,55 +702,11 @@ namespace Bloxstrap Directory.CreateDirectory(Paths.Base); Directory.CreateDirectory(Paths.Downloads); - Directory.CreateDirectory(Paths.Roblox); - - if (Directory.Exists(AppData.Directory)) - { - if (Directory.Exists(AppData.OldDirectory)) - Directory.Delete(AppData.OldDirectory, true); - - try - { - // test to see if any files are in use - // if you have a better way to check for this, please let me know! - Directory.Move(AppData.Directory, AppData.OldDirectory); - } - catch (Exception ex) - { - App.Logger.WriteLine(LOG_IDENT, "Could not clear old files, aborting update."); - App.Logger.WriteException(LOG_IDENT, ex); - - // 0x80070020 is the HRESULT that indicates that a process is still running - // (either RobloxPlayerBeta or RobloxCrashHandler), so we'll silently ignore it - if ((uint)ex.HResult != 0x80070020) - { - // ensure no files are marked as read-only for good measure - foreach (var file in Directory.GetFiles(AppData.Directory, "*", SearchOption.AllDirectories)) - Filesystem.AssertReadOnly(file); - - Frontend.ShowMessageBox( - Strings.Bootstrapper_FilesInUse, - _mustUpgrade ? MessageBoxImage.Error : MessageBoxImage.Warning - ); - - if (_mustUpgrade) - App.Terminate(ErrorCode.ERROR_CANCELLED); - } - - return; - } - - Directory.Delete(AppData.OldDirectory, true); - } + Directory.CreateDirectory(Paths.Versions); _isInstalling = true; - Directory.CreateDirectory(AppData.Directory); - - // installer lock, it should only be present while roblox is in the process of upgrading - // if it's present while we're launching, then it's an unfinished install and must be reinstalled - var lockFile = new FileInfo(AppData.LockFilePath); - lockFile.Create().Dispose(); + Directory.CreateDirectory(_latestVersionDirectory); var cachedPackageHashes = Directory.GetFiles(Paths.Downloads).Select(x => Path.GetFileName(x)); @@ -776,7 +774,7 @@ namespace Bloxstrap await Task.WhenAll(extractionTasks); App.Logger.WriteLine(LOG_IDENT, "Writing AppSettings.xml..."); - await File.WriteAllTextAsync(Path.Combine(AppData.Directory, "AppSettings.xml"), AppSettings); + await File.WriteAllTextAsync(Path.Combine(_latestVersionDirectory, "AppSettings.xml"), AppSettings); if (_cancelTokenSource.IsCancellationRequested) return; @@ -811,7 +809,7 @@ namespace Bloxstrap return; } - string baseDirectory = Path.Combine(AppData.Directory, AppData.PackageDirectoryMap[package.Name]); + string baseDirectory = Path.Combine(_latestVersionDirectory, AppData.PackageDirectoryMap[package.Name]); ExtractPackage(package); @@ -835,6 +833,8 @@ namespace Bloxstrap // finishing and cleanup + MigrateCompatibilityFlags(); + AppData.State.VersionGuid = _latestVersionGuid; AppData.State.PackageHashes.Clear(); @@ -842,6 +842,8 @@ namespace Bloxstrap foreach (var package in _versionPackageManifest) AppData.State.PackageHashes.Add(package.Name, package.Signature); + CleanupVersionsFolder(); + var allPackageHashes = new List(); allPackageHashes.AddRange(App.State.Prop.Player.PackageHashes.Values); @@ -882,8 +884,6 @@ namespace Bloxstrap App.State.Save(); - lockFile.Delete(); - _isInstalling = false; } @@ -916,7 +916,17 @@ namespace Bloxstrap const string path = "rbxasset://fonts/CustomFont.ttf"; - foreach (string jsonFilePath in Directory.GetFiles(Path.Combine(AppData.Directory, "content\\fonts\\families"))) + // lets make sure the content/fonts/families path exists in the version directory + string contentFolder = Path.Combine(_latestVersionDirectory, "content"); + Directory.CreateDirectory(contentFolder); + + string fontsFolder = Path.Combine(contentFolder, "fonts"); + Directory.CreateDirectory(fontsFolder); + + string familiesFolder = Path.Combine(fontsFolder, "families"); + Directory.CreateDirectory(familiesFolder); + + foreach (string jsonFilePath in Directory.GetFiles(familiesFolder)) { string jsonFilename = Path.GetFileName(jsonFilePath); string modFilepath = Path.Combine(modFontFamiliesFolder, jsonFilename); @@ -977,7 +987,7 @@ namespace Bloxstrap modFolderFiles.Add(relativeFile); string fileModFolder = Path.Combine(Paths.Modifications, relativeFile); - string fileVersionFolder = Path.Combine(AppData.Directory, relativeFile); + string fileVersionFolder = Path.Combine(_latestVersionDirectory, relativeFile); if (File.Exists(fileVersionFolder) && MD5Hash.FromFile(fileModFolder) == MD5Hash.FromFile(fileVersionFolder)) { @@ -1013,7 +1023,7 @@ namespace Bloxstrap { App.Logger.WriteLine(LOG_IDENT, $"{fileLocation} was removed as a mod but does not belong to a package"); - string versionFileLocation = Path.Combine(AppData.Directory, fileLocation); + string versionFileLocation = Path.Combine(_latestVersionDirectory, fileLocation); if (File.Exists(versionFileLocation)) File.Delete(versionFileLocation); @@ -1201,7 +1211,7 @@ namespace Bloxstrap return; } - string packageFolder = Path.Combine(AppData.Directory, packageDir); + string packageFolder = Path.Combine(_latestVersionDirectory, packageDir); string? fileFilter = null; // for sharpziplib, each file in the filter needs to be a regex diff --git a/Bloxstrap/Enums/NextAction.cs b/Bloxstrap/Enums/NextAction.cs index cf804f7..607029e 100644 --- a/Bloxstrap/Enums/NextAction.cs +++ b/Bloxstrap/Enums/NextAction.cs @@ -4,6 +4,7 @@ { Terminate, LaunchSettings, - LaunchRoblox + LaunchRoblox, + LaunchRobloxStudio } } diff --git a/Bloxstrap/Extensions/RegistryKeyEx.cs b/Bloxstrap/Extensions/RegistryKeyEx.cs index dd55690..19efd58 100644 --- a/Bloxstrap/Extensions/RegistryKeyEx.cs +++ b/Bloxstrap/Extensions/RegistryKeyEx.cs @@ -17,5 +17,19 @@ namespace Bloxstrap.Extensions App.Terminate(ErrorCode.ERROR_INSTALL_FAILURE); } } + + public static void DeleteValueSafe(this RegistryKey registryKey, string name) + { + try + { + App.Logger.WriteLine("RegistryKeyEx::DeleteValueSafe", $"Deleting {registryKey}\\{name}"); + registryKey.DeleteValue(name); + } + catch (UnauthorizedAccessException) + { + Frontend.ShowMessageBox(Strings.Dialog_RegistryWriteError, System.Windows.MessageBoxImage.Error); + App.Terminate(ErrorCode.ERROR_INSTALL_FAILURE); + } + } } } diff --git a/Bloxstrap/FastFlagManager.cs b/Bloxstrap/FastFlagManager.cs index 689299e..a69b3e5 100644 --- a/Bloxstrap/FastFlagManager.cs +++ b/Bloxstrap/FastFlagManager.cs @@ -207,7 +207,17 @@ namespace Bloxstrap } } - public string? GetPreset(string name) => GetValue(PresetFlags[name]); + public string? GetPreset(string name) + { + if (!PresetFlags.ContainsKey(name)) + { + App.Logger.WriteLine("FastFlagManager::GetPreset", $"Could not find preset {name}"); + Debug.Assert(false, $"Could not find preset {name}"); + return null; + } + + return GetValue(PresetFlags[name]); + } public T GetPresetEnum(IReadOnlyDictionary mapping, string prefix, string value) where T : Enum { diff --git a/Bloxstrap/Installer.cs b/Bloxstrap/Installer.cs index 6742f42..dbd5be8 100644 --- a/Bloxstrap/Installer.cs +++ b/Bloxstrap/Installer.cs @@ -91,7 +91,7 @@ namespace Bloxstrap App.Settings.Prop.EnableAnalytics = EnableAnalytics; - if (!String.IsNullOrEmpty(App.State.Prop.Studio.VersionGuid)) + if (App.IsStudioVisible) WindowsRegistry.RegisterStudio(); App.Settings.Save(); @@ -124,6 +124,10 @@ namespace Bloxstrap if (String.Compare(Directory.GetParent(InstallLocation)?.FullName, Paths.UserProfile, StringComparison.InvariantCultureIgnoreCase) == 0) return false; + // prevent from installing into the program files folder + if (InstallLocation.Contains("Program Files")) + return false; + return true; } @@ -190,7 +194,7 @@ namespace Bloxstrap if (!String.IsNullOrEmpty(App.State.Prop.Player.VersionGuid)) processes.AddRange(Process.GetProcessesByName(App.RobloxPlayerAppName)); - if (!String.IsNullOrEmpty(App.State.Prop.Studio.VersionGuid)) + if (App.IsStudioVisible) processes.AddRange(Process.GetProcessesByName(App.RobloxStudioAppName)); // prompt to shutdown roblox if its currently running @@ -283,8 +287,8 @@ namespace Bloxstrap () => File.Delete(StartMenuShortcut), + () => Directory.Delete(Paths.Versions, true), () => Directory.Delete(Paths.Downloads, true), - () => Directory.Delete(Paths.Roblox, true), () => File.Delete(App.State.FileLocation) }; @@ -477,21 +481,6 @@ namespace Bloxstrap App.FastFlags.SetValue("DFFlagVariableDPIScale2", null); } - if (Utilities.CompareVersions(existingVer, "2.5.1") == VersionComparison.LessThan) - { - App.FastFlags.SetValue("FIntDebugForceMSAASamples", null); - - if (App.FastFlags.GetPreset("UI.Menu.Style.DisableV2") is not null) - App.FastFlags.SetPreset("UI.Menu.Style.ABTest", false); - } - - if (Utilities.CompareVersions(existingVer, "2.5.3") == VersionComparison.LessThan) - { - string? val = App.FastFlags.GetPreset("UI.Menu.Style.EnableV4.1"); - if (App.FastFlags.GetPreset("UI.Menu.Style.EnableV4.2") != val) - App.FastFlags.SetPreset("UI.Menu.Style.EnableV4.2", val); - } - if (Utilities.CompareVersions(existingVer, "2.6.0") == VersionComparison.LessThan) { if (App.Settings.Prop.UseDisableAppPatch) @@ -556,38 +545,8 @@ namespace Bloxstrap WindowsRegistry.RegisterPlayer(); - string? oldV2Val = App.FastFlags.GetValue("FFlagDisableNewIGMinDUA"); - - if (oldV2Val is not null) - { - if (oldV2Val == "True") - { - App.FastFlags.SetPreset("UI.Menu.Style.V2Rollout", "0"); - - if (App.FastFlags.GetValue("UI.Menu.Style.EnableV4.1") == "False") - App.FastFlags.SetPreset("UI.Menu.Style.ReportButtonCutOff", "False"); - } - else - { - App.FastFlags.SetPreset("UI.Menu.Style.V2Rollout", "100"); - } - - if (App.FastFlags.GetPreset("UI.Menu.Style.ABTest.1") is not null) - App.FastFlags.SetPreset("UI.Menu.Style.ABTest", "False"); - - App.FastFlags.SetValue("FFlagDisableNewIGMinDUA", null); - } - + App.FastFlags.SetValue("FFlagDisableNewIGMinDUA", null); App.FastFlags.SetValue("FFlagFixGraphicsQuality", null); - - try - { - Directory.Delete(Path.Combine(Paths.Base, "Versions"), true); - } - catch (Exception ex) - { - App.Logger.WriteException(LOG_IDENT, ex); - } } if (Utilities.CompareVersions(existingVer, "2.8.1") == VersionComparison.LessThan) @@ -604,6 +563,17 @@ namespace Bloxstrap App.FastFlags.SetValue("FFlagEnableInGameMenuChromeABTest4", null); } + if (Utilities.CompareVersions(existingVer, "2.8.2") == VersionComparison.LessThan) + { + try + { + Directory.Delete(Path.Combine(Paths.Base, "Roblox"), true); + } + catch (Exception ex) + { + App.Logger.WriteException(LOG_IDENT, ex); + } + } App.Settings.Save(); App.FastFlags.Save(); diff --git a/Bloxstrap/JsonManager.cs b/Bloxstrap/JsonManager.cs index e20c06a..0336b9b 100644 --- a/Bloxstrap/JsonManager.cs +++ b/Bloxstrap/JsonManager.cs @@ -68,7 +68,7 @@ namespace Bloxstrap { File.WriteAllText(FileLocation, JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true })); } - catch (IOException ex) + catch (Exception ex) when (ex is IOException or UnauthorizedAccessException) { App.Logger.WriteLine(LOG_IDENT, "Failed to save"); App.Logger.WriteException(LOG_IDENT, ex); diff --git a/Bloxstrap/LaunchHandler.cs b/Bloxstrap/LaunchHandler.cs index cfd1a29..f76629b 100644 --- a/Bloxstrap/LaunchHandler.cs +++ b/Bloxstrap/LaunchHandler.cs @@ -21,6 +21,10 @@ namespace Bloxstrap LaunchRoblox(LaunchMode.Player); break; + case NextAction.LaunchRobloxStudio: + LaunchRoblox(LaunchMode.Studio); + break; + default: App.Terminate(isUnfinishedInstall ? ErrorCode.ERROR_INSTALL_USEREXIT : ErrorCode.ERROR_SUCCESS); break; diff --git a/Bloxstrap/LaunchSettings.cs b/Bloxstrap/LaunchSettings.cs index 62c87f5..3790148 100644 --- a/Bloxstrap/LaunchSettings.cs +++ b/Bloxstrap/LaunchSettings.cs @@ -53,6 +53,10 @@ namespace Bloxstrap { const string LOG_IDENT = "LaunchSettings"; +#if DEBUG + App.Logger.WriteLine(LOG_IDENT, $"Launched with arguments: {string.Join(' ', args)}"); +#endif + Args = args; // build flag map @@ -125,7 +129,23 @@ namespace Bloxstrap { RobloxLaunchMode = LaunchMode.Studio; - // TODO: do this later + if (String.IsNullOrEmpty(data)) + return; + + if (data.StartsWith("roblox-studio:")) + { + RobloxLaunchArgs = data; + } + else if (data.StartsWith("roblox-studio-auth:")) + { + RobloxLaunchMode = LaunchMode.StudioAuth; + RobloxLaunchArgs = data; + } + else + { + // likely a local path + RobloxLaunchArgs = $"-task EditFile -localPlaceFile \"{data}\""; + } } } } diff --git a/Bloxstrap/Models/Entities/ActivityData.cs b/Bloxstrap/Models/Entities/ActivityData.cs index 0afd1a8..039d06a 100644 --- a/Bloxstrap/Models/Entities/ActivityData.cs +++ b/Bloxstrap/Models/Entities/ActivityData.cs @@ -1,6 +1,7 @@ using System.Web; using System.Windows; using System.Windows.Input; +using Bloxstrap.AppData; using Bloxstrap.Models.APIs; using CommunityToolkit.Mvvm.Input; @@ -149,7 +150,7 @@ namespace Bloxstrap.Models.Entities private void RejoinServer() { - string playerPath = Path.Combine(Paths.Roblox, "Player", "RobloxPlayerBeta.exe"); + string playerPath = new RobloxPlayerData().ExecutablePath; Process.Start(playerPath, GetInviteDeeplink(false)); } diff --git a/Bloxstrap/Paths.cs b/Bloxstrap/Paths.cs index 36f8136..43d4a1c 100644 --- a/Bloxstrap/Paths.cs +++ b/Bloxstrap/Paths.cs @@ -20,8 +20,8 @@ public static string Downloads { get; private set; } = ""; public static string Logs { 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 Roblox { get; private set; } = ""; public static string Application { get; private set; } = ""; @@ -35,8 +35,8 @@ Downloads = Path.Combine(Base, "Downloads"); Logs = Path.Combine(Base, "Logs"); Integrations = Path.Combine(Base, "Integrations"); + Versions = Path.Combine(Base, "Versions"); Modifications = Path.Combine(Base, "Modifications"); - Roblox = Path.Combine(Base, "Roblox"); Application = Path.Combine(Base, $"{App.ProjectName}.exe"); } diff --git a/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/Matt.png b/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/Matt.png index 2f97480..ee6e100 100644 Binary files a/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/Matt.png and b/Bloxstrap/Resources/BootstrapperStyles/ByfronDialog/Matt.png differ diff --git a/Bloxstrap/Resources/MessageBox/Error.png b/Bloxstrap/Resources/MessageBox/Error.png index 278bdd4..c6506b1 100644 Binary files a/Bloxstrap/Resources/MessageBox/Error.png and b/Bloxstrap/Resources/MessageBox/Error.png differ diff --git a/Bloxstrap/Resources/MessageBox/FullQuality/Error.png b/Bloxstrap/Resources/MessageBox/FullQuality/Error.png new file mode 100644 index 0000000..278bdd4 Binary files /dev/null and b/Bloxstrap/Resources/MessageBox/FullQuality/Error.png differ diff --git a/Bloxstrap/Resources/MessageBox/FullQuality/Information.png b/Bloxstrap/Resources/MessageBox/FullQuality/Information.png new file mode 100644 index 0000000..3de3eec Binary files /dev/null and b/Bloxstrap/Resources/MessageBox/FullQuality/Information.png differ diff --git a/Bloxstrap/Resources/MessageBox/FullQuality/Question.png b/Bloxstrap/Resources/MessageBox/FullQuality/Question.png new file mode 100644 index 0000000..a5a6a10 Binary files /dev/null and b/Bloxstrap/Resources/MessageBox/FullQuality/Question.png differ diff --git a/Bloxstrap/Resources/MessageBox/FullQuality/Warning.png b/Bloxstrap/Resources/MessageBox/FullQuality/Warning.png new file mode 100644 index 0000000..80f4b4b Binary files /dev/null and b/Bloxstrap/Resources/MessageBox/FullQuality/Warning.png differ diff --git a/Bloxstrap/Resources/MessageBox/Information.png b/Bloxstrap/Resources/MessageBox/Information.png index 3de3eec..5d8f2b6 100644 Binary files a/Bloxstrap/Resources/MessageBox/Information.png and b/Bloxstrap/Resources/MessageBox/Information.png differ diff --git a/Bloxstrap/Resources/MessageBox/Question.png b/Bloxstrap/Resources/MessageBox/Question.png index a5a6a10..e23e4d1 100644 Binary files a/Bloxstrap/Resources/MessageBox/Question.png and b/Bloxstrap/Resources/MessageBox/Question.png differ diff --git a/Bloxstrap/Resources/MessageBox/Warning.png b/Bloxstrap/Resources/MessageBox/Warning.png index 80f4b4b..3009e82 100644 Binary files a/Bloxstrap/Resources/MessageBox/Warning.png and b/Bloxstrap/Resources/MessageBox/Warning.png differ diff --git a/Bloxstrap/Resources/Mods/Sounds/Empty.mp3 b/Bloxstrap/Resources/Mods/Sounds/Empty.mp3 index 9cd8436..a428a83 100644 Binary files a/Bloxstrap/Resources/Mods/Sounds/Empty.mp3 and b/Bloxstrap/Resources/Mods/Sounds/Empty.mp3 differ diff --git a/Bloxstrap/Resources/Strings.Designer.cs b/Bloxstrap/Resources/Strings.Designer.cs index f50f201..fd14b8f 100644 --- a/Bloxstrap/Resources/Strings.Designer.cs +++ b/Bloxstrap/Resources/Strings.Designer.cs @@ -70,7 +70,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to These are the people who've supported Bloxstrap through [Ko-fi]({0}). A massive thank you to everyone here! + /// Looks up a localized string similar to These are the people who've supported Bloxstrap through Ko-fi. A massive thank you to everyone here! ///Every person here is ranked by their overall pledge.. /// public static string About_Supporters_Description { @@ -316,7 +316,7 @@ namespace Bloxstrap.Resources { } /// - /// Looks up a localized string similar to Roblox is currently running, but must be closed before uninstalling Bloxstrap. Would you like close Roblox now?. + /// Looks up a localized string similar to Roblox is currently running, but must be closed before uninstalling Bloxstrap. Would you like to close Roblox now?. /// public static string Bootstrapper_Uninstall_RobloxRunning { get { @@ -1626,15 +1626,6 @@ namespace Bloxstrap.Resources { } } - /// - /// Looks up a localized string similar to Support us on Ko-fi!. - /// - public static string LaunchMenu_Donate { - get { - return ResourceManager.GetString("LaunchMenu.Donate", resourceCulture); - } - } - /// /// Looks up a localized string similar to Launch Roblox. /// @@ -1644,6 +1635,15 @@ namespace Bloxstrap.Resources { } } + /// + /// Looks up a localized string similar to Launch Roblox Studio. + /// + public static string LaunchMenu_LaunchRobloxStudio { + get { + return ResourceManager.GetString("LaunchMenu.LaunchRobloxStudio", resourceCulture); + } + } + /// /// Looks up a localized string similar to See the Wiki for help. /// diff --git a/Bloxstrap/Resources/Strings.resx b/Bloxstrap/Resources/Strings.resx index 96f6d0b..c8a5479 100644 --- a/Bloxstrap/Resources/Strings.resx +++ b/Bloxstrap/Resources/Strings.resx @@ -175,7 +175,7 @@ Bloxstrap has successfully uninstalled - Roblox is currently running, but must be closed before uninstalling Bloxstrap. Would you like close Roblox now? + Roblox is currently running, but must be closed before uninstalling Bloxstrap. Would you like to close Roblox now? Roblox requires the use of Windows Media Foundation components. You appear to be missing them, likely because you are using an N edition of Windows. Please install them first, and then launch Roblox. @@ -1116,7 +1116,7 @@ Check if Roblox works with [the original launcher]({1}). If it doesn't, then thi Supporters - These are the people who've supported Bloxstrap through [Ko-fi]({0}). A massive thank you to everyone here! + These are the people who've supported Bloxstrap through Ko-fi. A massive thank you to everyone here! Every person here is ranked by their overall pledge. @@ -1229,14 +1229,13 @@ Would you like to enable test mode? Install The word "Install" is being used as a verb in this instance, like the other navigation button texts of "Next" and "Back" - - Support us on Ko-fi! - Call-to-action button - Icons Name of the folder that gets created according to the "create shortcut icons" option. Ensure that it is a valid folder name. + + Launch Roblox Studio + Version {0} diff --git a/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml b/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml index 8bdd277..486cd12 100644 --- a/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml +++ b/Bloxstrap/UI/Elements/About/Pages/AboutPage.xaml @@ -97,6 +97,7 @@ + diff --git a/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml b/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml index 9620493..81fb1c6 100644 --- a/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml +++ b/Bloxstrap/UI/Elements/About/Pages/SupportersPage.xaml @@ -15,7 +15,7 @@ Scrollable="True"> - + diff --git a/Bloxstrap/UI/Elements/Dialogs/LaunchMenuDialog.xaml b/Bloxstrap/UI/Elements/Dialogs/LaunchMenuDialog.xaml index 17d0fff..7388f73 100644 --- a/Bloxstrap/UI/Elements/Dialogs/LaunchMenuDialog.xaml +++ b/Bloxstrap/UI/Elements/Dialogs/LaunchMenuDialog.xaml @@ -52,8 +52,7 @@ - - + @@ -64,6 +63,12 @@ + + + + + + diff --git a/Bloxstrap/UI/Elements/Settings/Pages/ShortcutsPage.xaml b/Bloxstrap/UI/Elements/Settings/Pages/ShortcutsPage.xaml index 38241ae..710b09a 100644 --- a/Bloxstrap/UI/Elements/Settings/Pages/ShortcutsPage.xaml +++ b/Bloxstrap/UI/Elements/Settings/Pages/ShortcutsPage.xaml @@ -49,14 +49,31 @@ + + + + + + - + - + + + + + diff --git a/Bloxstrap/UI/ViewModels/Dialogs/LaunchMenuViewModel.cs b/Bloxstrap/UI/ViewModels/Dialogs/LaunchMenuViewModel.cs index 25962a9..0c44b5d 100644 --- a/Bloxstrap/UI/ViewModels/Dialogs/LaunchMenuViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Dialogs/LaunchMenuViewModel.cs @@ -1,4 +1,5 @@ -using System.Windows.Input; +using System.Windows; +using System.Windows.Input; using CommunityToolkit.Mvvm.Input; using Bloxstrap.UI.Elements.About; @@ -9,10 +10,14 @@ namespace Bloxstrap.UI.ViewModels.Installer { public string Version => string.Format(Strings.Menu_About_Version, App.Version); + public Visibility RobloxStudioOptionVisibility => App.IsStudioVisible ? Visibility.Visible : Visibility.Collapsed; + public ICommand LaunchSettingsCommand => new RelayCommand(LaunchSettings); public ICommand LaunchRobloxCommand => new RelayCommand(LaunchRoblox); + public ICommand LaunchRobloxStudioCommand => new RelayCommand(LaunchRobloxStudio); + public ICommand LaunchAboutCommand => new RelayCommand(LaunchAbout); public event EventHandler? CloseWindowRequest; @@ -21,6 +26,8 @@ namespace Bloxstrap.UI.ViewModels.Installer private void LaunchRoblox() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRoblox); + private void LaunchRobloxStudio() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRobloxStudio); + private void LaunchAbout() => new MainWindow().ShowDialog(); } } diff --git a/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs b/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs index 016f69f..63ce62f 100644 --- a/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Settings/BloxstrapViewModel.cs @@ -62,6 +62,7 @@ namespace Bloxstrap.UI.ViewModels.Settings } zipStream.CloseEntry(); + zipStream.Finish(); memStream.Position = 0; using var outputStream = File.OpenWrite(dialog.FileName); diff --git a/Bloxstrap/UI/ViewModels/Settings/ShortcutsViewModel.cs b/Bloxstrap/UI/ViewModels/Settings/ShortcutsViewModel.cs index 413bb13..caef426 100644 --- a/Bloxstrap/UI/ViewModels/Settings/ShortcutsViewModel.cs +++ b/Bloxstrap/UI/ViewModels/Settings/ShortcutsViewModel.cs @@ -1,16 +1,17 @@ -using Bloxstrap.Models.SettingTasks; -using Bloxstrap.Resources; - -namespace Bloxstrap.UI.ViewModels.Settings +namespace Bloxstrap.UI.ViewModels.Settings { public class ShortcutsViewModel : NotifyPropertyChangedViewModel { + public bool IsStudioOptionVisible => App.IsStudioVisible; + public ShortcutTask DesktopIconTask { get; } = new("Desktop", Paths.Desktop, $"{App.ProjectName}.lnk"); public ShortcutTask StartMenuIconTask { get; } = new("StartMenu", Paths.WindowsStartMenu, $"{App.ProjectName}.lnk"); public ShortcutTask PlayerIconTask { get; } = new("RobloxPlayer", Paths.Desktop, $"{Strings.LaunchMenu_LaunchRoblox}.lnk", "-player"); + public ShortcutTask StudioIconTask { get; } = new("RobloxStudio", Paths.Desktop, $"{Strings.LaunchMenu_LaunchRobloxStudio}.lnk", "-studio"); + public ShortcutTask SettingsIconTask { get; } = new("Settings", Paths.Desktop, $"{Strings.Menu_Title}.lnk", "-settings"); public ExtractIconsTask ExtractIconsTask { get; } = new(); diff --git a/Bloxstrap/Utilities.cs b/Bloxstrap/Utilities.cs index b1cd93d..eeea1d6 100644 --- a/Bloxstrap/Utilities.cs +++ b/Bloxstrap/Utilities.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using Bloxstrap.AppData; +using System.ComponentModel; namespace Bloxstrap { @@ -29,6 +30,18 @@ namespace Bloxstrap } } + public static Version GetVersionFromString(string version) + { + if (version.StartsWith('v')) + version = version[1..]; + + int idx = version.IndexOf('+'); // commit info + if (idx != -1) + version = version[..idx]; + + return new Version(version); + } + /// /// /// @@ -44,8 +57,8 @@ namespace Bloxstrap { try { - var version1 = new Version(versionStr1.Replace("v", "")); - var version2 = new Version(versionStr2.Replace("v", "")); + var version1 = GetVersionFromString(versionStr1); + var version2 = GetVersionFromString(versionStr2); return (VersionComparison)version1.CompareTo(version2); } @@ -64,9 +77,9 @@ namespace Bloxstrap public static string GetRobloxVersion(bool studio) { - string fileName = studio ? "Studio/RobloxStudioBeta.exe" : "Player/RobloxPlayerBeta.exe"; + IAppData data = studio ? new RobloxStudioData() : new RobloxPlayerData(); - string playerLocation = Path.Combine(Paths.Roblox, fileName); + string playerLocation = data.ExecutablePath; if (!File.Exists(playerLocation)) return ""; diff --git a/Bloxstrap/Watcher.cs b/Bloxstrap/Watcher.cs index 660d5d4..eef397e 100644 --- a/Bloxstrap/Watcher.cs +++ b/Bloxstrap/Watcher.cs @@ -1,4 +1,5 @@ -using Bloxstrap.Integrations; +using Bloxstrap.AppData; +using Bloxstrap.Integrations; using Bloxstrap.Models; namespace Bloxstrap @@ -30,7 +31,7 @@ namespace Bloxstrap #if DEBUG if (String.IsNullOrEmpty(watcherDataArg)) { - string path = Path.Combine(Paths.Roblox, "Player", "RobloxPlayerBeta.exe"); + string path = new RobloxPlayerData().ExecutablePath; using var gameClientProcess = Process.Start(path); _watcherData = new() { ProcessId = gameClientProcess.Id }; diff --git a/README.md b/README.md index 906d8a8..4f31fc6 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ > The only official places to download Bloxstrap are this GitHub repository and [bloxstraplabs.com](https://bloxstraplabs.com). Any other websites offering downloads or claiming to be us are not controlled by us.

- - + +

@@ -22,7 +22,7 @@ Bloxstrap is a third-party replacement for the standard Roblox bootstrapper, providing additional useful features and improvements. -Running into a problem or need help with something? [Check out the Wiki](https://github.com/pizzaboxer/bloxstrap/wiki). If you can't find anything, or would like to suggest something, please [submit an issue](https://github.com/pizzaboxer/bloxstrap/issues). +Running into a problem or need help with something? [Check out the Wiki](https://github.com/bloxstraplabs/bloxstrap/wiki). If you can't find anything, or would like to suggest something, please [submit an issue](https://github.com/bloxstraplabs/bloxstrap/issues). Bloxstrap is only supported for PCs running Windows. @@ -34,11 +34,11 @@ Bloxstrap is only supported for PCs running Windows. **Q: Can using this get me banned?** -**A:** No, it shouldn't. Bloxstrap doesn't interact with the Roblox client in the same way that exploits do. [Read more about that here.](https://github.com/pizzaboxer/bloxstrap/wiki/Why-it's-not-reasonably-possible-for-you-to-be-banned-by-Bloxstrap) +**A:** No, it shouldn't. Bloxstrap doesn't interact with the Roblox client in the same way that exploits do. [Read more about that here.](https://github.com/bloxstraplabs/bloxstrap/wiki/Why-it's-not-reasonably-possible-for-you-to-be-banned-by-Bloxstrap) **Q: Why was multi-instance launching removed?** -**A:** It was removed starting with v2.6.0 for the [reasons stated here](https://github.com/pizzaboxer/bloxstrap/wiki/Plans-to-remove-multi%E2%80%90instance-launching-from-Bloxstrap). It may be added back in the future when there are less issues with doing so. +**A:** It was removed starting with v2.6.0 for the [reasons stated here](https://github.com/bloxstraplabs/bloxstrap/wiki/Plans-to-remove-multi%E2%80%90instance-launching-from-Bloxstrap). It may be added back in the future when there are less issues with doing so. ## Features @@ -48,7 +48,7 @@ Bloxstrap is only supported for PCs running Windows. - Ability to configure graphics fidelity and UI experience ## Installing -Download the [latest release of Bloxstrap](https://github.com/pizzaboxer/bloxstrap/releases/latest), and run it. Configure your preferences if needed, and install. That's about it! +Download the [latest release of Bloxstrap](https://github.com/bloxstraplabs/bloxstrap/releases/latest), and run it. Configure your preferences if needed, and install. That's about it! Alternatively, you can install Bloxstrap via [Winget](https://winstall.app/apps/pizzaboxer.Bloxstrap) by running this in a Command Prompt window: ``` @@ -66,19 +66,19 @@ Once installed, Bloxstrap is added to your Start Menu, where you can access the Bloxstrap uses the [WPF UI](https://github.com/lepoco/wpfui) library for the user interface design. We currently use and maintain our own fork of WPF UI at [bloxstraplabs/wpfui](https://github.com/bloxstraplabs/wpfui). -[shield-repo-license]: https://img.shields.io/github/license/pizzaboxer/bloxstrap -[shield-repo-workflow]: https://img.shields.io/github/actions/workflow/status/pizzaboxer/bloxstrap/ci-release.yml?branch=main&label=builds -[shield-repo-releases]: https://img.shields.io/github/downloads/pizzaboxer/bloxstrap/latest/total?color=981bfe -[shield-repo-latest]: https://img.shields.io/github/v/release/pizzaboxer/bloxstrap?color=7a39fb +[shield-repo-license]: https://img.shields.io/github/license/bloxstraplabs/bloxstrap +[shield-repo-workflow]: https://img.shields.io/github/actions/workflow/status/bloxstraplabs/bloxstrap/ci-release.yml?branch=main&label=builds +[shield-repo-releases]: https://img.shields.io/github/downloads/bloxstraplabs/bloxstrap/latest/total?color=981bfe +[shield-repo-latest]: https://img.shields.io/github/v/release/bloxstraplabs/bloxstrap?color=7a39fb [shield-crowdin-status]: https://badges.crowdin.net/bloxstrap/localized.svg [shield-discord-server]: https://img.shields.io/discord/1099468797410283540?logo=discord&logoColor=white&label=discord&color=4d3dff [shield-tenor-meme]: https://img.shields.io/badge/mom_made-pizza_rolls-orange -[repo-license]: https://github.com/pizzaboxer/bloxstrap/blob/main/LICENSE -[repo-actions]: https://github.com/pizzaboxer/bloxstrap/actions -[repo-releases]: https://github.com/pizzaboxer/bloxstrap/releases -[repo-latest]: https://github.com/pizzaboxer/bloxstrap/releases/latest +[repo-license]: https://github.com/bloxstraplabs/bloxstrap/blob/main/LICENSE +[repo-actions]: https://github.com/bloxstraplabs/bloxstrap/actions +[repo-releases]: https://github.com/bloxstraplabs/bloxstrap/releases +[repo-latest]: https://github.com/bloxstraplabs/bloxstrap/releases/latest [crowdin-project]: https://crowdin.com/project/bloxstrap [discord-invite]: https://discord.gg/nKjV3mGq6R