mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
Abstract differences in handling player and studio
This commit is contained in:
parent
765cccf89e
commit
d15e910904
63
Bloxstrap/AppData/CommonAppData.cs
Normal file
63
Bloxstrap/AppData/CommonAppData.cs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bloxstrap.AppData
|
||||||
|
{
|
||||||
|
public abstract class CommonAppData
|
||||||
|
{
|
||||||
|
// in case a new package is added, you can find the corresponding directory
|
||||||
|
// by opening the stock bootstrapper in a hex editor
|
||||||
|
private IReadOnlyDictionary<string, string> _commonMap { get; } = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "Libraries.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\" },
|
||||||
|
};
|
||||||
|
|
||||||
|
public virtual IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; }
|
||||||
|
|
||||||
|
public CommonAppData()
|
||||||
|
{
|
||||||
|
if (PackageDirectoryMap is null)
|
||||||
|
{
|
||||||
|
PackageDirectoryMap = _commonMap;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var merged = new Dictionary<string, string>();
|
||||||
|
|
||||||
|
foreach (var entry in _commonMap)
|
||||||
|
merged[entry.Key] = entry.Value;
|
||||||
|
|
||||||
|
foreach (var entry in PackageDirectoryMap)
|
||||||
|
merged[entry.Key] = entry.Value;
|
||||||
|
|
||||||
|
PackageDirectoryMap = merged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
Bloxstrap/AppData/IAppData.cs
Normal file
23
Bloxstrap/AppData/IAppData.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bloxstrap.AppData
|
||||||
|
{
|
||||||
|
internal interface IAppData
|
||||||
|
{
|
||||||
|
string ProductName { get; }
|
||||||
|
|
||||||
|
string BinaryType { get; }
|
||||||
|
|
||||||
|
string RegistryName { get; }
|
||||||
|
|
||||||
|
string ExecutableName { get; }
|
||||||
|
|
||||||
|
string StartEvent { get; }
|
||||||
|
|
||||||
|
IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; }
|
||||||
|
}
|
||||||
|
}
|
26
Bloxstrap/AppData/RobloxPlayerData.cs
Normal file
26
Bloxstrap/AppData/RobloxPlayerData.cs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bloxstrap.AppData
|
||||||
|
{
|
||||||
|
public class RobloxPlayerData : CommonAppData, IAppData
|
||||||
|
{
|
||||||
|
public string ProductName { get; } = "Roblox";
|
||||||
|
|
||||||
|
public string BinaryType { get; } = "WindowsPlayer";
|
||||||
|
|
||||||
|
public string RegistryName { get; } = "RobloxPlayer";
|
||||||
|
|
||||||
|
public string ExecutableName { get; } = "RobloxPlayerBeta.exe";
|
||||||
|
|
||||||
|
public string StartEvent { get; } = "www.roblox.com/robloxStartedEvent";
|
||||||
|
|
||||||
|
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "RobloxApp.zip", @"" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
42
Bloxstrap/AppData/RobloxStudioData.cs
Normal file
42
Bloxstrap/AppData/RobloxStudioData.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Bloxstrap.AppData
|
||||||
|
{
|
||||||
|
public class RobloxStudioData : CommonAppData, IAppData
|
||||||
|
{
|
||||||
|
public string ProductName { get; } = "Roblox Studio";
|
||||||
|
|
||||||
|
public string BinaryType { get; } = "WindowsStudio64";
|
||||||
|
|
||||||
|
public string RegistryName { get; } = "RobloxStudio";
|
||||||
|
|
||||||
|
public string ExecutableName { get; } = "RobloxStudioBeta.exe";
|
||||||
|
|
||||||
|
public string StartEvent { get; } = "www.roblox.com/robloxStudioStartedEvent";
|
||||||
|
|
||||||
|
public override IReadOnlyDictionary<string, string> PackageDirectoryMap { get; set; } = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
{ "RobloxStudio.zip", @"" },
|
||||||
|
{ "redist.zip", @"" },
|
||||||
|
{ "LibrariesQt5.zip", @"" },
|
||||||
|
|
||||||
|
{ "content-studio_svg_textures.zip", @"content\studio_svg_textures\"},
|
||||||
|
{ "content-qt_translations.zip", @"content\qt_translations\" },
|
||||||
|
{ "content-api-docs.zip", @"content\api_docs\" },
|
||||||
|
|
||||||
|
{ "extracontent-scripts.zip", @"ExtraContent\scripts\" },
|
||||||
|
|
||||||
|
{ "BuiltInPlugins.zip", @"BuiltInPlugins\" },
|
||||||
|
{ "BuiltInStandalonePlugins.zip", @"BuiltInStandalonePlugins\" },
|
||||||
|
|
||||||
|
{ "ApplicationConfig.zip", @"ApplicationConfig\" },
|
||||||
|
{ "Plugins.zip", @"Plugins\" },
|
||||||
|
{ "Qml.zip", @"Qml\" },
|
||||||
|
{ "StudioFonts.zip", @"StudioFonts\" }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,7 @@ using Microsoft.Win32;
|
|||||||
|
|
||||||
using Bloxstrap.Integrations;
|
using Bloxstrap.Integrations;
|
||||||
using Bloxstrap.Resources;
|
using Bloxstrap.Resources;
|
||||||
|
using Bloxstrap.AppData;
|
||||||
|
|
||||||
namespace Bloxstrap
|
namespace Bloxstrap
|
||||||
{
|
{
|
||||||
@ -24,8 +25,9 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
private bool FreshInstall => String.IsNullOrEmpty(_versionGuid);
|
private bool FreshInstall => String.IsNullOrEmpty(_versionGuid);
|
||||||
|
|
||||||
private string _playerFileName => _launchMode == LaunchMode.Player ? "RobloxPlayerBeta.exe" : "RobloxStudioBeta.exe";
|
private IAppData AppData;
|
||||||
private string _playerLocation => Path.Combine(_versionFolder, _playerFileName);
|
|
||||||
|
private string _playerLocation => Path.Combine(_versionFolder, AppData.ExecutableName);
|
||||||
|
|
||||||
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
||||||
private LaunchMode _launchMode = App.LaunchSettings.RobloxLaunchMode;
|
private LaunchMode _launchMode = App.LaunchSettings.RobloxLaunchMode;
|
||||||
@ -73,8 +75,6 @@ namespace Bloxstrap
|
|||||||
private int _packagesExtracted = 0;
|
private int _packagesExtracted = 0;
|
||||||
private bool _cancelFired = false;
|
private bool _cancelFired = false;
|
||||||
|
|
||||||
private IReadOnlyDictionary<string, string> _packageDirectories;
|
|
||||||
|
|
||||||
public IBootstrapperDialog? Dialog = null;
|
public IBootstrapperDialog? Dialog = null;
|
||||||
|
|
||||||
public bool IsStudioLaunch => _launchMode != LaunchMode.Player;
|
public bool IsStudioLaunch => _launchMode != LaunchMode.Player;
|
||||||
@ -85,19 +85,17 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
_installWebView2 = installWebView2;
|
_installWebView2 = installWebView2;
|
||||||
|
|
||||||
_packageDirectories = _launchMode == LaunchMode.Player ? PackageMap.Player : PackageMap.Studio;
|
if (_launchMode == LaunchMode.Player)
|
||||||
|
AppData = new RobloxPlayerData();
|
||||||
|
else
|
||||||
|
AppData = new RobloxStudioData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetStatus(string message)
|
private void SetStatus(string message)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine("Bootstrapper::SetStatus", message);
|
App.Logger.WriteLine("Bootstrapper::SetStatus", message);
|
||||||
|
|
||||||
string productName = "Roblox";
|
message = message.Replace("{product}", AppData.ProductName);
|
||||||
|
|
||||||
if (_launchMode != LaunchMode.Player)
|
|
||||||
productName = "Roblox Studio";
|
|
||||||
|
|
||||||
message = message.Replace("{product}", productName);
|
|
||||||
|
|
||||||
if (Dialog is not null)
|
if (Dialog is not null)
|
||||||
Dialog.Message = message;
|
Dialog.Message = message;
|
||||||
@ -229,9 +227,7 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
string channel = "production";
|
string channel = "production";
|
||||||
|
|
||||||
string keyPath = _launchMode == LaunchMode.Player ? "RobloxPlayer" : "RobloxStudio";
|
using var key = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\ROBLOX Corporation\\Environments\\{AppData.RegistryName}\\Channel");
|
||||||
|
|
||||||
using var key = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\ROBLOX Corporation\\Environments\\{keyPath}\\Channel");
|
|
||||||
|
|
||||||
var match = Regex.Match(App.LaunchSettings.RobloxLaunchArgs, "channel:([a-zA-Z0-9-_]+)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
var match = Regex.Match(App.LaunchSettings.RobloxLaunchArgs, "channel:([a-zA-Z0-9-_]+)", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||||
|
|
||||||
@ -246,11 +242,9 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
ClientVersion clientVersion;
|
ClientVersion clientVersion;
|
||||||
|
|
||||||
string binaryType = _launchMode == LaunchMode.Player ? "WindowsPlayer" : "WindowsStudio64";
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
clientVersion = await RobloxDeployment.GetInfo(channel, binaryType);
|
clientVersion = await RobloxDeployment.GetInfo(channel, AppData.BinaryType);
|
||||||
}
|
}
|
||||||
catch (HttpResponseException ex)
|
catch (HttpResponseException ex)
|
||||||
{
|
{
|
||||||
@ -263,7 +257,7 @@ namespace Bloxstrap
|
|||||||
App.Logger.WriteLine(LOG_IDENT, $"Changing channel from {channel} to {RobloxDeployment.DefaultChannel} because HTTP {(int)ex.ResponseMessage.StatusCode}");
|
App.Logger.WriteLine(LOG_IDENT, $"Changing channel from {channel} to {RobloxDeployment.DefaultChannel} because HTTP {(int)ex.ResponseMessage.StatusCode}");
|
||||||
|
|
||||||
channel = RobloxDeployment.DefaultChannel;
|
channel = RobloxDeployment.DefaultChannel;
|
||||||
clientVersion = await RobloxDeployment.GetInfo(channel, binaryType);
|
clientVersion = await RobloxDeployment.GetInfo(channel, AppData.BinaryType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientVersion.IsBehindDefaultChannel)
|
if (clientVersion.IsBehindDefaultChannel)
|
||||||
@ -271,7 +265,7 @@ namespace Bloxstrap
|
|||||||
App.Logger.WriteLine(LOG_IDENT, $"Changing channel from {channel} to {RobloxDeployment.DefaultChannel} because channel is behind production");
|
App.Logger.WriteLine(LOG_IDENT, $"Changing channel from {channel} to {RobloxDeployment.DefaultChannel} because channel is behind production");
|
||||||
|
|
||||||
channel = RobloxDeployment.DefaultChannel;
|
channel = RobloxDeployment.DefaultChannel;
|
||||||
clientVersion = await RobloxDeployment.GetInfo(channel, binaryType);
|
clientVersion = await RobloxDeployment.GetInfo(channel, AppData.BinaryType);
|
||||||
}
|
}
|
||||||
|
|
||||||
key.SetValue("www.roblox.com", channel);
|
key.SetValue("www.roblox.com", channel);
|
||||||
@ -325,13 +319,13 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {gameClientPid})");
|
App.Logger.WriteLine(LOG_IDENT, $"Started Roblox (PID {gameClientPid})");
|
||||||
|
|
||||||
string eventName = _launchMode == LaunchMode.Player ? "www.roblox.com/robloxStartedEvent" : "www.roblox.com/robloxQTStudioStartedEvent";
|
using (var startEvent = new SystemEvent(AppData.StartEvent))
|
||||||
using (SystemEvent startEvent = new(eventName))
|
|
||||||
{
|
{
|
||||||
bool startEventFired = await startEvent.WaitForEvent();
|
bool startEventFired = await startEvent.WaitForEvent();
|
||||||
|
|
||||||
startEvent.Close();
|
startEvent.Close();
|
||||||
|
|
||||||
|
// TODO: this cannot silently exit like this
|
||||||
if (!startEventFired)
|
if (!startEventFired)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -695,7 +689,7 @@ namespace Bloxstrap
|
|||||||
// move old compatibility flags for the old location
|
// move old compatibility flags for the old location
|
||||||
using (RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"))
|
using (RegistryKey appFlagsKey = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Layers"))
|
||||||
{
|
{
|
||||||
string oldGameClientLocation = Path.Combine(oldVersionFolder, _playerFileName);
|
string oldGameClientLocation = Path.Combine(oldVersionFolder, AppData.ExecutableName);
|
||||||
string? appFlags = (string?)appFlagsKey.GetValue(oldGameClientLocation);
|
string? appFlags = (string?)appFlagsKey.GetValue(oldGameClientLocation);
|
||||||
|
|
||||||
if (appFlags is not null)
|
if (appFlags is not null)
|
||||||
@ -812,7 +806,7 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
const string LOG_IDENT = "Bootstrapper::ApplyModifications";
|
const string LOG_IDENT = "Bootstrapper::ApplyModifications";
|
||||||
|
|
||||||
if (Process.GetProcessesByName(_playerFileName[..^4]).Any())
|
if (Process.GetProcessesByName(AppData.ExecutableName[..^4]).Any())
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Roblox is running, aborting mod check");
|
App.Logger.WriteLine(LOG_IDENT, "Roblox is running, aborting mod check");
|
||||||
return;
|
return;
|
||||||
@ -958,7 +952,7 @@ namespace Bloxstrap
|
|||||||
if (modFolderFiles.Contains(fileLocation))
|
if (modFolderFiles.Contains(fileLocation))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var package = _packageDirectories.SingleOrDefault(x => x.Value != "" && fileLocation.StartsWith(x.Value));
|
var package = AppData.PackageDirectoryMap.SingleOrDefault(x => x.Value != "" && fileLocation.StartsWith(x.Value));
|
||||||
|
|
||||||
// package doesn't exist, likely mistakenly placed file
|
// package doesn't exist, likely mistakenly placed file
|
||||||
if (String.IsNullOrEmpty(package.Key))
|
if (String.IsNullOrEmpty(package.Key))
|
||||||
@ -1128,7 +1122,7 @@ namespace Bloxstrap
|
|||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
string packageLocation = Path.Combine(Paths.Downloads, package.Signature);
|
string packageLocation = Path.Combine(Paths.Downloads, package.Signature);
|
||||||
string packageFolder = Path.Combine(_versionFolder, _packageDirectories[package.Name]);
|
string packageFolder = Path.Combine(_versionFolder, AppData.PackageDirectoryMap[package.Name]);
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Extracting {package.Name}...");
|
App.Logger.WriteLine(LOG_IDENT, $"Extracting {package.Name}...");
|
||||||
|
|
||||||
@ -1158,7 +1152,7 @@ namespace Bloxstrap
|
|||||||
if (entry is null)
|
if (entry is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
string extractionPath = Path.Combine(_versionFolder, _packageDirectories[package.Name], entry.FullName);
|
string extractionPath = Path.Combine(_versionFolder, AppData.PackageDirectoryMap[package.Name], entry.FullName);
|
||||||
entry.ExtractToFile(extractionPath, true);
|
entry.ExtractToFile(extractionPath, true);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
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>()
|
|
||||||
{
|
|
||||||
{ "Libraries.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 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\" },
|
|
||||||
{ "extracontent-scripts.zip", @"ExtraContent\scripts\" },
|
|
||||||
{ "BuiltInPlugins.zip", @"BuiltInPlugins\" },
|
|
||||||
{ "BuiltInStandalonePlugins.zip", @"BuiltInStandalonePlugins\" },
|
|
||||||
{ "LibrariesQt5.zip", @"" },
|
|
||||||
{ "Plugins.zip", @"Plugins\" },
|
|
||||||
{ "Qml.zip", @"Qml\" },
|
|
||||||
{ "StudioFonts.zip", @"StudioFonts\" },
|
|
||||||
{ "redist.zip", @"" },
|
|
||||||
};
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user