Merge branch 'main' into feature/settings-backup
1
.github/FUNDING.yml
vendored
@ -1 +0,0 @@
|
|||||||
ko_fi: boxerpizza
|
|
@ -42,6 +42,8 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
public static bool IsProductionBuild => IsActionBuild && BuildMetadata.CommitRef.StartsWith("tag", StringComparison.Ordinal);
|
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 MD5 MD5Provider = MD5.Create();
|
||||||
|
|
||||||
public static readonly Logger Logger = new();
|
public static readonly Logger Logger = new();
|
||||||
|
@ -43,12 +43,12 @@ namespace Bloxstrap.AppData
|
|||||||
|
|
||||||
public virtual string ExecutableName { get; } = null!;
|
public virtual string ExecutableName { get; } = null!;
|
||||||
|
|
||||||
public virtual string Directory { get; } = null!;
|
public string Directory => Path.Combine(Paths.Versions, State.VersionGuid);
|
||||||
|
|
||||||
public string LockFilePath => Path.Combine(Directory, "Bloxstrap.lock");
|
|
||||||
|
|
||||||
public string ExecutablePath => Path.Combine(Directory, ExecutableName);
|
public string ExecutablePath => Path.Combine(Directory, ExecutableName);
|
||||||
|
|
||||||
|
public virtual AppState State { get; } = null!;
|
||||||
|
|
||||||
public virtual IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; }
|
public virtual IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
@ -12,10 +12,6 @@
|
|||||||
|
|
||||||
string Directory { get; }
|
string Directory { get; }
|
||||||
|
|
||||||
string OldDirectory { get; }
|
|
||||||
|
|
||||||
string LockFilePath { get; }
|
|
||||||
|
|
||||||
string ExecutablePath { get; }
|
string ExecutablePath { get; }
|
||||||
|
|
||||||
AppState State { get; }
|
AppState State { get; }
|
||||||
|
@ -16,11 +16,7 @@ namespace Bloxstrap.AppData
|
|||||||
|
|
||||||
public override string ExecutableName => "RobloxPlayerBeta.exe";
|
public override string ExecutableName => "RobloxPlayerBeta.exe";
|
||||||
|
|
||||||
public override string Directory => Path.Combine(Paths.Roblox, "Player");
|
public override AppState State => App.State.Prop.Player;
|
||||||
|
|
||||||
public string OldDirectory => Path.Combine(Paths.Roblox, "Player.old");
|
|
||||||
|
|
||||||
public AppState State => App.State.Prop.Player;
|
|
||||||
|
|
||||||
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
|
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
|
@ -10,11 +10,7 @@
|
|||||||
|
|
||||||
public override string ExecutableName => "RobloxStudioBeta.exe";
|
public override string ExecutableName => "RobloxStudioBeta.exe";
|
||||||
|
|
||||||
public override string Directory => Path.Combine(Paths.Roblox, "Studio");
|
public override AppState State => App.State.Prop.Studio;
|
||||||
|
|
||||||
public string OldDirectory => Path.Combine(Paths.Roblox, "Studio.old");
|
|
||||||
|
|
||||||
public AppState State => App.State.Prop.Studio;
|
|
||||||
|
|
||||||
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
|
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
|
||||||
{
|
{
|
||||||
|
@ -7,8 +7,8 @@
|
|||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
<UseWindowsForms>True</UseWindowsForms>
|
<UseWindowsForms>True</UseWindowsForms>
|
||||||
<ApplicationIcon>Bloxstrap.ico</ApplicationIcon>
|
<ApplicationIcon>Bloxstrap.ico</ApplicationIcon>
|
||||||
<Version>2.8.1</Version>
|
<Version>2.8.2</Version>
|
||||||
<FileVersion>2.8.1</FileVersion>
|
<FileVersion>2.8.2</FileVersion>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
|
||||||
|
@ -50,6 +50,7 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
||||||
private string _latestVersionGuid = null!;
|
private string _latestVersionGuid = null!;
|
||||||
|
private string _latestVersionDirectory = null!;
|
||||||
private PackageManifest _versionPackageManifest = null!;
|
private PackageManifest _versionPackageManifest = null!;
|
||||||
|
|
||||||
private bool _isInstalling = false;
|
private bool _isInstalling = false;
|
||||||
@ -58,7 +59,7 @@ namespace Bloxstrap
|
|||||||
private double _taskbarProgressMaximum;
|
private double _taskbarProgressMaximum;
|
||||||
private long _totalDownloadedBytes = 0;
|
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 bool _noConnection = false;
|
||||||
|
|
||||||
private AsyncMutex? _mutex;
|
private AsyncMutex? _mutex;
|
||||||
@ -313,6 +314,7 @@ namespace Bloxstrap
|
|||||||
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
|
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
|
||||||
|
|
||||||
_latestVersionGuid = clientVersion.VersionGuid;
|
_latestVersionGuid = clientVersion.VersionGuid;
|
||||||
|
_latestVersionDirectory = Path.Combine(Paths.Versions, _latestVersionGuid);
|
||||||
|
|
||||||
string pkgManifestUrl = Deployment.GetLocation($"/{_latestVersionGuid}-rbxPkgManifest.txt");
|
string pkgManifestUrl = Deployment.GetLocation($"/{_latestVersionGuid}-rbxPkgManifest.txt");
|
||||||
var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl);
|
var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl);
|
||||||
@ -357,8 +359,11 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
string? logFileName = null;
|
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))
|
if (!Directory.Exists(rbxLogDir))
|
||||||
Directory.CreateDirectory(rbxLogDir);
|
Directory.CreateDirectory(rbxLogDir);
|
||||||
|
|
||||||
@ -510,18 +515,13 @@ namespace Bloxstrap
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// clean up install
|
// clean up install
|
||||||
if (Directory.Exists(AppData.Directory))
|
if (Directory.Exists(_latestVersionDirectory))
|
||||||
Directory.Delete(AppData.Directory, true);
|
Directory.Delete(_latestVersionDirectory, true);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Could not fully clean up installation!");
|
App.Logger.WriteLine(LOG_IDENT, "Could not fully clean up installation!");
|
||||||
App.Logger.WriteException(LOG_IDENT, ex);
|
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)
|
else if (_appPid != 0)
|
||||||
@ -649,6 +649,48 @@ namespace Bloxstrap
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Roblox Install
|
#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()
|
private async Task UpgradeRoblox()
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "Bootstrapper::UpgradeRoblox";
|
const string LOG_IDENT = "Bootstrapper::UpgradeRoblox";
|
||||||
@ -660,55 +702,11 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
Directory.CreateDirectory(Paths.Base);
|
Directory.CreateDirectory(Paths.Base);
|
||||||
Directory.CreateDirectory(Paths.Downloads);
|
Directory.CreateDirectory(Paths.Downloads);
|
||||||
Directory.CreateDirectory(Paths.Roblox);
|
Directory.CreateDirectory(Paths.Versions);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
_isInstalling = true;
|
_isInstalling = true;
|
||||||
|
|
||||||
Directory.CreateDirectory(AppData.Directory);
|
Directory.CreateDirectory(_latestVersionDirectory);
|
||||||
|
|
||||||
// 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();
|
|
||||||
|
|
||||||
var cachedPackageHashes = Directory.GetFiles(Paths.Downloads).Select(x => Path.GetFileName(x));
|
var cachedPackageHashes = Directory.GetFiles(Paths.Downloads).Select(x => Path.GetFileName(x));
|
||||||
|
|
||||||
@ -776,7 +774,7 @@ namespace Bloxstrap
|
|||||||
await Task.WhenAll(extractionTasks);
|
await Task.WhenAll(extractionTasks);
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Writing AppSettings.xml...");
|
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)
|
if (_cancelTokenSource.IsCancellationRequested)
|
||||||
return;
|
return;
|
||||||
@ -811,7 +809,7 @@ namespace Bloxstrap
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string baseDirectory = Path.Combine(AppData.Directory, AppData.PackageDirectoryMap[package.Name]);
|
string baseDirectory = Path.Combine(_latestVersionDirectory, AppData.PackageDirectoryMap[package.Name]);
|
||||||
|
|
||||||
ExtractPackage(package);
|
ExtractPackage(package);
|
||||||
|
|
||||||
@ -835,6 +833,8 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
// finishing and cleanup
|
// finishing and cleanup
|
||||||
|
|
||||||
|
MigrateCompatibilityFlags();
|
||||||
|
|
||||||
AppData.State.VersionGuid = _latestVersionGuid;
|
AppData.State.VersionGuid = _latestVersionGuid;
|
||||||
|
|
||||||
AppData.State.PackageHashes.Clear();
|
AppData.State.PackageHashes.Clear();
|
||||||
@ -842,6 +842,8 @@ namespace Bloxstrap
|
|||||||
foreach (var package in _versionPackageManifest)
|
foreach (var package in _versionPackageManifest)
|
||||||
AppData.State.PackageHashes.Add(package.Name, package.Signature);
|
AppData.State.PackageHashes.Add(package.Name, package.Signature);
|
||||||
|
|
||||||
|
CleanupVersionsFolder();
|
||||||
|
|
||||||
var allPackageHashes = new List<string>();
|
var allPackageHashes = new List<string>();
|
||||||
|
|
||||||
allPackageHashes.AddRange(App.State.Prop.Player.PackageHashes.Values);
|
allPackageHashes.AddRange(App.State.Prop.Player.PackageHashes.Values);
|
||||||
@ -882,8 +884,6 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
App.State.Save();
|
App.State.Save();
|
||||||
|
|
||||||
lockFile.Delete();
|
|
||||||
|
|
||||||
_isInstalling = false;
|
_isInstalling = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -916,7 +916,17 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
const string path = "rbxasset://fonts/CustomFont.ttf";
|
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 jsonFilename = Path.GetFileName(jsonFilePath);
|
||||||
string modFilepath = Path.Combine(modFontFamiliesFolder, jsonFilename);
|
string modFilepath = Path.Combine(modFontFamiliesFolder, jsonFilename);
|
||||||
@ -977,7 +987,7 @@ namespace Bloxstrap
|
|||||||
modFolderFiles.Add(relativeFile);
|
modFolderFiles.Add(relativeFile);
|
||||||
|
|
||||||
string fileModFolder = Path.Combine(Paths.Modifications, 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))
|
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");
|
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))
|
if (File.Exists(versionFileLocation))
|
||||||
File.Delete(versionFileLocation);
|
File.Delete(versionFileLocation);
|
||||||
@ -1201,7 +1211,7 @@ namespace Bloxstrap
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
string packageFolder = Path.Combine(AppData.Directory, packageDir);
|
string packageFolder = Path.Combine(_latestVersionDirectory, packageDir);
|
||||||
string? fileFilter = null;
|
string? fileFilter = null;
|
||||||
|
|
||||||
// for sharpziplib, each file in the filter needs to be a regex
|
// for sharpziplib, each file in the filter needs to be a regex
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
{
|
{
|
||||||
Terminate,
|
Terminate,
|
||||||
LaunchSettings,
|
LaunchSettings,
|
||||||
LaunchRoblox
|
LaunchRoblox,
|
||||||
|
LaunchRobloxStudio
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,5 +17,19 @@ namespace Bloxstrap.Extensions
|
|||||||
App.Terminate(ErrorCode.ERROR_INSTALL_FAILURE);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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<T>(IReadOnlyDictionary<T, string> mapping, string prefix, string value) where T : Enum
|
public T GetPresetEnum<T>(IReadOnlyDictionary<T, string> mapping, string prefix, string value) where T : Enum
|
||||||
{
|
{
|
||||||
|
@ -91,7 +91,7 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
App.Settings.Prop.EnableAnalytics = EnableAnalytics;
|
App.Settings.Prop.EnableAnalytics = EnableAnalytics;
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(App.State.Prop.Studio.VersionGuid))
|
if (App.IsStudioVisible)
|
||||||
WindowsRegistry.RegisterStudio();
|
WindowsRegistry.RegisterStudio();
|
||||||
|
|
||||||
App.Settings.Save();
|
App.Settings.Save();
|
||||||
@ -124,6 +124,10 @@ namespace Bloxstrap
|
|||||||
if (String.Compare(Directory.GetParent(InstallLocation)?.FullName, Paths.UserProfile, StringComparison.InvariantCultureIgnoreCase) == 0)
|
if (String.Compare(Directory.GetParent(InstallLocation)?.FullName, Paths.UserProfile, StringComparison.InvariantCultureIgnoreCase) == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// prevent from installing into the program files folder
|
||||||
|
if (InstallLocation.Contains("Program Files"))
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -190,7 +194,7 @@ namespace Bloxstrap
|
|||||||
if (!String.IsNullOrEmpty(App.State.Prop.Player.VersionGuid))
|
if (!String.IsNullOrEmpty(App.State.Prop.Player.VersionGuid))
|
||||||
processes.AddRange(Process.GetProcessesByName(App.RobloxPlayerAppName));
|
processes.AddRange(Process.GetProcessesByName(App.RobloxPlayerAppName));
|
||||||
|
|
||||||
if (!String.IsNullOrEmpty(App.State.Prop.Studio.VersionGuid))
|
if (App.IsStudioVisible)
|
||||||
processes.AddRange(Process.GetProcessesByName(App.RobloxStudioAppName));
|
processes.AddRange(Process.GetProcessesByName(App.RobloxStudioAppName));
|
||||||
|
|
||||||
// prompt to shutdown roblox if its currently running
|
// prompt to shutdown roblox if its currently running
|
||||||
@ -283,8 +287,8 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
() => File.Delete(StartMenuShortcut),
|
() => File.Delete(StartMenuShortcut),
|
||||||
|
|
||||||
|
() => Directory.Delete(Paths.Versions, true),
|
||||||
() => Directory.Delete(Paths.Downloads, true),
|
() => Directory.Delete(Paths.Downloads, true),
|
||||||
() => Directory.Delete(Paths.Roblox, true),
|
|
||||||
|
|
||||||
() => File.Delete(App.State.FileLocation)
|
() => File.Delete(App.State.FileLocation)
|
||||||
};
|
};
|
||||||
@ -477,21 +481,6 @@ namespace Bloxstrap
|
|||||||
App.FastFlags.SetValue("DFFlagVariableDPIScale2", null);
|
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 (Utilities.CompareVersions(existingVer, "2.6.0") == VersionComparison.LessThan)
|
||||||
{
|
{
|
||||||
if (App.Settings.Prop.UseDisableAppPatch)
|
if (App.Settings.Prop.UseDisableAppPatch)
|
||||||
@ -556,38 +545,8 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
WindowsRegistry.RegisterPlayer();
|
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);
|
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)
|
if (Utilities.CompareVersions(existingVer, "2.8.1") == VersionComparison.LessThan)
|
||||||
@ -604,6 +563,17 @@ namespace Bloxstrap
|
|||||||
App.FastFlags.SetValue("FFlagEnableInGameMenuChromeABTest4", null);
|
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.Settings.Save();
|
||||||
App.FastFlags.Save();
|
App.FastFlags.Save();
|
||||||
|
@ -68,7 +68,7 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
File.WriteAllText(FileLocation, JsonSerializer.Serialize(Prop, new JsonSerializerOptions { WriteIndented = true }));
|
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.WriteLine(LOG_IDENT, "Failed to save");
|
||||||
App.Logger.WriteException(LOG_IDENT, ex);
|
App.Logger.WriteException(LOG_IDENT, ex);
|
||||||
|
@ -21,6 +21,10 @@ namespace Bloxstrap
|
|||||||
LaunchRoblox(LaunchMode.Player);
|
LaunchRoblox(LaunchMode.Player);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case NextAction.LaunchRobloxStudio:
|
||||||
|
LaunchRoblox(LaunchMode.Studio);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
App.Terminate(isUnfinishedInstall ? ErrorCode.ERROR_INSTALL_USEREXIT : ErrorCode.ERROR_SUCCESS);
|
App.Terminate(isUnfinishedInstall ? ErrorCode.ERROR_INSTALL_USEREXIT : ErrorCode.ERROR_SUCCESS);
|
||||||
break;
|
break;
|
||||||
|
@ -53,6 +53,10 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
const string LOG_IDENT = "LaunchSettings";
|
const string LOG_IDENT = "LaunchSettings";
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, $"Launched with arguments: {string.Join(' ', args)}");
|
||||||
|
#endif
|
||||||
|
|
||||||
Args = args;
|
Args = args;
|
||||||
|
|
||||||
// build flag map
|
// build flag map
|
||||||
@ -125,7 +129,23 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
RobloxLaunchMode = LaunchMode.Studio;
|
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}\"";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System.Web;
|
using System.Web;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Input;
|
using System.Windows.Input;
|
||||||
|
using Bloxstrap.AppData;
|
||||||
using Bloxstrap.Models.APIs;
|
using Bloxstrap.Models.APIs;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ namespace Bloxstrap.Models.Entities
|
|||||||
|
|
||||||
private void RejoinServer()
|
private void RejoinServer()
|
||||||
{
|
{
|
||||||
string playerPath = Path.Combine(Paths.Roblox, "Player", "RobloxPlayerBeta.exe");
|
string playerPath = new RobloxPlayerData().ExecutablePath;
|
||||||
|
|
||||||
Process.Start(playerPath, GetInviteDeeplink(false));
|
Process.Start(playerPath, GetInviteDeeplink(false));
|
||||||
}
|
}
|
||||||
|
@ -20,8 +20,8 @@
|
|||||||
public static string Downloads { get; private set; } = "";
|
public static string Downloads { get; private set; } = "";
|
||||||
public static string Logs { get; private set; } = "";
|
public static string Logs { get; private set; } = "";
|
||||||
public static string Integrations { 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 Modifications { get; private set; } = "";
|
||||||
public static string Roblox { get; private set; } = "";
|
|
||||||
|
|
||||||
public static string Application { get; private set; } = "";
|
public static string Application { get; private set; } = "";
|
||||||
|
|
||||||
@ -35,8 +35,8 @@
|
|||||||
Downloads = Path.Combine(Base, "Downloads");
|
Downloads = Path.Combine(Base, "Downloads");
|
||||||
Logs = Path.Combine(Base, "Logs");
|
Logs = Path.Combine(Base, "Logs");
|
||||||
Integrations = Path.Combine(Base, "Integrations");
|
Integrations = Path.Combine(Base, "Integrations");
|
||||||
|
Versions = Path.Combine(Base, "Versions");
|
||||||
Modifications = Path.Combine(Base, "Modifications");
|
Modifications = Path.Combine(Base, "Modifications");
|
||||||
Roblox = Path.Combine(Base, "Roblox");
|
|
||||||
|
|
||||||
Application = Path.Combine(Base, $"{App.ProjectName}.exe");
|
Application = Path.Combine(Base, $"{App.ProjectName}.exe");
|
||||||
}
|
}
|
||||||
|
Before Width: | Height: | Size: 241 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 1.9 KiB |
BIN
Bloxstrap/Resources/MessageBox/FullQuality/Error.png
Normal file
After Width: | Height: | Size: 56 KiB |
BIN
Bloxstrap/Resources/MessageBox/FullQuality/Information.png
Normal file
After Width: | Height: | Size: 58 KiB |
BIN
Bloxstrap/Resources/MessageBox/FullQuality/Question.png
Normal file
After Width: | Height: | Size: 59 KiB |
BIN
Bloxstrap/Resources/MessageBox/FullQuality/Warning.png
Normal file
After Width: | Height: | Size: 37 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 6.0 KiB |
22
Bloxstrap/Resources/Strings.Designer.cs
generated
@ -70,7 +70,7 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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..
|
///Every person here is ranked by their overall pledge..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string About_Supporters_Description {
|
public static string About_Supporters_Description {
|
||||||
@ -316,7 +316,7 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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?.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static string Bootstrapper_Uninstall_RobloxRunning {
|
public static string Bootstrapper_Uninstall_RobloxRunning {
|
||||||
get {
|
get {
|
||||||
@ -1626,15 +1626,6 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Looks up a localized string similar to Support us on Ko-fi!.
|
|
||||||
/// </summary>
|
|
||||||
public static string LaunchMenu_Donate {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("LaunchMenu.Donate", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Launch Roblox.
|
/// Looks up a localized string similar to Launch Roblox.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -1644,6 +1635,15 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Launch Roblox Studio.
|
||||||
|
/// </summary>
|
||||||
|
public static string LaunchMenu_LaunchRobloxStudio {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("LaunchMenu.LaunchRobloxStudio", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to See the Wiki for help.
|
/// Looks up a localized string similar to See the Wiki for help.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -175,7 +175,7 @@
|
|||||||
<value>Bloxstrap has successfully uninstalled</value>
|
<value>Bloxstrap has successfully uninstalled</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Bootstrapper.Uninstall.RobloxRunning" xml:space="preserve">
|
<data name="Bootstrapper.Uninstall.RobloxRunning" xml:space="preserve">
|
||||||
<value>Roblox is currently running, but must be closed before uninstalling Bloxstrap. Would you like close Roblox now?</value>
|
<value>Roblox is currently running, but must be closed before uninstalling Bloxstrap. Would you like to close Roblox now?</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Bootstrapper.WMFNotFound" xml:space="preserve">
|
<data name="Bootstrapper.WMFNotFound" xml:space="preserve">
|
||||||
<value>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.</value>
|
<value>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.</value>
|
||||||
@ -1116,7 +1116,7 @@ Check if Roblox works with [the original launcher]({1}). If it doesn't, then thi
|
|||||||
<value>Supporters</value>
|
<value>Supporters</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="About.Supporters.Description" xml:space="preserve">
|
<data name="About.Supporters.Description" xml:space="preserve">
|
||||||
<value>These are the people who've supported Bloxstrap through [Ko-fi]({0}). A massive thank you to everyone here!
|
<value>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.</value>
|
Every person here is ranked by their overall pledge.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="JsonManager.SettingsLoadFailed" xml:space="preserve">
|
<data name="JsonManager.SettingsLoadFailed" xml:space="preserve">
|
||||||
@ -1229,14 +1229,13 @@ Would you like to enable test mode?</value>
|
|||||||
<value>Install</value>
|
<value>Install</value>
|
||||||
<comment>The word "Install" is being used as a verb in this instance, like the other navigation button texts of "Next" and "Back"</comment>
|
<comment>The word "Install" is being used as a verb in this instance, like the other navigation button texts of "Next" and "Back"</comment>
|
||||||
</data>
|
</data>
|
||||||
<data name="LaunchMenu.Donate" xml:space="preserve">
|
|
||||||
<value>Support us on Ko-fi!</value>
|
|
||||||
<comment>Call-to-action button</comment>
|
|
||||||
</data>
|
|
||||||
<data name="Paths.Icons" xml:space="preserve">
|
<data name="Paths.Icons" xml:space="preserve">
|
||||||
<value>Icons</value>
|
<value>Icons</value>
|
||||||
<comment>Name of the folder that gets created according to the "create shortcut icons" option. Ensure that it is a valid folder name.</comment>
|
<comment>Name of the folder that gets created according to the "create shortcut icons" option. Ensure that it is a valid folder name.</comment>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="LaunchMenu.LaunchRobloxStudio" xml:space="preserve">
|
||||||
|
<value>Launch Roblox Studio</value>
|
||||||
|
</data>
|
||||||
<data name="Dialog.Exception.Version" xml:space="preserve">
|
<data name="Dialog.Exception.Version" xml:space="preserve">
|
||||||
<value>Version {0}</value>
|
<value>Version {0}</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -97,6 +97,7 @@
|
|||||||
|
|
||||||
<controls:Expander Grid.Column="0" Margin="0,0,4,0" HeaderIcon="Code24" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_Code}" IsExpanded="True">
|
<controls:Expander Grid.Column="0" Margin="0,0,4,0" HeaderIcon="Code24" HeaderText="{x:Static resources:Strings.Menu_About_Contributors_Code}" IsExpanded="True">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[pizzaboxer](https://github.com/pizzaboxer)" />
|
||||||
<controls:MarkdownTextBlock MarkdownText="[Matt](https://github.com/bluepilledgreat)" />
|
<controls:MarkdownTextBlock MarkdownText="[Matt](https://github.com/bluepilledgreat)" />
|
||||||
<controls:MarkdownTextBlock MarkdownText="[lolmanurfunny](https://github.com/lolmanurfunny)" />
|
<controls:MarkdownTextBlock MarkdownText="[lolmanurfunny](https://github.com/lolmanurfunny)" />
|
||||||
<controls:MarkdownTextBlock MarkdownText="[1011025m](https://github.com/1011025m)" />
|
<controls:MarkdownTextBlock MarkdownText="[1011025m](https://github.com/1011025m)" />
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
Scrollable="True">
|
Scrollable="True">
|
||||||
<StackPanel Margin="0,0,14,14">
|
<StackPanel Margin="0,0,14,14">
|
||||||
<TextBlock Text="{x:Static resources:Strings.About_Supporters_Title}" FontWeight="Medium" FontSize="24" />
|
<TextBlock Text="{x:Static resources:Strings.About_Supporters_Title}" FontWeight="Medium" FontSize="24" />
|
||||||
<controls:MarkdownTextBlock MarkdownText="{Binding Source={x:Static resources:Strings.About_Supporters_Description}, Converter={StaticResource StringFormatConverter}, ConverterParameter='https://ko-fi.com/boxerpizza'}" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
<controls:MarkdownTextBlock MarkdownText="{x:Static resources:Strings.About_Supporters_Description}" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
|
||||||
<Grid Margin="0,8,0,0">
|
<Grid Margin="0,8,0,0">
|
||||||
<Grid.Style>
|
<Grid.Style>
|
||||||
|
@ -52,8 +52,7 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Grid.Row="1" HorizontalAlignment="Center">
|
<StackPanel Grid.Row="1" HorizontalAlignment="Center">
|
||||||
<ui:Hyperlink Icon="QuestionCircle48" Content="{x:Static resources:Strings.About_Title}" Margin="0,0,0,8" Command="{Binding LaunchAboutCommand, Mode=OneTime}" HorizontalAlignment="Center" />
|
<ui:Hyperlink Icon="QuestionCircle48" Content="{x:Static resources:Strings.About_Title}" Command="{Binding LaunchAboutCommand, Mode=OneTime}" HorizontalAlignment="Center" />
|
||||||
<ui:Hyperlink Icon="Heart48" Content="{x:Static resources:Strings.LaunchMenu_Donate}" NavigateUri="https://ko-fi.com/boxerpizza" HorizontalAlignment="Center" />
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
@ -64,6 +63,12 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ui:CardAction>
|
</ui:CardAction>
|
||||||
|
|
||||||
|
<ui:CardAction Margin="0,8,0,0" Icon="ArrowRight12" Visibility="{Binding RobloxStudioOptionVisibility, Mode=OneTime}" Command="{Binding LaunchRobloxStudioCommand, Mode=OneTime}">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="{x:Static resources:Strings.LaunchMenu_LaunchRobloxStudio}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
|
||||||
<ui:CardAction Margin="0,8,0,0" TabIndex="1" Icon="Settings28" Command="{Binding LaunchSettingsCommand, Mode=OneTime}">
|
<ui:CardAction Margin="0,8,0,0" TabIndex="1" Icon="Settings28" Command="{Binding LaunchSettingsCommand, Mode=OneTime}">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock FontSize="14" Text="{x:Static resources:Strings.LaunchMenu_ConfigureSettings}" />
|
<TextBlock FontSize="14" Text="{x:Static resources:Strings.LaunchMenu_ConfigureSettings}" />
|
||||||
|
@ -49,14 +49,31 @@
|
|||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
|
<!-- https://stackoverflow.com/a/51967350 -->
|
||||||
|
<ColumnDefinition>
|
||||||
|
<ColumnDefinition.Style>
|
||||||
|
<Style TargetType="ColumnDefinition">
|
||||||
|
<Setter Property="Width" Value="*" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsStudioOptionVisible}" Value="False">
|
||||||
|
<Setter Property="Width" Value="0" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</ColumnDefinition.Style>
|
||||||
|
</ColumnDefinition>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<controls:OptionControl Grid.Column="0" Margin="0,0,4,0" Header="{x:Static resources:Strings.LaunchMenu_LaunchRoblox}">
|
<controls:OptionControl Grid.Column="0" Margin="0,0,2,0" Header="{x:Static resources:Strings.LaunchMenu_LaunchRoblox}">
|
||||||
<ui:ToggleSwitch IsChecked="{Binding PlayerIconTask.NewState, Mode=TwoWay}" />
|
<ui:ToggleSwitch IsChecked="{Binding PlayerIconTask.NewState, Mode=TwoWay}" />
|
||||||
</controls:OptionControl>
|
</controls:OptionControl>
|
||||||
|
|
||||||
<controls:OptionControl Grid.Column="1" Margin="4,0,0,0" Header="{x:Static resources:Strings.Menu_Title}">
|
<controls:OptionControl Grid.Column="1" Margin="2,0,2,0" Header="{x:Static resources:Strings.LaunchMenu_LaunchRobloxStudio}">
|
||||||
|
<ui:ToggleSwitch IsChecked="{Binding StudioIconTask.NewState, Mode=TwoWay}" />
|
||||||
|
</controls:OptionControl>
|
||||||
|
|
||||||
|
<controls:OptionControl Grid.Column="2" Margin="2,0,0,0" Header="{x:Static resources:Strings.Menu_Title}">
|
||||||
<ui:ToggleSwitch IsChecked="{Binding SettingsIconTask.NewState, Mode=TwoWay}" />
|
<ui:ToggleSwitch IsChecked="{Binding SettingsIconTask.NewState, Mode=TwoWay}" />
|
||||||
</controls:OptionControl>
|
</controls:OptionControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Windows.Input;
|
using System.Windows;
|
||||||
|
using System.Windows.Input;
|
||||||
using CommunityToolkit.Mvvm.Input;
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
|
||||||
using Bloxstrap.UI.Elements.About;
|
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 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 LaunchSettingsCommand => new RelayCommand(LaunchSettings);
|
||||||
|
|
||||||
public ICommand LaunchRobloxCommand => new RelayCommand(LaunchRoblox);
|
public ICommand LaunchRobloxCommand => new RelayCommand(LaunchRoblox);
|
||||||
|
|
||||||
|
public ICommand LaunchRobloxStudioCommand => new RelayCommand(LaunchRobloxStudio);
|
||||||
|
|
||||||
public ICommand LaunchAboutCommand => new RelayCommand(LaunchAbout);
|
public ICommand LaunchAboutCommand => new RelayCommand(LaunchAbout);
|
||||||
|
|
||||||
public event EventHandler<NextAction>? CloseWindowRequest;
|
public event EventHandler<NextAction>? CloseWindowRequest;
|
||||||
@ -21,6 +26,8 @@ namespace Bloxstrap.UI.ViewModels.Installer
|
|||||||
|
|
||||||
private void LaunchRoblox() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRoblox);
|
private void LaunchRoblox() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRoblox);
|
||||||
|
|
||||||
|
private void LaunchRobloxStudio() => CloseWindowRequest?.Invoke(this, NextAction.LaunchRobloxStudio);
|
||||||
|
|
||||||
private void LaunchAbout() => new MainWindow().ShowDialog();
|
private void LaunchAbout() => new MainWindow().ShowDialog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,7 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
|||||||
}
|
}
|
||||||
|
|
||||||
zipStream.CloseEntry();
|
zipStream.CloseEntry();
|
||||||
|
zipStream.Finish();
|
||||||
memStream.Position = 0;
|
memStream.Position = 0;
|
||||||
|
|
||||||
using var outputStream = File.OpenWrite(dialog.FileName);
|
using var outputStream = File.OpenWrite(dialog.FileName);
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
using Bloxstrap.Models.SettingTasks;
|
namespace Bloxstrap.UI.ViewModels.Settings
|
||||||
using Bloxstrap.Resources;
|
|
||||||
|
|
||||||
namespace Bloxstrap.UI.ViewModels.Settings
|
|
||||||
{
|
{
|
||||||
public class ShortcutsViewModel : NotifyPropertyChangedViewModel
|
public class ShortcutsViewModel : NotifyPropertyChangedViewModel
|
||||||
{
|
{
|
||||||
|
public bool IsStudioOptionVisible => App.IsStudioVisible;
|
||||||
|
|
||||||
public ShortcutTask DesktopIconTask { get; } = new("Desktop", Paths.Desktop, $"{App.ProjectName}.lnk");
|
public ShortcutTask DesktopIconTask { get; } = new("Desktop", Paths.Desktop, $"{App.ProjectName}.lnk");
|
||||||
|
|
||||||
public ShortcutTask StartMenuIconTask { get; } = new("StartMenu", Paths.WindowsStartMenu, $"{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 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 ShortcutTask SettingsIconTask { get; } = new("Settings", Paths.Desktop, $"{Strings.Menu_Title}.lnk", "-settings");
|
||||||
|
|
||||||
public ExtractIconsTask ExtractIconsTask { get; } = new();
|
public ExtractIconsTask ExtractIconsTask { get; } = new();
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.ComponentModel;
|
using Bloxstrap.AppData;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
namespace Bloxstrap
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -44,8 +57,8 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var version1 = new Version(versionStr1.Replace("v", ""));
|
var version1 = GetVersionFromString(versionStr1);
|
||||||
var version2 = new Version(versionStr2.Replace("v", ""));
|
var version2 = GetVersionFromString(versionStr2);
|
||||||
|
|
||||||
return (VersionComparison)version1.CompareTo(version2);
|
return (VersionComparison)version1.CompareTo(version2);
|
||||||
}
|
}
|
||||||
@ -64,9 +77,9 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
public static string GetRobloxVersion(bool studio)
|
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))
|
if (!File.Exists(playerLocation))
|
||||||
return "";
|
return "";
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bloxstrap.Integrations;
|
using Bloxstrap.AppData;
|
||||||
|
using Bloxstrap.Integrations;
|
||||||
using Bloxstrap.Models;
|
using Bloxstrap.Models;
|
||||||
|
|
||||||
namespace Bloxstrap
|
namespace Bloxstrap
|
||||||
@ -30,7 +31,7 @@ namespace Bloxstrap
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (String.IsNullOrEmpty(watcherDataArg))
|
if (String.IsNullOrEmpty(watcherDataArg))
|
||||||
{
|
{
|
||||||
string path = Path.Combine(Paths.Roblox, "Player", "RobloxPlayerBeta.exe");
|
string path = new RobloxPlayerData().ExecutablePath;
|
||||||
using var gameClientProcess = Process.Start(path);
|
using var gameClientProcess = Process.Start(path);
|
||||||
|
|
||||||
_watcherData = new() { ProcessId = gameClientProcess.Id };
|
_watcherData = new() { ProcessId = gameClientProcess.Id };
|
||||||
|
28
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.
|
> 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.
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://github.com/pizzaboxer/bloxstrap/raw/main/Images/Bloxstrap-full-dark.png#gh-dark-mode-only" width="420">
|
<img src="https://github.com/bloxstraplabs/bloxstrap/raw/main/Images/Bloxstrap-full-dark.png#gh-dark-mode-only" width="420">
|
||||||
<img src="https://github.com/pizzaboxer/bloxstrap/raw/main/Images/Bloxstrap-full-light.png#gh-light-mode-only" width="420">
|
<img src="https://github.com/bloxstraplabs/bloxstrap/raw/main/Images/Bloxstrap-full-light.png#gh-light-mode-only" width="420">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div align="center">
|
<div align="center">
|
||||||
@ -22,7 +22,7 @@
|
|||||||
|
|
||||||
Bloxstrap is a third-party replacement for the standard Roblox bootstrapper, providing additional useful features and improvements.
|
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.
|
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?**
|
**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?**
|
**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
|
## Features
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ Bloxstrap is only supported for PCs running Windows.
|
|||||||
- Ability to configure graphics fidelity and UI experience
|
- Ability to configure graphics fidelity and UI experience
|
||||||
|
|
||||||
## Installing
|
## 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:
|
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).
|
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-license]: https://img.shields.io/github/license/bloxstraplabs/bloxstrap
|
||||||
[shield-repo-workflow]: https://img.shields.io/github/actions/workflow/status/pizzaboxer/bloxstrap/ci-release.yml?branch=main&label=builds
|
[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/pizzaboxer/bloxstrap/latest/total?color=981bfe
|
[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/pizzaboxer/bloxstrap?color=7a39fb
|
[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-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-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
|
[shield-tenor-meme]: https://img.shields.io/badge/mom_made-pizza_rolls-orange
|
||||||
|
|
||||||
[repo-license]: https://github.com/pizzaboxer/bloxstrap/blob/main/LICENSE
|
[repo-license]: https://github.com/bloxstraplabs/bloxstrap/blob/main/LICENSE
|
||||||
[repo-actions]: https://github.com/pizzaboxer/bloxstrap/actions
|
[repo-actions]: https://github.com/bloxstraplabs/bloxstrap/actions
|
||||||
[repo-releases]: https://github.com/pizzaboxer/bloxstrap/releases
|
[repo-releases]: https://github.com/bloxstraplabs/bloxstrap/releases
|
||||||
[repo-latest]: https://github.com/pizzaboxer/bloxstrap/releases/latest
|
[repo-latest]: https://github.com/bloxstraplabs/bloxstrap/releases/latest
|
||||||
|
|
||||||
[crowdin-project]: https://crowdin.com/project/bloxstrap
|
[crowdin-project]: https://crowdin.com/project/bloxstrap
|
||||||
[discord-invite]: https://discord.gg/nKjV3mGq6R
|
[discord-invite]: https://discord.gg/nKjV3mGq6R
|
||||||
|