mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
add studio support
This commit is contained in:
parent
bb5b46adf5
commit
1fcd05096a
@ -30,7 +30,6 @@ namespace Bloxstrap
|
||||
public static bool IsNoLaunch { get; private set; } = false;
|
||||
public static bool IsUpgrade { get; private set; } = false;
|
||||
public static bool IsMenuLaunch { get; private set; } = false;
|
||||
public static bool IsStudioLaunch { get; private set; } = false;
|
||||
public static string[] LaunchArgs { get; private set; } = null!;
|
||||
|
||||
public static BuildMetadataAttribute BuildMetadata = Assembly.GetExecutingAssembly().GetCustomAttribute<BuildMetadataAttribute>()!;
|
||||
@ -155,12 +154,6 @@ namespace Bloxstrap
|
||||
Logger.WriteLine(LOG_IDENT, "Bloxstrap started with IsUpgrade flag");
|
||||
IsUpgrade = true;
|
||||
}
|
||||
|
||||
if (Array.IndexOf(LaunchArgs, "-studio") != -1)
|
||||
{
|
||||
Logger.WriteLine(LOG_IDENT, "Bloxstrap started with IsStudioLaunch flag");
|
||||
IsStudioLaunch = true;
|
||||
}
|
||||
}
|
||||
|
||||
using (var checker = new InstallChecker())
|
||||
@ -196,6 +189,7 @@ namespace Bloxstrap
|
||||
#endif
|
||||
|
||||
string commandLine = "";
|
||||
bool isStudioLaunch = false;
|
||||
|
||||
if (IsMenuLaunch)
|
||||
{
|
||||
@ -234,6 +228,10 @@ namespace Bloxstrap
|
||||
|
||||
commandLine = $"--app --deeplink {LaunchArgs[0]}";
|
||||
}
|
||||
else if (LaunchArgs[0].StartsWith("roblox-studio:") || LaunchArgs[0].StartsWith("roblox-studio-auth:"))
|
||||
{
|
||||
commandLine = LaunchArgs[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
commandLine = "--app";
|
||||
@ -251,7 +249,7 @@ namespace Bloxstrap
|
||||
|
||||
// start bootstrapper and show the bootstrapper modal if we're not running silently
|
||||
Logger.WriteLine(LOG_IDENT, "Initializing bootstrapper");
|
||||
Bootstrapper bootstrapper = new(commandLine);
|
||||
Bootstrapper bootstrapper = new(commandLine, isStudioLaunch);
|
||||
IBootstrapperDialog? dialog = null;
|
||||
|
||||
if (!IsQuiet)
|
||||
|
@ -10,38 +10,6 @@ namespace Bloxstrap
|
||||
public class Bootstrapper
|
||||
{
|
||||
#region Properties
|
||||
// in case a new package is added, you can find the corresponding directory
|
||||
// by opening the stock bootstrapper in a hex editor
|
||||
// TODO - there ideally should be a less static way to do this that's not hardcoded?
|
||||
private static readonly IReadOnlyDictionary<string, string> PackageDirectories = new Dictionary<string, string>()
|
||||
{
|
||||
{ "RobloxApp.zip", @"" },
|
||||
{ "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\" },
|
||||
{ "content-sky.zip", @"content\sky\" },
|
||||
{ "content-sounds.zip", @"content\sounds\" },
|
||||
{ "content-textures2.zip", @"content\textures\" },
|
||||
{ "content-models.zip", @"content\models\" },
|
||||
|
||||
{ "content-textures3.zip", @"PlatformContent\pc\textures\" },
|
||||
{ "content-terrain.zip", @"PlatformContent\pc\terrain\" },
|
||||
{ "content-platform-fonts.zip", @"PlatformContent\pc\fonts\" },
|
||||
|
||||
{ "extracontent-luapackages.zip", @"ExtraContent\LuaPackages\" },
|
||||
{ "extracontent-translations.zip", @"ExtraContent\translations\" },
|
||||
{ "extracontent-models.zip", @"ExtraContent\models\" },
|
||||
{ "extracontent-textures.zip", @"ExtraContent\textures\" },
|
||||
{ "extracontent-places.zip", @"ExtraContent\places\" },
|
||||
};
|
||||
|
||||
private const string AppSettings =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" +
|
||||
"<Settings>\r\n" +
|
||||
@ -51,11 +19,30 @@ namespace Bloxstrap
|
||||
|
||||
private readonly CancellationTokenSource _cancelTokenSource = new();
|
||||
|
||||
private static bool FreshInstall => String.IsNullOrEmpty(App.State.Prop.PlayerVersionGuid);
|
||||
private bool FreshInstall => String.IsNullOrEmpty(_versionGuid);
|
||||
|
||||
private string _playerLocation => Path.Combine(_versionFolder, "RobloxPlayerBeta.exe");
|
||||
private string _playerFileName => _studioLaunch ? "RobloxStudioBeta.exe" : "RobloxPlayerBeta.exe";
|
||||
// TODO: change name
|
||||
private string _playerLocation => Path.Combine(_versionFolder, _playerFileName);
|
||||
|
||||
private string _launchCommandLine;
|
||||
private bool _studioLaunch;
|
||||
|
||||
private string _versionGuid
|
||||
{
|
||||
get
|
||||
{
|
||||
return _studioLaunch ? App.State.Prop.StudioVersionGuid : App.State.Prop.PlayerVersionGuid;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (_studioLaunch)
|
||||
App.State.Prop.StudioVersionGuid = value;
|
||||
else
|
||||
App.State.Prop.PlayerVersionGuid = value;
|
||||
}
|
||||
}
|
||||
|
||||
private string _latestVersionGuid = null!;
|
||||
private PackageManifest _versionPackageManifest = null!;
|
||||
@ -68,13 +55,16 @@ namespace Bloxstrap
|
||||
private int _packagesExtracted = 0;
|
||||
private bool _cancelFired = false;
|
||||
|
||||
private IReadOnlyDictionary<string, string> _packageDirectories => _studioLaunch ? PackageMap.Studio : PackageMap.Player;
|
||||
|
||||
public IBootstrapperDialog? Dialog = null;
|
||||
#endregion
|
||||
|
||||
#region Core
|
||||
public Bootstrapper(string launchCommandLine)
|
||||
public Bootstrapper(string launchCommandLine, bool studioLaunch)
|
||||
{
|
||||
_launchCommandLine = launchCommandLine;
|
||||
_studioLaunch = studioLaunch;
|
||||
}
|
||||
|
||||
private void SetStatus(string message)
|
||||
@ -183,7 +173,7 @@ namespace Bloxstrap
|
||||
await CheckLatestVersion();
|
||||
|
||||
// install/update roblox if we're running for the first time, needs updating, or the player location doesn't exist
|
||||
if (App.IsFirstRun || _latestVersionGuid != App.State.Prop.PlayerVersionGuid || !File.Exists(_playerLocation))
|
||||
if (App.IsFirstRun || _latestVersionGuid != _versionGuid || !File.Exists(_playerLocation))
|
||||
await InstallLatestVersion();
|
||||
|
||||
if (App.IsFirstRun)
|
||||
@ -199,7 +189,7 @@ namespace Bloxstrap
|
||||
if (App.IsFirstRun || FreshInstall)
|
||||
{
|
||||
Register();
|
||||
RegisterProgramSize();
|
||||
RegisterProgramSize(); // STUDIO TODO
|
||||
}
|
||||
|
||||
CheckInstall();
|
||||
@ -223,18 +213,20 @@ namespace Bloxstrap
|
||||
|
||||
ClientVersion clientVersion;
|
||||
|
||||
string binaryType = _studioLaunch ? "WindowsStudio64" : "WindowsPlayer";
|
||||
|
||||
try
|
||||
{
|
||||
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel);
|
||||
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel, binaryType: binaryType);
|
||||
}
|
||||
catch (HttpResponseException ex)
|
||||
{
|
||||
if (ex.ResponseMessage.StatusCode != HttpStatusCode.NotFound)
|
||||
throw;
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Reverting enrolled channel to {RobloxDeployment.DefaultChannel} because a WindowsPlayer build does not exist for {App.Settings.Prop.Channel}");
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Reverting enrolled channel to {RobloxDeployment.DefaultChannel} because a {binaryType} build does not exist for {App.Settings.Prop.Channel}");
|
||||
App.Settings.Prop.Channel = RobloxDeployment.DefaultChannel;
|
||||
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel);
|
||||
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel, binaryType: binaryType);
|
||||
}
|
||||
|
||||
if (clientVersion.IsBehindDefaultChannel)
|
||||
@ -257,7 +249,7 @@ namespace Bloxstrap
|
||||
App.Logger.WriteLine("Bootstrapper::CheckLatestVersion", $"Changed Roblox channel from {App.Settings.Prop.Channel} to {RobloxDeployment.DefaultChannel}");
|
||||
|
||||
App.Settings.Prop.Channel = RobloxDeployment.DefaultChannel;
|
||||
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel);
|
||||
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel, binaryType: binaryType);
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,8 +494,8 @@ namespace Bloxstrap
|
||||
|
||||
ProtocolHandler.Register("roblox", "Roblox", Paths.Application);
|
||||
ProtocolHandler.Register("roblox-player", "Roblox", Paths.Application);
|
||||
ProtocolHandler.Register("roblox-studio", "Roblox", Paths.Application, "-studio");
|
||||
ProtocolHandler.Register("roblox-studio-auth", "Roblox", Paths.Application, "-studio");
|
||||
ProtocolHandler.Register("roblox-studio", "Roblox", Paths.Application);
|
||||
ProtocolHandler.Register("roblox-studio-auth", "Roblox", Paths.Application);
|
||||
|
||||
if (Environment.ProcessPath is not null && Environment.ProcessPath != Paths.Application)
|
||||
{
|
||||
@ -798,7 +790,8 @@ namespace Bloxstrap
|
||||
|
||||
_isInstalling = true;
|
||||
|
||||
SetStatus(FreshInstall ? "Installing Roblox..." : "Upgrading Roblox...");
|
||||
string extra = _studioLaunch ? " Studio" : "";
|
||||
SetStatus(FreshInstall ? $"Installing Roblox{extra}..." : $"Upgrading Roblox{extra}...");
|
||||
|
||||
Directory.CreateDirectory(Paths.Base);
|
||||
Directory.CreateDirectory(Paths.Downloads);
|
||||
@ -892,12 +885,12 @@ namespace Bloxstrap
|
||||
}
|
||||
}
|
||||
|
||||
string oldVersionFolder = Path.Combine(Paths.Versions, App.State.Prop.PlayerVersionGuid);
|
||||
string oldVersionFolder = Path.Combine(Paths.Versions, _versionGuid);
|
||||
|
||||
// move old compatibility flags for the old location
|
||||
using (RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"))
|
||||
{
|
||||
string oldGameClientLocation = Path.Combine(oldVersionFolder, "RobloxPlayerBeta.exe");
|
||||
string oldGameClientLocation = Path.Combine(oldVersionFolder, _playerFileName);
|
||||
string? appFlags = (string?)appFlagsKey.GetValue(oldGameClientLocation);
|
||||
|
||||
if (appFlags is not null)
|
||||
@ -915,7 +908,7 @@ namespace Bloxstrap
|
||||
{
|
||||
foreach (DirectoryInfo dir in new DirectoryInfo(Paths.Versions).GetDirectories())
|
||||
{
|
||||
if (dir.Name == _latestVersionGuid || !dir.Name.StartsWith("version-"))
|
||||
if (dir.Name == App.State.Prop.PlayerVersionGuid || dir.Name == App.State.Prop.StudioVersionGuid || !dir.Name.StartsWith("version-"))
|
||||
continue;
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Removing old version folder for {dir.Name}");
|
||||
@ -933,7 +926,7 @@ namespace Bloxstrap
|
||||
}
|
||||
}
|
||||
|
||||
App.State.Prop.PlayerVersionGuid = _latestVersionGuid;
|
||||
_versionGuid = _latestVersionGuid;
|
||||
|
||||
// don't register program size until the program is registered, which will be done after this
|
||||
if (!App.IsFirstRun && !FreshInstall)
|
||||
@ -1228,7 +1221,7 @@ namespace Bloxstrap
|
||||
if (modFolderFiles.Contains(fileLocation))
|
||||
continue;
|
||||
|
||||
var package = PackageDirectories.SingleOrDefault(x => x.Value != "" && fileLocation.StartsWith(x.Value));
|
||||
var package = _packageDirectories.SingleOrDefault(x => x.Value != "" && fileLocation.StartsWith(x.Value));
|
||||
|
||||
// package doesn't exist, likely mistakenly placed file
|
||||
if (String.IsNullOrEmpty(package.Key))
|
||||
@ -1436,7 +1429,7 @@ namespace Bloxstrap
|
||||
return;
|
||||
|
||||
string packageLocation = Path.Combine(Paths.Downloads, package.Signature);
|
||||
string packageFolder = Path.Combine(_versionFolder, PackageDirectories[package.Name]);
|
||||
string packageFolder = Path.Combine(_versionFolder, _packageDirectories[package.Name]);
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Reading {package.Name}...");
|
||||
|
||||
@ -1462,7 +1455,7 @@ namespace Bloxstrap
|
||||
if (directory is not null)
|
||||
Directory.CreateDirectory(directory);
|
||||
|
||||
var fileManifest = _versionFileManifest.FirstOrDefault(x => x.Name == Path.Combine(PackageDirectories[package.Name], entry.FullName));
|
||||
var fileManifest = _versionFileManifest.FirstOrDefault(x => x.Name == Path.Combine(_packageDirectories[package.Name], entry.FullName));
|
||||
string? signature = fileManifest?.Signature;
|
||||
|
||||
if (File.Exists(extractPath))
|
||||
@ -1515,7 +1508,7 @@ namespace Bloxstrap
|
||||
if (entry is null)
|
||||
return;
|
||||
|
||||
string extractionPath = Path.Combine(_versionFolder, PackageDirectories[package.Name], entry.FullName);
|
||||
string extractionPath = Path.Combine(_versionFolder, _packageDirectories[package.Name], entry.FullName);
|
||||
entry.ExtractToFile(extractionPath, true);
|
||||
}
|
||||
#endregion
|
||||
|
85
Bloxstrap/PackageMap.cs
Normal file
85
Bloxstrap/PackageMap.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Bloxstrap
|
||||
{
|
||||
internal class PackageMap
|
||||
{
|
||||
public static IReadOnlyDictionary<string, string> Player
|
||||
{
|
||||
get { return CombineDictionaries(_common, _playerOnly); }
|
||||
}
|
||||
|
||||
public static IReadOnlyDictionary<string, string> Studio
|
||||
{
|
||||
get { return CombineDictionaries(_common, _studioOnly); }
|
||||
}
|
||||
|
||||
// in case a new package is added, you can find the corresponding directory
|
||||
// by opening the stock bootstrapper in a hex editor
|
||||
// TODO - there ideally should be a less static way to do this that's not hardcoded?
|
||||
private static IReadOnlyDictionary<string, string> _common = new Dictionary<string, string>()
|
||||
{
|
||||
{ "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\" },
|
||||
{ "content-sky.zip", @"content\sky\" },
|
||||
{ "content-sounds.zip", @"content\sounds\" },
|
||||
{ "content-textures2.zip", @"content\textures\" },
|
||||
{ "content-models.zip", @"content\models\" },
|
||||
|
||||
{ "content-textures3.zip", @"PlatformContent\pc\textures\" },
|
||||
{ "content-terrain.zip", @"PlatformContent\pc\terrain\" },
|
||||
{ "content-platform-fonts.zip", @"PlatformContent\pc\fonts\" },
|
||||
|
||||
{ "extracontent-luapackages.zip", @"ExtraContent\LuaPackages\" },
|
||||
{ "extracontent-translations.zip", @"ExtraContent\translations\" },
|
||||
{ "extracontent-models.zip", @"ExtraContent\models\" },
|
||||
{ "extracontent-textures.zip", @"ExtraContent\textures\" },
|
||||
{ "extracontent-places.zip", @"ExtraContent\places\" },
|
||||
};
|
||||
|
||||
private static IReadOnlyDictionary<string, string> _playerOnly = new Dictionary<string, string>()
|
||||
{
|
||||
{ "RobloxApp.zip", @"" }
|
||||
};
|
||||
|
||||
private static IReadOnlyDictionary<string, string> _studioOnly = new Dictionary<string, string>()
|
||||
{
|
||||
{ "RobloxStudio.zip", @"" },
|
||||
{ "ApplicationConfig.zip", @"ApplicationConfig\" },
|
||||
{ "content-studio_svg_textures.zip", @"content\studio_svg_textures\"},
|
||||
{ "content-qt_translations.zip", @"content\qt_translations\" },
|
||||
{ "content-api-docs.zip", @"content\api_docs\" },
|
||||
{ "BuiltInPlugins.zip", @"BuiltInPlugins\" },
|
||||
{ "BuiltInStandalonePlugins.zip", @"BuiltInStandalonePlugins\" },
|
||||
{ "LibrariesQt5.zip", @"" },
|
||||
{ "Plugins.zip", @"Plugins\" },
|
||||
{ "Qml.zip", @"Qml\" },
|
||||
{ "StudioFonts.zip", @"StudioFonts\" },
|
||||
};
|
||||
|
||||
private static Dictionary<string, string> CombineDictionaries(IReadOnlyDictionary<string, string> d1, IReadOnlyDictionary<string, string> d2)
|
||||
{
|
||||
Dictionary<string, string> newD = new Dictionary<string, string>();
|
||||
|
||||
foreach (var d in d1)
|
||||
newD[d.Key] = d.Value;
|
||||
|
||||
foreach (var d in d2)
|
||||
newD[d.Key] = d.Value;
|
||||
|
||||
return newD;
|
||||
}
|
||||
}
|
||||
}
|
@ -105,18 +105,9 @@ namespace Bloxstrap
|
||||
App.State.Save();
|
||||
}
|
||||
|
||||
private static string ConstructHandlerArgs(string handler, string? extraArgs = null)
|
||||
public static void Register(string key, string name, string handler)
|
||||
{
|
||||
string handlerArgs = $"\"{handler}\"";
|
||||
if (!string.IsNullOrEmpty(extraArgs))
|
||||
handlerArgs += $" {extraArgs}";
|
||||
handlerArgs += " %1";
|
||||
return handlerArgs;
|
||||
}
|
||||
|
||||
public static void Register(string key, string name, string handler, string? extraArgs = null)
|
||||
{
|
||||
string handlerArgs = ConstructHandlerArgs(handler, extraArgs);
|
||||
string handlerArgs = $"\"{handler}\" %1";
|
||||
RegistryKey uriKey = Registry.CurrentUser.CreateSubKey($@"Software\Classes\{key}");
|
||||
RegistryKey uriIconKey = uriKey.CreateSubKey("DefaultIcon");
|
||||
RegistryKey uriCommandKey = uriKey.CreateSubKey(@"shell\open\command");
|
||||
|
@ -69,7 +69,7 @@
|
||||
return location;
|
||||
}
|
||||
|
||||
public static async Task<ClientVersion> GetInfo(string channel, bool extraInformation = false)
|
||||
public static async Task<ClientVersion> GetInfo(string channel, bool extraInformation = false, string binaryType = "WindowsPlayer")
|
||||
{
|
||||
const string LOG_IDENT = "RobloxDeployment::GetInfo";
|
||||
|
||||
@ -84,7 +84,7 @@
|
||||
}
|
||||
else
|
||||
{
|
||||
string path = $"/v2/client-version/WindowsPlayer/channel/{channel}";
|
||||
string path = $"/v2/client-version/{binaryType}/channel/{channel}";
|
||||
HttpResponseMessage deployInfoResponse;
|
||||
|
||||
try
|
||||
|
Loading…
Reference in New Issue
Block a user