mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
commit
8f084958e2
@ -49,6 +49,8 @@ namespace Bloxstrap
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private static bool _showingExceptionDialog = false;
|
||||||
|
|
||||||
public static void Terminate(ErrorCode exitCode = ErrorCode.ERROR_SUCCESS)
|
public static void Terminate(ErrorCode exitCode = ErrorCode.ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
if (IsFirstRun)
|
if (IsFirstRun)
|
||||||
@ -85,6 +87,11 @@ namespace Bloxstrap
|
|||||||
#if DEBUG
|
#if DEBUG
|
||||||
throw exception;
|
throw exception;
|
||||||
#else
|
#else
|
||||||
|
if (_showingExceptionDialog)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_showingExceptionDialog = true;
|
||||||
|
|
||||||
if (!IsQuiet)
|
if (!IsQuiet)
|
||||||
Controls.ShowExceptionDialog(exception);
|
Controls.ShowExceptionDialog(exception);
|
||||||
|
|
||||||
@ -149,33 +156,6 @@ namespace Bloxstrap
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!IsMenuLaunch)
|
|
||||||
{
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Performing connectivity check...");
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
HttpClient.GetAsync("https://detectportal.firefox.com").Wait();
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Connectivity check finished");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.WriteLine(LOG_IDENT, "Connectivity check failed!");
|
|
||||||
Logger.WriteException(LOG_IDENT, ex);
|
|
||||||
|
|
||||||
if (ex.GetType() == typeof(AggregateException))
|
|
||||||
ex = ex.InnerException!;
|
|
||||||
|
|
||||||
Controls.ShowConnectivityDialog(
|
|
||||||
"the internet",
|
|
||||||
$"Something may be preventing {ProjectName} from connecting to the internet, or you are currently offline. Please check and try again.",
|
|
||||||
ex
|
|
||||||
);
|
|
||||||
|
|
||||||
Terminate(ErrorCode.ERROR_CANCELLED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var checker = new InstallChecker())
|
using (var checker = new InstallChecker())
|
||||||
{
|
{
|
||||||
checker.Check();
|
checker.Check();
|
||||||
|
@ -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.5.0</Version>
|
<Version>2.5.1</Version>
|
||||||
<FileVersion>2.5.0.0</FileVersion>
|
<FileVersion>2.5.1.0</FileVersion>
|
||||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
@ -60,6 +60,7 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
private string _latestVersionGuid = null!;
|
private string _latestVersionGuid = null!;
|
||||||
private PackageManifest _versionPackageManifest = null!;
|
private PackageManifest _versionPackageManifest = null!;
|
||||||
|
private FileManifest _versionFileManifest = null!;
|
||||||
private string _versionFolder = null!;
|
private string _versionFolder = null!;
|
||||||
|
|
||||||
private bool _isInstalling = false;
|
private bool _isInstalling = false;
|
||||||
@ -114,6 +115,39 @@ namespace Bloxstrap
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// connectivity check
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Performing connectivity check...");
|
||||||
|
|
||||||
|
SetStatus("Connecting to Roblox...");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
await RobloxDeployment.GetInfo(RobloxDeployment.DefaultChannel);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Connectivity check failed!");
|
||||||
|
App.Logger.WriteException(LOG_IDENT, ex);
|
||||||
|
|
||||||
|
string message = $"It's possible that something is preventing {App.ProjectName} from connecting to the internet. Please check and try again.";
|
||||||
|
|
||||||
|
if (ex.GetType() == typeof(HttpResponseException))
|
||||||
|
message = "Roblox may be down right now. See status.roblox.com for more information. Please try again later.";
|
||||||
|
else if (ex.GetType() == typeof(TaskCanceledException))
|
||||||
|
message = "Bloxstrap timed out when trying to connect to three different Roblox deployment mirrors, indicating a poor internet connection. Please try again later.";
|
||||||
|
else if (ex.GetType() == typeof(AggregateException))
|
||||||
|
ex = ex.InnerException!;
|
||||||
|
|
||||||
|
Controls.ShowConnectivityDialog("Roblox", message, ex);
|
||||||
|
|
||||||
|
App.Terminate(ErrorCode.ERROR_CANCELLED);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Connectivity check finished");
|
||||||
|
}
|
||||||
|
|
||||||
#if !DEBUG
|
#if !DEBUG
|
||||||
if (!App.IsFirstRun && App.Settings.Prop.CheckForUpdates)
|
if (!App.IsFirstRun && App.Settings.Prop.CheckForUpdates)
|
||||||
await CheckForUpdates();
|
await CheckForUpdates();
|
||||||
@ -126,8 +160,9 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Mutex.OpenExisting("Bloxstrap_BootstrapperMutex").Close();
|
Mutex.OpenExisting("Bloxstrap_SingletonMutex").Close();
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Bloxstrap_BootstrapperMutex mutex exists, waiting...");
|
App.Logger.WriteLine(LOG_IDENT, "Bloxstrap_SingletonMutex mutex exists, waiting...");
|
||||||
|
SetStatus("Waiting for other instances...");
|
||||||
mutexExists = true;
|
mutexExists = true;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
@ -136,7 +171,7 @@ namespace Bloxstrap
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait for mutex to be released if it's not yet
|
// wait for mutex to be released if it's not yet
|
||||||
await using AsyncMutex mutex = new("Bloxstrap_BootstrapperMutex");
|
await using var mutex = new AsyncMutex(true, "Bloxstrap_SingletonMutex");
|
||||||
await mutex.AcquireAsync(_cancelTokenSource.Token);
|
await mutex.AcquireAsync(_cancelTokenSource.Token);
|
||||||
|
|
||||||
// reload our configs since they've likely changed by now
|
// reload our configs since they've likely changed by now
|
||||||
@ -148,8 +183,6 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
await CheckLatestVersion();
|
await CheckLatestVersion();
|
||||||
|
|
||||||
CheckInstallMigration();
|
|
||||||
|
|
||||||
// install/update roblox if we're running for the first time, needs updating, or the player location doesn't exist
|
// 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.VersionGuid || !File.Exists(_playerLocation))
|
if (App.IsFirstRun || _latestVersionGuid != App.State.Prop.VersionGuid || !File.Exists(_playerLocation))
|
||||||
await InstallLatestVersion();
|
await InstallLatestVersion();
|
||||||
@ -187,7 +220,7 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
private async Task CheckLatestVersion()
|
private async Task CheckLatestVersion()
|
||||||
{
|
{
|
||||||
SetStatus("Connecting to Roblox...");
|
const string LOG_IDENT = "Bootstrapper::CheckLatestVersion";
|
||||||
|
|
||||||
ClientVersion clientVersion;
|
ClientVersion clientVersion;
|
||||||
|
|
||||||
@ -195,17 +228,14 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel);
|
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (HttpResponseException ex)
|
||||||
{
|
{
|
||||||
string message = "It's possible that Roblox is being blocked by a firewall. Please check and try again.";
|
if (ex.ResponseMessage.StatusCode != HttpStatusCode.NotFound)
|
||||||
|
throw;
|
||||||
|
|
||||||
if (ex.GetType() == typeof(HttpResponseException))
|
App.Logger.WriteLine(LOG_IDENT, $"Reverting enrolled channel to {RobloxDeployment.DefaultChannel} because a WindowsPlayer build does not exist for {App.Settings.Prop.Channel}");
|
||||||
message = "Roblox may be down right now. See status.roblox.com for more information. Please try again later.";
|
App.Settings.Prop.Channel = RobloxDeployment.DefaultChannel;
|
||||||
|
clientVersion = await RobloxDeployment.GetInfo(App.Settings.Prop.Channel);
|
||||||
Controls.ShowConnectivityDialog("Roblox", message, ex);
|
|
||||||
|
|
||||||
App.Terminate(ErrorCode.ERROR_CANCELLED);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clientVersion.IsBehindDefaultChannel)
|
if (clientVersion.IsBehindDefaultChannel)
|
||||||
@ -235,6 +265,7 @@ namespace Bloxstrap
|
|||||||
_latestVersionGuid = clientVersion.VersionGuid;
|
_latestVersionGuid = clientVersion.VersionGuid;
|
||||||
_versionFolder = Path.Combine(Paths.Versions, _latestVersionGuid);
|
_versionFolder = Path.Combine(Paths.Versions, _latestVersionGuid);
|
||||||
_versionPackageManifest = await PackageManifest.Get(_latestVersionGuid);
|
_versionPackageManifest = await PackageManifest.Get(_latestVersionGuid);
|
||||||
|
_versionFileManifest = await FileManifest.Get(_latestVersionGuid);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task StartRoblox()
|
private async Task StartRoblox()
|
||||||
@ -266,8 +297,12 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
_launchCommandLine = _launchCommandLine.Replace("LAUNCHTIMEPLACEHOLDER", DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString());
|
_launchCommandLine = _launchCommandLine.Replace("LAUNCHTIMEPLACEHOLDER", DateTimeOffset.Now.ToUnixTimeMilliseconds().ToString());
|
||||||
|
|
||||||
if (App.Settings.Prop.Channel.ToLowerInvariant() != RobloxDeployment.DefaultChannel.ToLowerInvariant())
|
_launchCommandLine += " -channel ";
|
||||||
_launchCommandLine += " -channel " + App.Settings.Prop.Channel.ToLowerInvariant();
|
|
||||||
|
if (App.Settings.Prop.Channel.ToLowerInvariant() == RobloxDeployment.DefaultChannel.ToLowerInvariant())
|
||||||
|
_launchCommandLine += "production";
|
||||||
|
else
|
||||||
|
_launchCommandLine += App.Settings.Prop.Channel.ToLowerInvariant();
|
||||||
|
|
||||||
// whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes
|
// whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes
|
||||||
bool shouldWait = false;
|
bool shouldWait = false;
|
||||||
@ -391,6 +426,8 @@ namespace Bloxstrap
|
|||||||
App.Logger.WriteException(LOG_IDENT, ex);
|
App.Logger.WriteException(LOG_IDENT, ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dialog?.CloseBootstrapper();
|
||||||
|
|
||||||
App.Terminate(ErrorCode.ERROR_CANCELLED);
|
App.Terminate(ErrorCode.ERROR_CANCELLED);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
@ -444,71 +481,6 @@ namespace Bloxstrap
|
|||||||
App.Logger.WriteLine(LOG_IDENT, $"Registered as {totalSize} KB");
|
App.Logger.WriteLine(LOG_IDENT, $"Registered as {totalSize} KB");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckInstallMigration()
|
|
||||||
{
|
|
||||||
const string LOG_IDENT = "Bootstrapper::CheckInstallMigration";
|
|
||||||
|
|
||||||
// check if we've changed our install location since the last time we started
|
|
||||||
// in which case, we'll have to copy over all our folders so we don't lose any mods and stuff
|
|
||||||
|
|
||||||
using RegistryKey? applicationKey = Registry.CurrentUser.OpenSubKey($@"Software\{App.ProjectName}", true);
|
|
||||||
|
|
||||||
string? oldInstallLocation = (string?)applicationKey?.GetValue("OldInstallLocation");
|
|
||||||
|
|
||||||
if (applicationKey is null || oldInstallLocation is null || oldInstallLocation == Paths.Base)
|
|
||||||
return;
|
|
||||||
|
|
||||||
SetStatus("Migrating install location...");
|
|
||||||
|
|
||||||
if (Directory.Exists(oldInstallLocation))
|
|
||||||
{
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Moving all files in {oldInstallLocation} to {Paths.Base}...");
|
|
||||||
|
|
||||||
foreach (string oldFileLocation in Directory.GetFiles(oldInstallLocation, "*.*", SearchOption.AllDirectories))
|
|
||||||
{
|
|
||||||
string relativeFile = oldFileLocation.Substring(oldInstallLocation.Length + 1);
|
|
||||||
string newFileLocation = Path.Combine(Paths.Base, relativeFile);
|
|
||||||
string? newDirectory = Path.GetDirectoryName(newFileLocation);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!String.IsNullOrEmpty(newDirectory))
|
|
||||||
Directory.CreateDirectory(newDirectory);
|
|
||||||
|
|
||||||
File.Move(oldFileLocation, newFileLocation, true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to move {oldFileLocation} to {newFileLocation}! {ex}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Directory.Delete(oldInstallLocation, true);
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Deleted old install location");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to delete old install location! {ex}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
applicationKey.DeleteValue("OldInstallLocation");
|
|
||||||
|
|
||||||
// allow shortcuts to be re-registered
|
|
||||||
if (Directory.Exists(Paths.StartMenu))
|
|
||||||
Directory.Delete(Paths.StartMenu, true);
|
|
||||||
|
|
||||||
if (File.Exists(DesktopShortcutLocation))
|
|
||||||
{
|
|
||||||
File.Delete(DesktopShortcutLocation);
|
|
||||||
App.Settings.Prop.CreateDesktopIcon = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Finished migrating install location!");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CheckInstall()
|
public static void CheckInstall()
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "Bootstrapper::CheckInstall";
|
const string LOG_IDENT = "Bootstrapper::CheckInstall";
|
||||||
@ -713,7 +685,7 @@ namespace Bloxstrap
|
|||||||
// if the folder we're installed to does not end with "Bloxstrap", we're installed to a user-selected folder
|
// if the folder we're installed to does not end with "Bloxstrap", we're installed to a user-selected folder
|
||||||
// in which case, chances are they chose to install to somewhere they didn't really mean to (prior to the added warning in 2.4.0)
|
// in which case, chances are they chose to install to somewhere they didn't really mean to (prior to the added warning in 2.4.0)
|
||||||
// if so, we're walking on eggshells and have to ensure we only clean up what we need to clean up
|
// if so, we're walking on eggshells and have to ensure we only clean up what we need to clean up
|
||||||
bool cautiousUninstall = !Paths.Base.EndsWith(App.ProjectName);
|
bool cautiousUninstall = !Paths.Base.ToLower().EndsWith(App.ProjectName.ToLower());
|
||||||
|
|
||||||
var cleanupSequence = new List<Action>
|
var cleanupSequence = new List<Action>
|
||||||
{
|
{
|
||||||
@ -783,7 +755,7 @@ namespace Bloxstrap
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialog?.ShowSuccess($"{App.ProjectName} has succesfully uninstalled", callback);
|
Dialog?.ShowSuccess($"{App.ProjectName} has successfully uninstalled", callback);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -906,7 +878,16 @@ namespace Bloxstrap
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Removing old version folder for {dir.Name}");
|
App.Logger.WriteLine(LOG_IDENT, $"Removing old version folder for {dir.Name}");
|
||||||
dir.Delete(true);
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
dir.Delete(true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Failed to delete version folder!");
|
||||||
|
App.Logger.WriteException(LOG_IDENT, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -999,6 +980,12 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
const string LOG_IDENT = "Bootstrapper::ApplyModifications";
|
const string LOG_IDENT = "Bootstrapper::ApplyModifications";
|
||||||
|
|
||||||
|
if (Process.GetProcessesByName("RobloxPlayerBeta").Where(x => x.MainModule!.FileName == _playerLocation).Any())
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Roblox is running, aborting mod check");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
SetStatus("Applying Roblox modifications...");
|
SetStatus("Applying Roblox modifications...");
|
||||||
|
|
||||||
// set executable flags for fullscreen optimizations
|
// set executable flags for fullscreen optimizations
|
||||||
@ -1332,6 +1319,9 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
for (int i = 1; i <= maxTries; i++)
|
for (int i = 1; i <= maxTries; i++)
|
||||||
{
|
{
|
||||||
|
if (_cancelFired)
|
||||||
|
return;
|
||||||
|
|
||||||
int totalBytesRead = 0;
|
int totalBytesRead = 0;
|
||||||
|
|
||||||
try
|
try
|
||||||
@ -1370,7 +1360,8 @@ namespace Bloxstrap
|
|||||||
App.Logger.WriteLine(LOG_IDENT, $"An exception occurred after downloading {totalBytesRead} bytes. ({i}/{maxTries})");
|
App.Logger.WriteLine(LOG_IDENT, $"An exception occurred after downloading {totalBytesRead} bytes. ({i}/{maxTries})");
|
||||||
App.Logger.WriteException(LOG_IDENT, ex);
|
App.Logger.WriteException(LOG_IDENT, ex);
|
||||||
|
|
||||||
File.Delete(packageLocation);
|
if (File.Exists(packageLocation))
|
||||||
|
File.Delete(packageLocation);
|
||||||
|
|
||||||
if (i >= maxTries)
|
if (i >= maxTries)
|
||||||
throw;
|
throw;
|
||||||
@ -1415,6 +1406,16 @@ namespace Bloxstrap
|
|||||||
if (directory is not null)
|
if (directory is not null)
|
||||||
Directory.CreateDirectory(directory);
|
Directory.CreateDirectory(directory);
|
||||||
|
|
||||||
|
if (File.Exists(extractPath))
|
||||||
|
{
|
||||||
|
var fileManifest = _versionFileManifest.FirstOrDefault(x => x.Name == Path.Combine(PackageDirectories[package.Name], entry.FullName));
|
||||||
|
|
||||||
|
if (fileManifest is not null && MD5Hash.FromFile(extractPath) == fileManifest.Signature)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
File.Delete(extractPath);
|
||||||
|
}
|
||||||
|
|
||||||
entry.ExtractToFile(extractPath, true);
|
entry.ExtractToFile(extractPath, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,8 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
public static IReadOnlyDictionary<string, string> PresetFlags = new Dictionary<string, string>
|
public static IReadOnlyDictionary<string, string> PresetFlags = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
|
{ "Network.Log", "FLogNetwork" },
|
||||||
|
|
||||||
{ "HTTP.Log", "DFLogHttpTraceLight" },
|
{ "HTTP.Log", "DFLogHttpTraceLight" },
|
||||||
|
|
||||||
{ "HTTP.Proxy.Enable", "DFFlagDebugEnableHttpProxy" },
|
{ "HTTP.Proxy.Enable", "DFFlagDebugEnableHttpProxy" },
|
||||||
@ -25,7 +27,6 @@ namespace Bloxstrap
|
|||||||
{ "Rendering.ManualFullscreen", "FFlagHandleAltEnterFullscreenManually" },
|
{ "Rendering.ManualFullscreen", "FFlagHandleAltEnterFullscreenManually" },
|
||||||
{ "Rendering.TexturePack", "FStringPartTexturePackTable2022" },
|
{ "Rendering.TexturePack", "FStringPartTexturePackTable2022" },
|
||||||
{ "Rendering.DisableScaling", "DFFlagDisableDPIScale" },
|
{ "Rendering.DisableScaling", "DFFlagDisableDPIScale" },
|
||||||
{ "Rendering.MSAA", "FIntDebugForceMSAASamples" },
|
|
||||||
|
|
||||||
{ "Rendering.Mode.D3D11", "FFlagDebugGraphicsPreferD3D11" },
|
{ "Rendering.Mode.D3D11", "FFlagDebugGraphicsPreferD3D11" },
|
||||||
{ "Rendering.Mode.D3D10", "FFlagDebugGraphicsPreferD3D11FL10" },
|
{ "Rendering.Mode.D3D10", "FFlagDebugGraphicsPreferD3D11FL10" },
|
||||||
@ -43,7 +44,12 @@ namespace Bloxstrap
|
|||||||
{ "UI.Menu.GraphicsSlider", "FFlagFixGraphicsQuality" },
|
{ "UI.Menu.GraphicsSlider", "FFlagFixGraphicsQuality" },
|
||||||
|
|
||||||
{ "UI.Menu.Style.DisableV2", "FFlagDisableNewIGMinDUA" },
|
{ "UI.Menu.Style.DisableV2", "FFlagDisableNewIGMinDUA" },
|
||||||
{ "UI.Menu.Style.EnableV4", "FFlagEnableInGameMenuControls" }
|
{ "UI.Menu.Style.EnableV4", "FFlagEnableInGameMenuControls" },
|
||||||
|
|
||||||
|
{ "UI.Menu.Style.ABTest.1", "FFlagEnableMenuControlsABTest" },
|
||||||
|
{ "UI.Menu.Style.ABTest.2", "FFlagEnableMenuModernizationABTest" },
|
||||||
|
{ "UI.Menu.Style.ABTest.3", "FFlagEnableMenuModernizationABTest2" },
|
||||||
|
{ "UI.Menu.Style.ABTest.4", "FFlagEnableV3MenuABTest3" }
|
||||||
};
|
};
|
||||||
|
|
||||||
// only one missing here is Metal because lol
|
// only one missing here is Metal because lol
|
||||||
@ -82,7 +88,8 @@ namespace Bloxstrap
|
|||||||
new Dictionary<string, string?>
|
new Dictionary<string, string?>
|
||||||
{
|
{
|
||||||
{ "DisableV2", null },
|
{ "DisableV2", null },
|
||||||
{ "EnableV4", null }
|
{ "EnableV4", null },
|
||||||
|
{ "ABTest", null }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -91,7 +98,8 @@ namespace Bloxstrap
|
|||||||
new Dictionary<string, string?>
|
new Dictionary<string, string?>
|
||||||
{
|
{
|
||||||
{ "DisableV2", "True" },
|
{ "DisableV2", "True" },
|
||||||
{ "EnableV4", "False" }
|
{ "EnableV4", "False" },
|
||||||
|
{ "ABTest", "False" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -100,7 +108,8 @@ namespace Bloxstrap
|
|||||||
new Dictionary<string, string?>
|
new Dictionary<string, string?>
|
||||||
{
|
{
|
||||||
{ "DisableV2", "False" },
|
{ "DisableV2", "False" },
|
||||||
{ "EnableV4", "False" }
|
{ "EnableV4", "False" },
|
||||||
|
{ "ABTest", "False" }
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -109,7 +118,8 @@ namespace Bloxstrap
|
|||||||
new Dictionary<string, string?>
|
new Dictionary<string, string?>
|
||||||
{
|
{
|
||||||
{ "DisableV2", "True" },
|
{ "DisableV2", "True" },
|
||||||
{ "EnableV4", "True" }
|
{ "EnableV4", "True" },
|
||||||
|
{ "ABTest", "False" }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -205,6 +215,11 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
CheckManualFullscreenPreset();
|
CheckManualFullscreenPreset();
|
||||||
|
|
||||||
|
// TODO - remove when activity tracking has been revamped
|
||||||
|
if (GetPreset("Network.Log") != "7")
|
||||||
|
SetPreset("Network.Log", "7");
|
||||||
|
|
||||||
|
|
||||||
if (GetPreset("Rendering.Framerate") is not null)
|
if (GetPreset("Rendering.Framerate") is not null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -18,8 +18,9 @@ global using Bloxstrap.Enums;
|
|||||||
global using Bloxstrap.Exceptions;
|
global using Bloxstrap.Exceptions;
|
||||||
global using Bloxstrap.Extensions;
|
global using Bloxstrap.Extensions;
|
||||||
global using Bloxstrap.Models;
|
global using Bloxstrap.Models;
|
||||||
global using Bloxstrap.Models.BloxstrapRPC;
|
|
||||||
global using Bloxstrap.Models.Attributes;
|
global using Bloxstrap.Models.Attributes;
|
||||||
|
global using Bloxstrap.Models.BloxstrapRPC;
|
||||||
global using Bloxstrap.Models.RobloxApi;
|
global using Bloxstrap.Models.RobloxApi;
|
||||||
|
global using Bloxstrap.Models.Manifest;
|
||||||
global using Bloxstrap.UI;
|
global using Bloxstrap.UI;
|
||||||
global using Bloxstrap.Utility;
|
global using Bloxstrap.Utility;
|
@ -1,5 +1,4 @@
|
|||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
using Microsoft.Win32;
|
using Microsoft.Win32;
|
||||||
|
|
||||||
namespace Bloxstrap
|
namespace Bloxstrap
|
||||||
@ -29,9 +28,23 @@ namespace Bloxstrap
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Installation registry key is likely malformed");
|
||||||
|
|
||||||
_installLocation = Path.GetDirectoryName(Paths.Process)!;
|
_installLocation = Path.GetDirectoryName(Paths.Process)!;
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Registry key is likely malformed. Setting install location as '{_installLocation}'");
|
var result = Controls.ShowMessageBox(
|
||||||
|
$"It appears as if {App.ProjectName} hasn't been properly installed. Is it supposed to be installed at {_installLocation}?",
|
||||||
|
MessageBoxImage.Warning,
|
||||||
|
MessageBoxButton.YesNo
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != MessageBoxResult.Yes)
|
||||||
|
{
|
||||||
|
FirstTimeRun();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, $"Setting install location as '{_installLocation}'");
|
||||||
|
|
||||||
if (_registryKey is null)
|
if (_registryKey is null)
|
||||||
_registryKey = Registry.CurrentUser.CreateSubKey($"Software\\{App.ProjectName}");
|
_registryKey = Registry.CurrentUser.CreateSubKey($"Software\\{App.ProjectName}");
|
||||||
@ -199,11 +212,23 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
// update migrations
|
// update migrations
|
||||||
|
|
||||||
if (App.BuildMetadata.CommitRef.StartsWith("tag") && existingVersionInfo.ProductVersion == "2.4.0")
|
if (App.BuildMetadata.CommitRef.StartsWith("tag"))
|
||||||
{
|
{
|
||||||
App.FastFlags.SetValue("DFFlagDisableDPIScale", null);
|
if (existingVersionInfo.ProductVersion == "2.4.0")
|
||||||
App.FastFlags.SetValue("DFFlagVariableDPIScale2", null);
|
{
|
||||||
App.FastFlags.Save();
|
App.FastFlags.SetValue("DFFlagDisableDPIScale", null);
|
||||||
|
App.FastFlags.SetValue("DFFlagVariableDPIScale2", null);
|
||||||
|
App.FastFlags.Save();
|
||||||
|
}
|
||||||
|
else if (existingVersionInfo.ProductVersion == "2.5.0")
|
||||||
|
{
|
||||||
|
App.FastFlags.SetValue("FIntDebugForceMSAASamples", null);
|
||||||
|
|
||||||
|
if (App.FastFlags.GetPreset("UI.Menu.Style.DisableV2") is not null)
|
||||||
|
App.FastFlags.SetPreset("UI.Menu.Style.ABTest", false);
|
||||||
|
|
||||||
|
App.FastFlags.Save();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isAutoUpgrade)
|
if (isAutoUpgrade)
|
||||||
|
@ -9,6 +9,7 @@ namespace Bloxstrap.Integrations
|
|||||||
|
|
||||||
private DiscordRPC.RichPresence? _currentPresence;
|
private DiscordRPC.RichPresence? _currentPresence;
|
||||||
private DiscordRPC.RichPresence? _currentPresenceCopy;
|
private DiscordRPC.RichPresence? _currentPresenceCopy;
|
||||||
|
private Message? _stashedRPCMessage;
|
||||||
|
|
||||||
private bool _visible = true;
|
private bool _visible = true;
|
||||||
private long _currentUniverseId;
|
private long _currentUniverseId;
|
||||||
@ -55,6 +56,13 @@ namespace Bloxstrap.Integrations
|
|||||||
|
|
||||||
if (_currentPresence is null || _currentPresenceCopy is null)
|
if (_currentPresence is null || _currentPresenceCopy is null)
|
||||||
{
|
{
|
||||||
|
if (_activityWatcher.ActivityInGame)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Presence is not yet set, but is currently in game, stashing presence set request");
|
||||||
|
_stashedRPCMessage = message;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Presence is not set, aborting");
|
App.Logger.WriteLine(LOG_IDENT, "Presence is not set, aborting");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -173,7 +181,10 @@ namespace Bloxstrap.Integrations
|
|||||||
if (!_activityWatcher.ActivityInGame)
|
if (!_activityWatcher.ActivityInGame)
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Not in game, clearing presence");
|
App.Logger.WriteLine(LOG_IDENT, "Not in game, clearing presence");
|
||||||
_currentPresence = _currentPresenceCopy = null;
|
|
||||||
|
_currentPresence = _currentPresenceCopy = null;
|
||||||
|
_stashedRPCMessage = null;
|
||||||
|
|
||||||
UpdatePresence();
|
UpdatePresence();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -250,6 +261,9 @@ namespace Bloxstrap.Integrations
|
|||||||
_ => $"by {universeDetails.Creator.Name}" + (universeDetails.Creator.HasVerifiedBadge ? " ☑️" : ""),
|
_ => $"by {universeDetails.Creator.Name}" + (universeDetails.Creator.HasVerifiedBadge ? " ☑️" : ""),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (universeDetails.Name.Length < 2)
|
||||||
|
universeDetails.Name = $"{universeDetails.Name}\x2800\x2800\x2800";
|
||||||
|
|
||||||
_currentPresence = new DiscordRPC.RichPresence
|
_currentPresence = new DiscordRPC.RichPresence
|
||||||
{
|
{
|
||||||
Details = $"Playing {universeDetails.Name}",
|
Details = $"Playing {universeDetails.Name}",
|
||||||
@ -268,7 +282,16 @@ namespace Bloxstrap.Integrations
|
|||||||
// this is used for configuration from BloxstrapRPC
|
// this is used for configuration from BloxstrapRPC
|
||||||
_currentPresenceCopy = _currentPresence.Clone();
|
_currentPresenceCopy = _currentPresence.Clone();
|
||||||
|
|
||||||
UpdatePresence();
|
if (_stashedRPCMessage is not null)
|
||||||
|
{
|
||||||
|
App.Logger.WriteLine(LOG_IDENT, "Found stashed RPC message, invoking presence set command now");
|
||||||
|
ProcessRPCMessage(_stashedRPCMessage);
|
||||||
|
_stashedRPCMessage = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UpdatePresence();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
catch (IOException)
|
catch (IOException)
|
||||||
{
|
{
|
||||||
WriteLine(LOG_IDENT, "Failed to initialize because log file already exists");
|
WriteLine(LOG_IDENT, "Failed to initialize because log file already exists");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -64,7 +65,16 @@
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
WriteLine(LOG_IDENT, $"Cleaning up old log file '{log.Name}'");
|
WriteLine(LOG_IDENT, $"Cleaning up old log file '{log.Name}'");
|
||||||
log.Delete();
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
log.Delete();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
WriteLine(LOG_IDENT, "Failed to delete log!");
|
||||||
|
WriteException(LOG_IDENT, ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
33
Bloxstrap/Models/Manifest/FileManifest.cs
Normal file
33
Bloxstrap/Models/Manifest/FileManifest.cs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
namespace Bloxstrap.Models.Manifest
|
||||||
|
{
|
||||||
|
public class FileManifest : List<ManifestFile>
|
||||||
|
{
|
||||||
|
private FileManifest(string data)
|
||||||
|
{
|
||||||
|
using StringReader reader = new StringReader(data);
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
string? fileName = reader.ReadLine();
|
||||||
|
string? signature = reader.ReadLine();
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(fileName) || string.IsNullOrEmpty(signature))
|
||||||
|
break;
|
||||||
|
|
||||||
|
Add(new ManifestFile
|
||||||
|
{
|
||||||
|
Name = fileName,
|
||||||
|
Signature = signature
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<FileManifest> Get(string versionGuid)
|
||||||
|
{
|
||||||
|
string pkgManifestUrl = RobloxDeployment.GetLocation($"/{versionGuid}-rbxManifest.txt");
|
||||||
|
var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl);
|
||||||
|
|
||||||
|
return new FileManifest(pkgManifestData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
Bloxstrap/Models/Manifest/ManifestFile.cs
Normal file
13
Bloxstrap/Models/Manifest/ManifestFile.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace Bloxstrap.Models.Manifest
|
||||||
|
{
|
||||||
|
public class ManifestFile
|
||||||
|
{
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public string Signature { get; set; } = "";
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"[{Signature}] {Name}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,7 +4,7 @@
|
|||||||
* Copyright (c) 2015-present MaximumADHD
|
* Copyright (c) 2015-present MaximumADHD
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Bloxstrap.Models
|
namespace Bloxstrap.Models.Manifest
|
||||||
{
|
{
|
||||||
public class Package
|
public class Package
|
||||||
{
|
{
|
@ -4,7 +4,7 @@
|
|||||||
* Copyright (c) 2015-present MaximumADHD
|
* Copyright (c) 2015-present MaximumADHD
|
||||||
*/
|
*/
|
||||||
|
|
||||||
namespace Bloxstrap.Models
|
namespace Bloxstrap.Models.Manifest
|
||||||
{
|
{
|
||||||
public class PackageManifest : List<Package>
|
public class PackageManifest : List<Package>
|
||||||
{
|
{
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
private static Dictionary<string, ClientVersion> ClientVersionCache = new();
|
private static Dictionary<string, ClientVersion> ClientVersionCache = new();
|
||||||
|
|
||||||
// a list of roblox delpoyment locations that we check for, in case one of them don't work
|
// a list of roblox deployment locations that we check for, in case one of them don't work
|
||||||
private static List<string> BaseUrls = new()
|
private static List<string> BaseUrls = new()
|
||||||
{
|
{
|
||||||
"https://setup.rbxcdn.com",
|
"https://setup.rbxcdn.com",
|
||||||
@ -52,18 +52,6 @@
|
|||||||
return _baseUrl;
|
return _baseUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// most commonly used/interesting channels
|
|
||||||
public static readonly List<string> SelectableChannels = new()
|
|
||||||
{
|
|
||||||
"LIVE",
|
|
||||||
"ZFlag",
|
|
||||||
"ZNext",
|
|
||||||
"ZCanary",
|
|
||||||
"ZIntegration",
|
|
||||||
"ZAvatarTeam",
|
|
||||||
"ZSocialTeam"
|
|
||||||
};
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public static string GetLocation(string resource, string? channel = null)
|
public static string GetLocation(string resource, string? channel = null)
|
||||||
|
@ -96,7 +96,7 @@ namespace Bloxstrap.UI.Elements.ContextMenu
|
|||||||
|
|
||||||
private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) => _richPresenceHandler?.SetVisibility(((MenuItem)sender).IsChecked);
|
private void RichPresenceMenuItem_Click(object sender, RoutedEventArgs e) => _richPresenceHandler?.SetVisibility(((MenuItem)sender).IsChecked);
|
||||||
|
|
||||||
private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetText($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}");
|
private void InviteDeeplinkMenuItem_Click(object sender, RoutedEventArgs e) => Clipboard.SetDataObject($"roblox://experiences/start?placeId={_activityWatcher?.ActivityPlaceId}&gameInstanceId={_activityWatcher?.ActivityJobId}");
|
||||||
|
|
||||||
private void ServerDetailsMenuItem_Click(object sender, RoutedEventArgs e) => ShowServerInformationWindow();
|
private void ServerDetailsMenuItem_Click(object sender, RoutedEventArgs e) => ShowServerInformationWindow();
|
||||||
|
|
||||||
|
@ -33,10 +33,10 @@
|
|||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" MinWidth="100" Text="Flag name" Margin="0,0,0,12" />
|
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" MinWidth="100" Text="Name" Margin="0,0,0,12" />
|
||||||
<TextBox Grid.Row="0" Grid.Column="1" Name="FlagNameTextBox" Margin="0,0,0,12" />
|
<TextBox Grid.Row="0" Grid.Column="1" Name="FlagNameTextBox" Margin="0,0,0,12" />
|
||||||
|
|
||||||
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" MinWidth="100" Text="Flag value" />
|
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center" MinWidth="100" Text="Value" />
|
||||||
<TextBox Grid.Row="1" Grid.Column="1" Name="FlagValueTextBox" />
|
<TextBox Grid.Row="1" Grid.Column="1" Name="FlagValueTextBox" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
60
Bloxstrap/UI/Elements/Dialogs/BulkAddFastFlagDialog.xaml
Normal file
60
Bloxstrap/UI/Elements/Dialogs/BulkAddFastFlagDialog.xaml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<ui:UiWindow x:Class="Bloxstrap.UI.Elements.Dialogs.BulkAddFastFlagDialog"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
|
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Dialogs"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="Import JSON"
|
||||||
|
MinHeight="0"
|
||||||
|
Width="480"
|
||||||
|
SizeToContent="Height"
|
||||||
|
ResizeMode="NoResize"
|
||||||
|
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
||||||
|
ExtendsContentIntoTitleBar="True"
|
||||||
|
WindowStartupLocation="CenterScreen">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<ui:TitleBar Grid.Row="0" Grid.ColumnSpan="2" Padding="8" Title="Import JSON" ShowMinimize="False" ShowMaximize="False" CanMaximize="False" KeyboardNavigation.TabNavigation="None" />
|
||||||
|
|
||||||
|
<Grid Grid.Row="1" Margin="8,4,8,4">
|
||||||
|
<TextBox x:Name="JsonTextBox" Margin="5" AcceptsTab="True" AcceptsReturn="True" MinHeight="80" MaxHeight="480" />
|
||||||
|
<TextBlock IsHitTestVisible="False" Margin="18,14,0,0" Foreground="DarkGray">
|
||||||
|
<TextBlock.Style>
|
||||||
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
|
<Setter Property="Visibility" Value="Collapsed"/>
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Text, ElementName=JsonTextBox}" Value="">
|
||||||
|
<Setter Property="Visibility" Value="Visible"/>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</TextBlock.Style>
|
||||||
|
Paste in your JSON here...
|
||||||
|
</TextBlock>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Border Grid.Row="3" Margin="0,10,0,0" Padding="15" Background="{ui:ThemeResource SolidBackgroundFillColorSecondaryBrush}">
|
||||||
|
<StackPanel Orientation="Horizontal" FlowDirection="LeftToRight" HorizontalAlignment="Right">
|
||||||
|
<Button MinWidth="100" Content="OK" Click="OKButton_Click">
|
||||||
|
<Button.Style>
|
||||||
|
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding ElementName=JsonTextBox, Path=Text.Length}" Value="0">
|
||||||
|
<Setter Property="IsEnabled" Value="False" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Button.Style>
|
||||||
|
</Button>
|
||||||
|
<Button MinWidth="100" Margin="12,0,0,0" Content="Cancel" IsCancel="True" />
|
||||||
|
</StackPanel>
|
||||||
|
</Border>
|
||||||
|
</Grid>
|
||||||
|
</ui:UiWindow>
|
35
Bloxstrap/UI/Elements/Dialogs/BulkAddFastFlagDialog.xaml.cs
Normal file
35
Bloxstrap/UI/Elements/Dialogs/BulkAddFastFlagDialog.xaml.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
namespace Bloxstrap.UI.Elements.Dialogs
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interaction logic for BulkAddFastFlagDialog.xaml
|
||||||
|
/// </summary>
|
||||||
|
public partial class BulkAddFastFlagDialog
|
||||||
|
{
|
||||||
|
public MessageBoxResult Result = MessageBoxResult.Cancel;
|
||||||
|
|
||||||
|
public BulkAddFastFlagDialog()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OKButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Result = MessageBoxResult.OK;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,17 +16,12 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
|||||||
{
|
{
|
||||||
public ConnectivityDialog(string targetName, string description, Exception exception)
|
public ConnectivityDialog(string targetName, string description, Exception exception)
|
||||||
{
|
{
|
||||||
Exception? innerException = exception.InnerException;
|
|
||||||
|
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
TitleTextBlock.Text = $"{App.ProjectName} is unable to connect to {targetName}";
|
TitleTextBlock.Text = $"{App.ProjectName} is unable to connect to {targetName}";
|
||||||
DescriptionTextBlock.Text = description;
|
DescriptionTextBlock.Text = description;
|
||||||
|
|
||||||
ErrorRichTextBox.Selection.Text = $"{exception.GetType()}: {exception.Message}";
|
AddException(exception);
|
||||||
|
|
||||||
if (innerException is not null)
|
|
||||||
ErrorRichTextBox.Selection.Text += $"\n\n===== Inner Exception =====\n{innerException.GetType()}: {innerException.Message}";
|
|
||||||
|
|
||||||
CloseButton.Click += delegate
|
CloseButton.Click += delegate
|
||||||
{
|
{
|
||||||
@ -41,5 +36,18 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
|||||||
PInvoke.FlashWindow((HWND)hWnd, true);
|
PInvoke.FlashWindow((HWND)hWnd, true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddException(Exception exception, bool inner = false)
|
||||||
|
{
|
||||||
|
if (!inner)
|
||||||
|
ErrorRichTextBox.Selection.Text = $"{exception.GetType()}: {exception.Message}";
|
||||||
|
|
||||||
|
if (exception.InnerException is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ErrorRichTextBox.Selection.Text += $"\n\n[Inner Exception]\n{exception.InnerException.GetType()}: {exception.InnerException.Message}";
|
||||||
|
|
||||||
|
AddException(exception.InnerException, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Dialogs"
|
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Dialogs"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Width="480"
|
Width="540"
|
||||||
MinHeight="0"
|
MinHeight="0"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
Background="{ui:ThemeResource ApplicationBackgroundBrush}"
|
||||||
|
@ -22,10 +22,8 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
|||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Title = RootTitleBar.Title = $"{App.ProjectName} Exception";
|
Title = RootTitleBar.Title = $"{App.ProjectName} Exception";
|
||||||
ErrorRichTextBox.Selection.Text = $"{exception.GetType()}: {exception.Message}";
|
|
||||||
|
|
||||||
if (innerException is not null)
|
AddException(exception);
|
||||||
ErrorRichTextBox.Selection.Text += $"\n\n===== Inner Exception =====\n{innerException.GetType()}: {innerException.Message}";
|
|
||||||
|
|
||||||
if (!App.Logger.Initialized)
|
if (!App.Logger.Initialized)
|
||||||
LocateLogFileButton.Content = "Copy log contents";
|
LocateLogFileButton.Content = "Copy log contents";
|
||||||
@ -35,7 +33,7 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
|||||||
if (App.Logger.Initialized)
|
if (App.Logger.Initialized)
|
||||||
Process.Start("explorer.exe", $"/select,\"{App.Logger.FileLocation}\"");
|
Process.Start("explorer.exe", $"/select,\"{App.Logger.FileLocation}\"");
|
||||||
else
|
else
|
||||||
Clipboard.SetText(String.Join("\r\n", App.Logger.Backlog));
|
Clipboard.SetDataObject(String.Join("\r\n", App.Logger.Backlog));
|
||||||
};
|
};
|
||||||
|
|
||||||
ReportOptions.DropDownClosed += (sender, e) =>
|
ReportOptions.DropDownClosed += (sender, e) =>
|
||||||
@ -66,5 +64,18 @@ namespace Bloxstrap.UI.Elements.Dialogs
|
|||||||
PInvoke.FlashWindow((HWND)hWnd, true);
|
PInvoke.FlashWindow((HWND)hWnd, true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddException(Exception exception, bool inner = false)
|
||||||
|
{
|
||||||
|
if (!inner)
|
||||||
|
ErrorRichTextBox.Selection.Text = $"{exception.GetType()}: {exception.Message}";
|
||||||
|
|
||||||
|
if (exception.InnerException is null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ErrorRichTextBox.Selection.Text += $"\n\n[Inner Exception]\n{exception.InnerException.GetType()}: {exception.InnerException.Message}";
|
||||||
|
|
||||||
|
AddException(exception.InnerException, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,26 +59,24 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StatusBar x:Name="RootStatusBar" Grid.Row="2" Padding="14,10" Background="{ui:ThemeResource ApplicationBackgroundBrush}" BorderThickness="0,1,0,0">
|
<StatusBar x:Name="RootStatusBar" Grid.Row="2" Padding="14,10" Background="{ui:ThemeResource ApplicationBackgroundBrush}" BorderThickness="0,1,0,0">
|
||||||
<StatusBar.ItemsPanel>
|
<StatusBar.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
</Grid>
|
</Grid>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</StatusBar.ItemsPanel>
|
</StatusBar.ItemsPanel>
|
||||||
<StatusBarItem Grid.Column="1" Padding="0,0,4,0">
|
<StatusBarItem Grid.Column="1" Padding="0,0,4,0">
|
||||||
<ui:Button Content="{Binding ConfirmButtonText, Mode=OneTime}" Appearance="Primary" Command="{Binding ConfirmSettingsCommand, Mode=OneWay}" IsEnabled="{Binding ConfirmButtonEnabled, Mode=OneWay}" />
|
<ui:Button Content="{Binding ConfirmButtonText, Mode=OneTime}" Appearance="Primary" Command="{Binding ConfirmSettingsCommand, Mode=OneWay}" IsEnabled="{Binding ConfirmButtonEnabled, Mode=OneWay}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
<StatusBarItem Grid.Column="2" Padding="4,0,0,0">
|
<StatusBarItem Grid.Column="2" Padding="4,0,0,0">
|
||||||
<ui:Button Content="Cancel" Command="{Binding CloseWindowCommand, Mode=OneWay}" />
|
<ui:Button Content="Cancel" Command="{Binding CloseWindowCommand, Mode=OneWay}" />
|
||||||
</StatusBarItem>
|
</StatusBarItem>
|
||||||
</StatusBar>
|
</StatusBar>
|
||||||
|
</Grid>
|
||||||
<ui:Dialog x:Name="RootDialog" Title="WPF UI" Grid.Row="1" Grid.RowSpan="2" ButtonLeftVisibility="Collapsed" ButtonRightName="Continue" DialogHeight="225" DialogWidth="430" />
|
|
||||||
</Grid>
|
|
||||||
</ui:UiWindow>
|
</ui:UiWindow>
|
||||||
|
@ -15,16 +15,14 @@ namespace Bloxstrap.UI.Elements.Menu
|
|||||||
public partial class MainWindow : INavigationWindow
|
public partial class MainWindow : INavigationWindow
|
||||||
{
|
{
|
||||||
private readonly IThemeService _themeService = new ThemeService();
|
private readonly IThemeService _themeService = new ThemeService();
|
||||||
private readonly IDialogService _dialogService = new DialogService();
|
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
App.Logger.WriteLine("MainWindow::MainWindow", "Initializing menu");
|
App.Logger.WriteLine("MainWindow::MainWindow", "Initializing menu");
|
||||||
|
|
||||||
DataContext = new MainWindowViewModel(this, _dialogService);
|
DataContext = new MainWindowViewModel(this);
|
||||||
SetTheme();
|
SetTheme();
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
_dialogService.SetDialogControl(RootDialog);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetTheme()
|
public void SetTheme()
|
||||||
|
@ -46,7 +46,7 @@
|
|||||||
<TextBlock FontSize="14" Text="Channel" />
|
<TextBlock FontSize="14" Text="Channel" />
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Choose which deployment channel Roblox should be downloaded from." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Choose which deployment channel Roblox should be downloaded from." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ComboBox Grid.Column="1" Margin="8,0,8,0" Padding="10,5,10,5" Width="200" IsEditable="True" ItemsSource="{Binding Channels, Mode=OneWay}" Text="{Binding SelectedChannel, Mode=TwoWay, Delay=250}" />
|
<ui:TextBox Grid.Column="1" Margin="8,0,8,0" Padding="10,5,10,5" Width="200" Text="{Binding SelectedChannel, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, Delay=250}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ui:CardExpander.Header>
|
</ui:CardExpander.Header>
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using Bloxstrap.UI.ViewModels.Menu;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@ -14,6 +13,8 @@ using System.Windows.Media.Imaging;
|
|||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
using Bloxstrap.UI.ViewModels.Menu;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.Elements.Menu.Pages
|
namespace Bloxstrap.UI.Elements.Menu.Pages
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Margin="0,0,0,16" Text="Manage your own FastFlags. Double click the value column to edit." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
<TextBlock Grid.Row="0" Margin="0,0,0,16" Text="Manage your own FastFlags. Double click a column to edit." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||||
|
|
||||||
<StackPanel Grid.Row="1" Margin="0,0,0,16" Orientation="Horizontal">
|
<StackPanel Grid.Row="1" Margin="0,0,0,16" Orientation="Horizontal">
|
||||||
<ui:Button Icon="ArrowLeft48" Content="Back" Click="BackButton_Click" />
|
<ui:Button Icon="ArrowLeft48" Content="Back" Click="BackButton_Click" />
|
||||||
@ -87,7 +87,7 @@
|
|||||||
</DataGrid.CellStyle>
|
</DataGrid.CellStyle>
|
||||||
|
|
||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn Header="Name" Binding="{Binding Name}" IsReadOnly="True" />
|
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
|
||||||
<DataGridTextColumn Header="Value" Binding="{Binding Value}" Width="*" />
|
<DataGridTextColumn Header="Value" Binding="{Binding Value}" Width="*" />
|
||||||
</DataGrid.Columns>
|
</DataGrid.Columns>
|
||||||
</DataGrid>
|
</DataGrid>
|
||||||
|
@ -8,6 +8,7 @@ using Microsoft.Win32;
|
|||||||
using Wpf.Ui.Mvvm.Contracts;
|
using Wpf.Ui.Mvvm.Contracts;
|
||||||
|
|
||||||
using Bloxstrap.UI.Elements.Dialogs;
|
using Bloxstrap.UI.Elements.Dialogs;
|
||||||
|
using System.Xml.Linq;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.Elements.Menu.Pages
|
namespace Bloxstrap.UI.Elements.Menu.Pages
|
||||||
{
|
{
|
||||||
@ -111,11 +112,28 @@ namespace Bloxstrap.UI.Elements.Menu.Pages
|
|||||||
break; */
|
break; */
|
||||||
|
|
||||||
case "Name":
|
case "Name":
|
||||||
string newName = ((TextBox)e.EditingElement).Text;
|
var textbox = e.EditingElement as TextBox;
|
||||||
|
|
||||||
App.FastFlags.SetValue(entry.Name, null);
|
string oldName = entry.Name;
|
||||||
|
string newName = textbox!.Text;
|
||||||
|
|
||||||
|
if (newName == oldName)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (App.FastFlags.GetValue(newName) is not null)
|
||||||
|
{
|
||||||
|
Controls.ShowMessageBox("A FastFlag with this name already exists.", MessageBoxImage.Information);
|
||||||
|
e.Cancel = true;
|
||||||
|
textbox.Text = oldName;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
App.FastFlags.SetValue(oldName, null);
|
||||||
App.FastFlags.SetValue(newName, entry.Value);
|
App.FastFlags.SetValue(newName, entry.Value);
|
||||||
|
|
||||||
|
if (!newName.Contains(_searchFilter))
|
||||||
|
ClearSearch();
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "Value":
|
case "Value":
|
||||||
@ -215,58 +233,65 @@ namespace Bloxstrap.UI.Elements.Menu.Pages
|
|||||||
|
|
||||||
private void ImportJSONButton_Click(object sender, RoutedEventArgs e)
|
private void ImportJSONButton_Click(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var dialog = new OpenFileDialog
|
string json = "";
|
||||||
|
Dictionary<string, object>? list = null;
|
||||||
|
|
||||||
|
while (list is null)
|
||||||
{
|
{
|
||||||
Filter = "JSON files|*.json|All files|*.*"
|
var dialog = new BulkAddFastFlagDialog();
|
||||||
};
|
dialog.JsonTextBox.Text = json;
|
||||||
|
dialog.ShowDialog();
|
||||||
|
|
||||||
if (dialog.ShowDialog() != true)
|
if (dialog.Result != MessageBoxResult.OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
try
|
json = dialog.JsonTextBox.Text;
|
||||||
{
|
|
||||||
var list = JsonSerializer.Deserialize<Dictionary<string, object>>(File.ReadAllText(dialog.FileName));
|
|
||||||
|
|
||||||
if (list is null)
|
try
|
||||||
throw new Exception("JSON deserialization returned null");
|
|
||||||
|
|
||||||
var conflictingFlags = App.FastFlags.Prop.Where(x => list.ContainsKey(x.Key)).Select(x => x.Key);
|
|
||||||
bool overwriteConflicting = false;
|
|
||||||
|
|
||||||
if (conflictingFlags.Any())
|
|
||||||
{
|
{
|
||||||
var result = Controls.ShowMessageBox(
|
list = JsonSerializer.Deserialize<Dictionary<string, object>>(json);
|
||||||
"Some of the flags you are attempting to import already have set values. Would you like to overwrite their current values with the ones defined in the import?\n" +
|
|
||||||
|
if (list is null)
|
||||||
|
throw new Exception("JSON deserialization returned null");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Controls.ShowMessageBox(
|
||||||
|
"The JSON you've entered does not appear to be valid. Please double check it and try again.\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"Conflicting flags:\n" +
|
"More information:\n" +
|
||||||
String.Join(", ", conflictingFlags),
|
$"{ex.Message}",
|
||||||
MessageBoxImage.Question,
|
MessageBoxImage.Error
|
||||||
MessageBoxButton.YesNo
|
|
||||||
);
|
);
|
||||||
|
|
||||||
overwriteConflicting = result == MessageBoxResult.Yes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var pair in list)
|
|
||||||
{
|
|
||||||
if (App.FastFlags.Prop.ContainsKey(pair.Key) && !overwriteConflicting)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
App.FastFlags.SetValue(pair.Key, pair.Value);
|
|
||||||
}
|
|
||||||
|
|
||||||
ClearSearch();
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
|
var conflictingFlags = App.FastFlags.Prop.Where(x => list.ContainsKey(x.Key)).Select(x => x.Key);
|
||||||
|
bool overwriteConflicting = false;
|
||||||
|
|
||||||
|
if (conflictingFlags.Any())
|
||||||
{
|
{
|
||||||
Controls.ShowMessageBox(
|
var result = Controls.ShowMessageBox(
|
||||||
"The file you've selected does not appear to be valid JSON. Please double check the file contents and try again.\n" +
|
"Some of the flags you are attempting to import already have set values. Would you like to overwrite their current values with the ones defined in the import?\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"More information:\n" +
|
"Conflicting flags:\n" +
|
||||||
$"{ex.Message}",
|
String.Join(", ", conflictingFlags),
|
||||||
MessageBoxImage.Error
|
MessageBoxImage.Question,
|
||||||
|
MessageBoxButton.YesNo
|
||||||
);
|
);
|
||||||
|
|
||||||
|
overwriteConflicting = result == MessageBoxResult.Yes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var pair in list)
|
||||||
|
{
|
||||||
|
if (App.FastFlags.Prop.ContainsKey(pair.Key) && !overwriteConflicting)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
App.FastFlags.SetValue(pair.Key, pair.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
ClearSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
@ -171,15 +171,6 @@
|
|||||||
</ui:CardControl.Header>
|
</ui:CardControl.Header>
|
||||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding RenderingModes.Keys, Mode=OneTime}" Text="{Binding SelectedRenderingMode, Mode=TwoWay}" />
|
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding RenderingModes.Keys, Mode=OneTime}" Text="{Binding SelectedRenderingMode, Mode=TwoWay}" />
|
||||||
</ui:CardControl>
|
</ui:CardControl>
|
||||||
<ui:CardControl Margin="0,8,0,0">
|
|
||||||
<ui:CardControl.Header>
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="14" Text="Antialiasing quality" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Forces the amount of MSAA samples that are taken." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardControl.Header>
|
|
||||||
<ComboBox Margin="5,0,0,0" Padding="10,5,10,5" Width="200" ItemsSource="{Binding MSAAModes.Keys, Mode=OneTime}" Text="{Binding SelectedMSAAMode, Mode=TwoWay}" />
|
|
||||||
</ui:CardControl>
|
|
||||||
<ui:CardControl Margin="0,8,0,0">
|
<ui:CardControl Margin="0,8,0,0">
|
||||||
<ui:CardControl.Header>
|
<ui:CardControl.Header>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
|
@ -3,64 +3,77 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:models="clr-namespace:Bloxstrap.UI.ViewModels"
|
|
||||||
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
xmlns:ui="http://schemas.lepo.co/wpfui/2022/xaml"
|
||||||
|
xmlns:local="clr-namespace:Bloxstrap.UI.Elements.Menu.Pages"
|
||||||
|
xmlns:models="clr-namespace:Bloxstrap.UI.ViewModels"
|
||||||
|
xmlns:viewmodels="clr-namespace:Bloxstrap.UI.ViewModels.Menu"
|
||||||
|
d:DataContext="{d:DesignInstance Type=viewmodels:InstallationViewModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
Title="InstallationPage"
|
Title="InstallationPage">
|
||||||
Scrollable="True">
|
|
||||||
<StackPanel Margin="0,0,14,14">
|
|
||||||
<TextBlock Text="Configure how Bloxstrap/Roblox is installed." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
|
||||||
|
|
||||||
<ui:CardExpander Margin="0,16,0,0" IsExpanded="True">
|
<StackPanel Margin="0,0,14,14">
|
||||||
<ui:CardExpander.Header>
|
<TextBlock Text="Configure how Bloxstrap/Roblox is installed." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||||
<StackPanel>
|
|
||||||
<TextBlock FontSize="14" Text="Install Location" />
|
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Choose where Bloxstrap should be installed to." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
|
||||||
</StackPanel>
|
|
||||||
</ui:CardExpander.Header>
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBox Grid.Column="0" Margin="0,0,4,0" Text="{Binding InstallLocation, Mode=TwoWay}" />
|
|
||||||
<ui:Button Grid.Column="1" Margin="4,0,4,0" Height="35" Icon="Folder24" Content="Browse" Command="{Binding BrowseInstallLocationCommand}" />
|
|
||||||
<ui:Button Grid.Column="2" Margin="4,0,0,0" Height="35" Icon="ArrowCounterclockwise24" Content="Reset" Command="{Binding ResetInstallLocationCommand}" />
|
|
||||||
</Grid>
|
|
||||||
</ui:CardExpander>
|
|
||||||
|
|
||||||
<Grid Margin="0,8,0,0">
|
<ui:CardExpander Margin="0,16,0,0" IsExpanded="True">
|
||||||
<Grid.Style>
|
<ui:CardExpander.Style>
|
||||||
<Style TargetType="Grid">
|
<Style TargetType="ui:CardExpander" BasedOn="{StaticResource {x:Type ui:CardExpander}}">
|
||||||
<Setter Property="Visibility" Value="Collapsed" />
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
<DataTrigger Binding="{Binding Source={x:Static models:GlobalViewModel.IsNotFirstRun}}" Value="True">
|
<DataTrigger Binding="{Binding Source={x:Static models:GlobalViewModel.IsNotFirstRun}}" Value="False">
|
||||||
<Setter Property="Visibility" Value="Visible" />
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
</DataTrigger>
|
</DataTrigger>
|
||||||
</Style.Triggers>
|
</Style.Triggers>
|
||||||
</Style>
|
</Style>
|
||||||
</Grid.Style>
|
</ui:CardExpander.Style>
|
||||||
|
<ui:CardExpander.Header>
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="Install Location" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Choose where Bloxstrap should be installed to." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardExpander.Header>
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBox Grid.Column="0" Margin="0,0,4,0" Text="{Binding InstallLocation, Mode=TwoWay}" />
|
||||||
|
<ui:Button Grid.Column="1" Margin="4,0,4,0" Height="35" Icon="Folder24" Content="Browse" Command="{Binding BrowseInstallLocationCommand}" />
|
||||||
|
<ui:Button Grid.Column="2" Margin="4,0,0,0" Height="35" Icon="ArrowCounterclockwise24" Content="Reset" Command="{Binding ResetInstallLocationCommand}" />
|
||||||
|
</Grid>
|
||||||
|
</ui:CardExpander>
|
||||||
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid Margin="0,8,0,0">
|
||||||
<ColumnDefinition Width="*" />
|
<Grid.Style>
|
||||||
<ColumnDefinition Width="*" />
|
<Style TargetType="Grid">
|
||||||
</Grid.ColumnDefinitions>
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding Source={x:Static models:GlobalViewModel.IsNotFirstRun}}" Value="True">
|
||||||
|
<Setter Property="Visibility" Value="Visible" />
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Grid.Style>
|
||||||
|
|
||||||
<ui:CardAction Grid.Column="0" x:Name="OpenFolderCardAction" Margin="0,0,4,0" Icon="Folder24" Command="{Binding OpenFolderCommand}" >
|
<Grid.ColumnDefinitions>
|
||||||
<StackPanel>
|
<ColumnDefinition Width="*" />
|
||||||
<TextBlock FontSize="14" Text="Open Installation Folder" />
|
<ColumnDefinition Width="*" />
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Where Bloxstrap is currently installed to." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
</Grid.ColumnDefinitions>
|
||||||
</StackPanel>
|
|
||||||
</ui:CardAction>
|
|
||||||
|
|
||||||
<ui:CardAction Grid.Column="1" Margin="4,0,0,0" Icon="UninstallApp24" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/Uninstalling-Bloxstrap">
|
<ui:CardAction Grid.Column="0" x:Name="OpenFolderCardAction" Margin="0,0,4,0" Icon="Folder24" Command="{Binding OpenFolderCommand}" >
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock FontSize="14" Text="Looking to uninstall?" />
|
<TextBlock FontSize="14" Text="Open Installation Folder" />
|
||||||
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Here's a guide on how to uninstall Bloxstrap." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Where Bloxstrap is currently installed to." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ui:CardAction>
|
</ui:CardAction>
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
<ui:CardAction Grid.Column="1" Margin="4,0,0,0" Icon="UninstallApp24" Command="models:GlobalViewModel.OpenWebpageCommand" CommandParameter="https://github.com/pizzaboxer/bloxstrap/wiki/Uninstalling-Bloxstrap">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock FontSize="14" Text="Looking to uninstall?" />
|
||||||
|
<TextBlock Margin="0,2,0,0" FontSize="12" Text="Here's a guide on how to uninstall Bloxstrap." Foreground="{DynamicResource TextFillColorTertiaryBrush}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ui:CardAction>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
</ui:UiPage>
|
</ui:UiPage>
|
||||||
|
@ -1,4 +1,19 @@
|
|||||||
using Bloxstrap.UI.ViewModels.Menu;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Data;
|
||||||
|
using System.Windows.Documents;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using System.Windows.Media;
|
||||||
|
using System.Windows.Media.Imaging;
|
||||||
|
using System.Windows.Navigation;
|
||||||
|
using System.Windows.Shapes;
|
||||||
|
|
||||||
|
using Bloxstrap.UI.ViewModels.Menu;
|
||||||
|
|
||||||
namespace Bloxstrap.UI.Elements.Menu.Pages
|
namespace Bloxstrap.UI.Elements.Menu.Pages
|
||||||
{
|
{
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<StackPanel Margin="0,0,14,14">
|
<StackPanel Margin="0,0,14,14">
|
||||||
<TextBlock Text="Configure quick and easy ways to improve the Roblox gameplay experience." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
<TextBlock Text="Configure quick and easy ways to improve the Roblox gameplay experience." FontSize="14" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||||
|
|
||||||
<TextBlock Text="Roblox activity tracking" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
|
<TextBlock Text="Activity tracking" FontSize="16" FontWeight="Medium" Margin="0,16,0,0" />
|
||||||
<ui:CardControl Margin="0,8,0,0">
|
<ui:CardControl Margin="0,8,0,0">
|
||||||
<ui:CardControl.Header>
|
<ui:CardControl.Header>
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
|
@ -82,7 +82,7 @@ namespace Bloxstrap.UI
|
|||||||
string serverLocation = await _activityWatcher!.GetServerLocation();
|
string serverLocation = await _activityWatcher!.GetServerLocation();
|
||||||
|
|
||||||
ShowAlert(
|
ShowAlert(
|
||||||
$"Connnected to {_activityWatcher.ActivityServerType.ToString().ToLower()} server",
|
$"Connected to {_activityWatcher.ActivityServerType.ToString().ToLower()} server",
|
||||||
$"Located at {serverLocation}\nClick for more information",
|
$"Located at {serverLocation}\nClick for more information",
|
||||||
10,
|
10,
|
||||||
(_, _) => _menuContainer?.ShowServerInformationWindow()
|
(_, _) => _menuContainer?.ShowServerInformationWindow()
|
||||||
@ -124,7 +124,7 @@ namespace Bloxstrap.UI
|
|||||||
if (_alertClickHandler == clickHandler)
|
if (_alertClickHandler == clickHandler)
|
||||||
_alertClickHandler = null;
|
_alertClickHandler = null;
|
||||||
else
|
else
|
||||||
App.Logger.WriteLine(LOG_IDENT, "Click handler has been overriden by another alert");
|
App.Logger.WriteLine(LOG_IDENT, "Click handler has been overridden by another alert");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,6 @@ namespace Bloxstrap.UI.ViewModels.ContextMenu
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CopyInstanceId() => Clipboard.SetText(InstanceId);
|
private void CopyInstanceId() => Clipboard.SetDataObject(InstanceId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,18 +81,12 @@
|
|||||||
set => App.Settings.Prop.CheckForUpdates = value;
|
set => App.Settings.Prop.CheckForUpdates = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<string> Channels => RobloxDeployment.SelectableChannels;
|
|
||||||
|
|
||||||
public string SelectedChannel
|
public string SelectedChannel
|
||||||
{
|
{
|
||||||
get => App.Settings.Prop.Channel;
|
get => App.Settings.Prop.Channel;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
value = value.Trim();
|
value = value.Trim();
|
||||||
|
|
||||||
if (String.IsNullOrEmpty(value))
|
|
||||||
value = RobloxDeployment.DefaultChannel;
|
|
||||||
|
|
||||||
Task.Run(() => LoadChannelDeployInfo(value));
|
Task.Run(() => LoadChannelDeployInfo(value));
|
||||||
App.Settings.Prop.Channel = value;
|
App.Settings.Prop.Channel = value;
|
||||||
}
|
}
|
||||||
|
@ -101,8 +101,11 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
|
|
||||||
foreach (var flag in version.Value)
|
foreach (var flag in version.Value)
|
||||||
{
|
{
|
||||||
if (App.FastFlags.GetPreset($"UI.Menu.Style.{flag.Key}") != flag.Value)
|
foreach (var presetFlag in FastFlagManager.PresetFlags.Where(x => x.Key.StartsWith($"UI.Menu.Style.{flag.Key}")))
|
||||||
flagsMatch = false;
|
{
|
||||||
|
if (App.FastFlags.GetValue(presetFlag.Value) != flag.Value)
|
||||||
|
flagsMatch = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flagsMatch)
|
if (flagsMatch)
|
||||||
@ -127,14 +130,6 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
set => App.FastFlags.SetPresetEnum("Rendering.Lighting", LightingModes[value], "True");
|
set => App.FastFlags.SetPresetEnum("Rendering.Lighting", LightingModes[value], "True");
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, string?> MSAAModes => FastFlagManager.MSAAModes;
|
|
||||||
|
|
||||||
public string SelectedMSAAMode
|
|
||||||
{
|
|
||||||
get => MSAAModes.First(x => x.Value == App.FastFlags.GetPreset("Rendering.MSAA")).Key ?? MSAAModes.First().Key;
|
|
||||||
set => App.FastFlags.SetPreset("Rendering.MSAA", MSAAModes[value]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool GuiHidingEnabled
|
public bool GuiHidingEnabled
|
||||||
{
|
{
|
||||||
get => App.FastFlags.GetPreset("UI.Hide") == "32380007";
|
get => App.FastFlags.GetPreset("UI.Hide") == "32380007";
|
||||||
|
@ -14,8 +14,6 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
public class MainWindowViewModel : NotifyPropertyChangedViewModel
|
public class MainWindowViewModel : NotifyPropertyChangedViewModel
|
||||||
{
|
{
|
||||||
private readonly Window _window;
|
private readonly Window _window;
|
||||||
private readonly IDialogService _dialogService;
|
|
||||||
private readonly string _originalBaseDirectory = App.BaseDirectory; // we need this to check if the basedirectory changes
|
|
||||||
|
|
||||||
public ICommand CloseWindowCommand => new RelayCommand(CloseWindow);
|
public ICommand CloseWindowCommand => new RelayCommand(CloseWindow);
|
||||||
public ICommand ConfirmSettingsCommand => new RelayCommand(ConfirmSettings);
|
public ICommand ConfirmSettingsCommand => new RelayCommand(ConfirmSettings);
|
||||||
@ -24,25 +22,31 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
public string ConfirmButtonText => App.IsFirstRun ? "Install" : "Save";
|
public string ConfirmButtonText => App.IsFirstRun ? "Install" : "Save";
|
||||||
public bool ConfirmButtonEnabled { get; set; } = true;
|
public bool ConfirmButtonEnabled { get; set; } = true;
|
||||||
|
|
||||||
public MainWindowViewModel(Window window, IDialogService dialogService)
|
public MainWindowViewModel(Window window)
|
||||||
{
|
{
|
||||||
_window = window;
|
_window = window;
|
||||||
_dialogService = dialogService;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CloseWindow() => _window.Close();
|
private void CloseWindow() => _window.Close();
|
||||||
|
|
||||||
private void ConfirmSettings()
|
private void ConfirmSettings()
|
||||||
{
|
{
|
||||||
|
if (!App.IsFirstRun)
|
||||||
|
{
|
||||||
|
App.ShouldSaveConfigs = true;
|
||||||
|
App.FastFlags.Save();
|
||||||
|
CloseWindow();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(App.BaseDirectory))
|
if (string.IsNullOrEmpty(App.BaseDirectory))
|
||||||
{
|
{
|
||||||
Controls.ShowMessageBox("You must set an install location", MessageBoxImage.Error);
|
Controls.ShowMessageBox("You must set an install location", MessageBoxImage.Error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldCheckInstallLocation = App.IsFirstRun || App.BaseDirectory != _originalBaseDirectory;
|
if (NavigationVisibility == Visibility.Visible)
|
||||||
|
|
||||||
if (shouldCheckInstallLocation && NavigationVisibility == Visibility.Visible)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -87,54 +91,45 @@ namespace Bloxstrap.UI.ViewModels.Menu
|
|||||||
else if (result == MessageBoxResult.Cancel)
|
else if (result == MessageBoxResult.Cancel)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
App.BaseDirectory.Length <= 3 || // prevent from installing to the root of a drive
|
||||||
|
App.BaseDirectory.StartsWith("\\\\") || // i actually haven't encountered anyone doing this and i dont even know if this is possible but this is just to be safe lmao
|
||||||
|
App.BaseDirectory.ToLowerInvariant().Contains("onedrive") || // prevent from installing to a onedrive folder
|
||||||
|
Directory.GetParent(App.BaseDirectory)!.ToString().ToLowerInvariant() == Paths.UserProfile.ToLowerInvariant() // prevent from installing to an essential user profile folder
|
||||||
|
)
|
||||||
|
{
|
||||||
|
Controls.ShowMessageBox(
|
||||||
|
$"{App.ProjectName} cannot be installed here. Please choose a different location, or resort to using the default location by clicking the reset button.",
|
||||||
|
MessageBoxImage.Error,
|
||||||
|
MessageBoxButton.OK
|
||||||
|
);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (App.IsFirstRun)
|
if (NavigationVisibility == Visibility.Visible)
|
||||||
{
|
{
|
||||||
if (NavigationVisibility == Visibility.Visible)
|
((INavigationWindow)_window).Navigate(typeof(PreInstallPage));
|
||||||
|
|
||||||
|
NavigationVisibility = Visibility.Collapsed;
|
||||||
|
OnPropertyChanged(nameof(NavigationVisibility));
|
||||||
|
|
||||||
|
ConfirmButtonEnabled = false;
|
||||||
|
OnPropertyChanged(nameof(ConfirmButtonEnabled));
|
||||||
|
|
||||||
|
Task.Run(async delegate
|
||||||
{
|
{
|
||||||
((INavigationWindow)_window).Navigate(typeof(PreInstallPage));
|
await Task.Delay(3000);
|
||||||
|
|
||||||
NavigationVisibility = Visibility.Collapsed;
|
ConfirmButtonEnabled = true;
|
||||||
OnPropertyChanged(nameof(NavigationVisibility));
|
|
||||||
|
|
||||||
ConfirmButtonEnabled = false;
|
|
||||||
OnPropertyChanged(nameof(ConfirmButtonEnabled));
|
OnPropertyChanged(nameof(ConfirmButtonEnabled));
|
||||||
|
});
|
||||||
Task.Run(async delegate
|
|
||||||
{
|
|
||||||
await Task.Delay(3000);
|
|
||||||
|
|
||||||
ConfirmButtonEnabled = true;
|
|
||||||
OnPropertyChanged(nameof(ConfirmButtonEnabled));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
App.IsSetupComplete = true;
|
|
||||||
CloseWindow();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
App.ShouldSaveConfigs = true;
|
App.IsSetupComplete = true;
|
||||||
App.FastFlags.Save();
|
|
||||||
|
|
||||||
if (shouldCheckInstallLocation)
|
|
||||||
{
|
|
||||||
App.Logger.WriteLine("MainWindowViewModel::ConfirmSettings", $"Changing install location from {_originalBaseDirectory} to {App.BaseDirectory}");
|
|
||||||
|
|
||||||
Controls.ShowMessageBox(
|
|
||||||
$"{App.ProjectName} will install to the new location you've set the next time it runs.",
|
|
||||||
MessageBoxImage.Information
|
|
||||||
);
|
|
||||||
|
|
||||||
using RegistryKey registryKey = Registry.CurrentUser.CreateSubKey($@"Software\{App.ProjectName}");
|
|
||||||
registryKey.SetValue("InstallLocation", App.BaseDirectory);
|
|
||||||
registryKey.SetValue("OldInstallLocation", _originalBaseDirectory);
|
|
||||||
Paths.Initialize(App.BaseDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseWindow();
|
CloseWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,15 @@
|
|||||||
|
|
||||||
public sealed class AsyncMutex : IAsyncDisposable
|
public sealed class AsyncMutex : IAsyncDisposable
|
||||||
{
|
{
|
||||||
|
private readonly bool _initiallyOwned;
|
||||||
private readonly string _name;
|
private readonly string _name;
|
||||||
private Task? _mutexTask;
|
private Task? _mutexTask;
|
||||||
private ManualResetEventSlim? _releaseEvent;
|
private ManualResetEventSlim? _releaseEvent;
|
||||||
private CancellationTokenSource? _cancellationTokenSource;
|
private CancellationTokenSource? _cancellationTokenSource;
|
||||||
|
|
||||||
public AsyncMutex(string name)
|
public AsyncMutex(bool initiallyOwned, string name)
|
||||||
{
|
{
|
||||||
|
_initiallyOwned = initiallyOwned;
|
||||||
_name = name;
|
_name = name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,7 +33,7 @@
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
CancellationToken cancellationToken = _cancellationTokenSource.Token;
|
CancellationToken cancellationToken = _cancellationTokenSource.Token;
|
||||||
using var mutex = new Mutex(false, _name);
|
using var mutex = new Mutex(_initiallyOwned, _name);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Wait for either the mutex to be acquired, or cancellation
|
// Wait for either the mutex to be acquired, or cancellation
|
||||||
|
Loading…
Reference in New Issue
Block a user