mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
commit
9d6bf8c024
@ -248,7 +248,7 @@ namespace Bloxstrap
|
||||
if (!IsFirstRun)
|
||||
ShouldSaveConfigs = true;
|
||||
|
||||
DeployManager.SetChannel(Settings.Prop.Channel);
|
||||
DeployManager.Channel = Settings.Prop.Channel;
|
||||
|
||||
// start bootstrapper and show the bootstrapper modal if we're not running silently
|
||||
Logger.WriteLine($"[App::OnStartup] Initializing bootstrapper");
|
||||
|
@ -38,6 +38,10 @@ namespace Bloxstrap
|
||||
{ "shaders.zip", @"shaders\" },
|
||||
{ "ssl.zip", @"ssl\" },
|
||||
|
||||
// the runtime installer is only extracted if it needs installing
|
||||
{ "WebView2.zip", @"" },
|
||||
{ "WebView2RuntimeInstaller.zip", @"WebView2RuntimeInstaller\" },
|
||||
|
||||
{ "content-avatar.zip", @"content\avatar\" },
|
||||
{ "content-configs.zip", @"content\configs\" },
|
||||
{ "content-fonts.zip", @"content\fonts\" },
|
||||
@ -67,13 +71,15 @@ namespace Bloxstrap
|
||||
private readonly CancellationTokenSource _cancelTokenSource = new();
|
||||
|
||||
private static bool FreshInstall => String.IsNullOrEmpty(App.State.Prop.VersionGuid);
|
||||
private static bool ShouldInstallWebView2 = false;
|
||||
private static string DesktopShortcutLocation => Path.Combine(Directories.Desktop, "Play Roblox.lnk");
|
||||
|
||||
private string? _launchCommandLine;
|
||||
|
||||
private string _versionGuid = null!;
|
||||
private string _latestVersionGuid = null!;
|
||||
private PackageManifest _versionPackageManifest = null!;
|
||||
private string _versionFolder = null!;
|
||||
private string _playerLocation => Path.Combine(_versionFolder, "RobloxPlayerBeta.exe");
|
||||
|
||||
private bool _isInstalling = false;
|
||||
private double _progressIncrement;
|
||||
@ -88,6 +94,18 @@ namespace Bloxstrap
|
||||
public Bootstrapper(string? launchCommandLine = null)
|
||||
{
|
||||
_launchCommandLine = launchCommandLine;
|
||||
|
||||
// check if the webview2 runtime needs to be installed
|
||||
// webview2 can either be installed be per-user or globally, so we need to check in both hklm and hkcu
|
||||
// https://learn.microsoft.com/en-us/microsoft-edge/webview2/concepts/distribution#online-only-deployment
|
||||
|
||||
string hklmLocation = "SOFTWARE\\WOW6432Node\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}";
|
||||
string hkcuLocation = "Software\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}";
|
||||
|
||||
if (!Environment.Is64BitOperatingSystem)
|
||||
hklmLocation = "SOFTWARE\\Microsoft\\EdgeUpdate\\Clients\\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}";
|
||||
|
||||
ShouldInstallWebView2 = Registry.LocalMachine.OpenSubKey(hklmLocation) is null && Registry.CurrentUser.OpenSubKey(hkcuLocation) is null;
|
||||
}
|
||||
|
||||
private void SetStatus(string message)
|
||||
@ -144,8 +162,9 @@ namespace Bloxstrap
|
||||
|
||||
CheckInstallMigration();
|
||||
|
||||
// if roblox needs updating but is running and we have multiple instances open, ignore update for now
|
||||
if (App.IsFirstRun || _versionGuid != App.State.Prop.VersionGuid && !Utilities.CheckIfRobloxRunning())
|
||||
// only update roblox if we're running for the first time, or if
|
||||
// roblox isn't running and our version guid is out of date, or the player exe doesn't exist
|
||||
if (App.IsFirstRun || !Utilities.CheckIfRobloxRunning() && (_latestVersionGuid != App.State.Prop.VersionGuid || !File.Exists(_playerLocation)))
|
||||
await InstallLatestVersion();
|
||||
|
||||
// last time the version folder was set, it was set to the latest version guid
|
||||
@ -158,6 +177,9 @@ namespace Bloxstrap
|
||||
App.FastFlags.Save();
|
||||
}
|
||||
|
||||
if (ShouldInstallWebView2)
|
||||
await InstallWebView2();
|
||||
|
||||
if (App.Settings.Prop.UseReShade)
|
||||
SetStatus("Configuring/Downloading ReShade...");
|
||||
|
||||
@ -244,9 +266,9 @@ namespace Bloxstrap
|
||||
SetStatus("Connecting to Roblox...");
|
||||
|
||||
ClientVersion clientVersion = await App.DeployManager.GetLastDeploy();
|
||||
_versionGuid = clientVersion.VersionGuid;
|
||||
_versionFolder = Path.Combine(Directories.Versions, _versionGuid);
|
||||
_versionPackageManifest = await PackageManifest.Get(_versionGuid);
|
||||
_latestVersionGuid = clientVersion.VersionGuid;
|
||||
_versionFolder = Path.Combine(Directories.Versions, _latestVersionGuid);
|
||||
_versionPackageManifest = await PackageManifest.Get(_latestVersionGuid);
|
||||
}
|
||||
|
||||
private void CheckInstallMigration()
|
||||
@ -336,7 +358,7 @@ namespace Bloxstrap
|
||||
// whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes
|
||||
bool shouldWait = false;
|
||||
|
||||
Process gameClient = Process.Start(Path.Combine(_versionFolder, "RobloxPlayerBeta.exe"), _launchCommandLine);
|
||||
Process gameClient = Process.Start(_playerLocation, _launchCommandLine);
|
||||
List<Process> autocloseProcesses = new();
|
||||
GameActivityWatcher? activityWatcher = null;
|
||||
DiscordRichPresence? richPresence = null;
|
||||
@ -683,8 +705,13 @@ namespace Bloxstrap
|
||||
// download all the packages synchronously
|
||||
await DownloadPackage(package);
|
||||
|
||||
// we'll extract the runtime installer later if we need to
|
||||
if (package.Name == "WebView2RuntimeInstaller.zip")
|
||||
continue;
|
||||
|
||||
// extract the package immediately after download asynchronously
|
||||
ExtractPackage(package);
|
||||
// discard is just used to suppress the warning
|
||||
Task _ = ExtractPackage(package);
|
||||
}
|
||||
|
||||
if (_cancelFired)
|
||||
@ -699,8 +726,8 @@ namespace Bloxstrap
|
||||
SetStatus("Configuring Roblox...");
|
||||
}
|
||||
|
||||
// wait for all packages to finish extracting
|
||||
while (_packagesExtracted < _versionPackageManifest.Count)
|
||||
// wait for all packages to finish extracting, with an exception for the webview2 runtime installer
|
||||
while (_packagesExtracted < _versionPackageManifest.Where(x => x.Name != "WebView2RuntimeInstaller.zip").Count())
|
||||
{
|
||||
await Task.Delay(100);
|
||||
}
|
||||
@ -727,7 +754,7 @@ namespace Bloxstrap
|
||||
|
||||
string oldVersionFolder = Path.Combine(Directories.Versions, App.State.Prop.VersionGuid);
|
||||
|
||||
if (_versionGuid != App.State.Prop.VersionGuid && Directory.Exists(oldVersionFolder))
|
||||
if (_latestVersionGuid != App.State.Prop.VersionGuid && Directory.Exists(oldVersionFolder))
|
||||
{
|
||||
// and also to delete our old version folder
|
||||
Directory.Delete(oldVersionFolder, true);
|
||||
@ -737,13 +764,12 @@ namespace Bloxstrap
|
||||
using (RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"))
|
||||
{
|
||||
string oldGameClientLocation = Path.Combine(oldVersionFolder, "RobloxPlayerBeta.exe");
|
||||
string newGameClientLocation = Path.Combine(_versionFolder, "RobloxPlayerBeta.exe");
|
||||
string? appFlags = (string?)appFlagsKey.GetValue(oldGameClientLocation);
|
||||
|
||||
if (appFlags is not null)
|
||||
{
|
||||
App.Logger.WriteLine($"[Bootstrapper::InstallLatestVersion] Migrating app compatibility flags from {oldGameClientLocation} to {newGameClientLocation}...");
|
||||
appFlagsKey.SetValue(newGameClientLocation, appFlags);
|
||||
App.Logger.WriteLine($"[Bootstrapper::InstallLatestVersion] Migrating app compatibility flags from {oldGameClientLocation} to {_playerLocation}...");
|
||||
appFlagsKey.SetValue(_playerLocation, appFlags);
|
||||
appFlagsKey.DeleteValue(oldGameClientLocation);
|
||||
}
|
||||
}
|
||||
@ -752,11 +778,47 @@ namespace Bloxstrap
|
||||
if (Dialog is not null)
|
||||
Dialog.CancelEnabled = false;
|
||||
|
||||
App.State.Prop.VersionGuid = _versionGuid;
|
||||
App.State.Prop.VersionGuid = _latestVersionGuid;
|
||||
|
||||
_isInstalling = false;
|
||||
}
|
||||
|
||||
private async Task InstallWebView2()
|
||||
{
|
||||
if (!ShouldInstallWebView2)
|
||||
return;
|
||||
|
||||
App.Logger.WriteLine($"[Bootstrapper::InstallWebView2] Installing runtime...");
|
||||
|
||||
string baseDirectory = Path.Combine(_versionFolder, "WebView2RuntimeInstaller");
|
||||
|
||||
if (!Directory.Exists(baseDirectory))
|
||||
{
|
||||
Package? package = _versionPackageManifest.Find(x => x.Name == "WebView2RuntimeInstaller.zip");
|
||||
|
||||
if (package is null)
|
||||
{
|
||||
App.Logger.WriteLine($"[Bootstrapper::InstallWebView2] Aborted runtime install because package does not exist, has WebView2 been added in this Roblox version yet?");
|
||||
return;
|
||||
}
|
||||
|
||||
await ExtractPackage(package);
|
||||
}
|
||||
|
||||
SetStatus("Installing WebView2, please wait...");
|
||||
|
||||
ProcessStartInfo startInfo = new()
|
||||
{
|
||||
WorkingDirectory = baseDirectory,
|
||||
FileName = Path.Combine(baseDirectory, "MicrosoftEdgeWebview2Setup.exe"),
|
||||
Arguments = "/silent /install"
|
||||
};
|
||||
|
||||
await Process.Start(startInfo)!.WaitForExitAsync();
|
||||
|
||||
App.Logger.WriteLine($"[Bootstrapper::InstallWebView2] Finished installing runtime");
|
||||
}
|
||||
|
||||
private async Task ApplyModifications()
|
||||
{
|
||||
SetStatus("Applying Roblox modifications...");
|
||||
@ -766,23 +828,22 @@ namespace Bloxstrap
|
||||
using (RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"))
|
||||
{
|
||||
const string flag = " DISABLEDXMAXIMIZEDWINDOWEDMODE";
|
||||
string gameClientLocation = Path.Combine(_versionFolder, "RobloxPlayerBeta.exe");
|
||||
string? appFlags = (string?)appFlagsKey.GetValue(gameClientLocation);
|
||||
string? appFlags = (string?)appFlagsKey.GetValue(_playerLocation);
|
||||
|
||||
if (App.Settings.Prop.DisableFullscreenOptimizations)
|
||||
{
|
||||
if (appFlags is null)
|
||||
appFlagsKey.SetValue(gameClientLocation, $"~{flag}");
|
||||
appFlagsKey.SetValue(_playerLocation, $"~{flag}");
|
||||
else if (!appFlags.Contains(flag))
|
||||
appFlagsKey.SetValue(gameClientLocation, appFlags + flag);
|
||||
appFlagsKey.SetValue(_playerLocation, appFlags + flag);
|
||||
}
|
||||
else if (appFlags is not null && appFlags.Contains(flag))
|
||||
{
|
||||
// if there's more than one space, there's more flags set we need to preserve
|
||||
if (appFlags.Split(' ').Length > 2)
|
||||
appFlagsKey.SetValue(gameClientLocation, appFlags.Remove(appFlags.IndexOf(flag), flag.Length));
|
||||
appFlagsKey.SetValue(_playerLocation, appFlags.Remove(appFlags.IndexOf(flag), flag.Length));
|
||||
else
|
||||
appFlagsKey.DeleteValue(gameClientLocation);
|
||||
appFlagsKey.DeleteValue(_playerLocation);
|
||||
}
|
||||
}
|
||||
|
||||
@ -905,7 +966,7 @@ namespace Bloxstrap
|
||||
if (_cancelFired)
|
||||
return;
|
||||
|
||||
string packageUrl = $"{App.DeployManager.BaseUrl}/{_versionGuid}-{package.Name}";
|
||||
string packageUrl = $"{App.DeployManager.BaseUrl}/{_latestVersionGuid}-{package.Name}";
|
||||
string packageLocation = Path.Combine(Directories.Downloads, package.Signature);
|
||||
string robloxPackageLocation = Path.Combine(Directories.LocalAppData, "Roblox", "Downloads", package.Signature);
|
||||
|
||||
@ -975,7 +1036,7 @@ namespace Bloxstrap
|
||||
}
|
||||
}
|
||||
|
||||
private async void ExtractPackage(Package package)
|
||||
private async Task ExtractPackage(Package package)
|
||||
{
|
||||
if (_cancelFired)
|
||||
return;
|
||||
|
@ -13,11 +13,68 @@ namespace Bloxstrap.Helpers
|
||||
public class DeployManager
|
||||
{
|
||||
#region Properties
|
||||
public const string DefaultBaseUrl = "https://setup.rbxcdn.com";
|
||||
public const string DefaultChannel = "LIVE";
|
||||
|
||||
public string BaseUrl { get; private set; } = DefaultBaseUrl;
|
||||
public string Channel { get; private set; } = DefaultChannel;
|
||||
private string _channel = DefaultChannel;
|
||||
|
||||
public string Channel
|
||||
{
|
||||
get => _channel;
|
||||
set
|
||||
{
|
||||
if (_channel != value)
|
||||
App.Logger.WriteLine($"[DeployManager::SetChannel] Changed channel to {value}");
|
||||
|
||||
_channel = value;
|
||||
}
|
||||
}
|
||||
|
||||
// a list of roblox delpoyment locations that we check for, in case one of them don't work
|
||||
private List<string> BaseUrls = new()
|
||||
{
|
||||
"https://setup.rbxcdn.com",
|
||||
"https://setup-ak.rbxcdn.com",
|
||||
"https://s3.amazonaws.com/setup.roblox.com"
|
||||
};
|
||||
|
||||
private string? _baseUrl = null;
|
||||
|
||||
public string BaseUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
if (String.IsNullOrEmpty(_baseUrl))
|
||||
{
|
||||
// check for a working accessible deployment domain
|
||||
foreach (string attemptedUrl in BaseUrls)
|
||||
{
|
||||
App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] Testing connection to '{attemptedUrl}'...");
|
||||
|
||||
try
|
||||
{
|
||||
App.HttpClient.GetAsync($"{attemptedUrl}/version").Wait();
|
||||
App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] Connection successful!");
|
||||
_baseUrl = attemptedUrl;
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] Connection failed!");
|
||||
App.Logger.WriteLine($"[DeployManager::DefaultBaseUrl.Set] {ex}");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (String.IsNullOrEmpty(_baseUrl))
|
||||
throw new Exception("Unable to find an accessible Roblox deploy mirror!");
|
||||
}
|
||||
|
||||
if (Channel == DefaultChannel)
|
||||
return _baseUrl;
|
||||
else
|
||||
return $"{_baseUrl}/channel/{Channel.ToLower()}";
|
||||
}
|
||||
}
|
||||
|
||||
// basically any channel that has had a deploy within the past month with a windowsplayer build
|
||||
public static readonly List<string> ChannelsAbstracted = new()
|
||||
@ -51,17 +108,6 @@ namespace Bloxstrap.Helpers
|
||||
};
|
||||
#endregion
|
||||
|
||||
public void SetChannel(string channel)
|
||||
{
|
||||
if (Channel == channel)
|
||||
return;
|
||||
|
||||
App.Logger.WriteLine($"[DeployManager::SetChannel] Set channel to {Channel}");
|
||||
|
||||
Channel = channel;
|
||||
BaseUrl = channel == DefaultChannel ? DefaultBaseUrl : $"{DefaultBaseUrl}/channel/{channel.ToLower()}";
|
||||
}
|
||||
|
||||
public async Task<ClientVersion> GetLastDeploy(bool timestamp = false)
|
||||
{
|
||||
App.Logger.WriteLine($"[DeployManager::GetLastDeploy] Getting deploy info for channel {Channel} (timestamp={timestamp})");
|
||||
|
@ -39,7 +39,7 @@ namespace Bloxstrap.ViewModels
|
||||
ChannelDeployInfo = null;
|
||||
OnPropertyChanged(nameof(ChannelDeployInfo));
|
||||
|
||||
App.DeployManager.SetChannel(channel);
|
||||
App.DeployManager.Channel = channel;
|
||||
ClientVersion info = await App.DeployManager.GetLastDeploy(true);
|
||||
|
||||
ChannelDeployInfo = new DeployInfo
|
||||
|
Loading…
Reference in New Issue
Block a user