mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-06-23 23:00:23 -07:00
Compare commits
11 Commits
69bd1bc080
...
91721601bb
Author | SHA1 | Date | |
---|---|---|---|
|
91721601bb | ||
|
bae578f94d | ||
|
3f02c6ba93 | ||
|
afc3200b68 | ||
|
d244f42b49 | ||
|
49fd8eb2d2 | ||
|
d0f1b9de22 | ||
|
f0eb2eb745 | ||
|
b54e44aa58 | ||
|
3e9e0fba16 | ||
|
7be311dda6 |
@ -471,21 +471,48 @@ namespace Bloxstrap
|
||||
}
|
||||
}
|
||||
|
||||
private static void LaunchMultiInstanceWatcher()
|
||||
{
|
||||
const string LOG_IDENT = "Bootstrapper::LaunchMultiInstanceWatcher";
|
||||
|
||||
if (Utilities.DoesMutexExist("ROBLOX_singletonMutex"))
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Roblox singleton mutex already exists");
|
||||
return;
|
||||
}
|
||||
|
||||
using EventWaitHandle initEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "Bloxstrap-MultiInstanceWatcherInitialisationFinished");
|
||||
Process.Start(Paths.Process, "-multiinstancewatcher");
|
||||
|
||||
bool initSuccess = initEventHandle.WaitOne(TimeSpan.FromSeconds(2));
|
||||
if (initSuccess)
|
||||
App.Logger.WriteLine(LOG_IDENT, "Initialisation finished signalled, continuing.");
|
||||
else
|
||||
App.Logger.WriteLine(LOG_IDENT, "Did not receive the initialisation finished signal, continuing.");
|
||||
}
|
||||
|
||||
private void StartRoblox()
|
||||
{
|
||||
const string LOG_IDENT = "Bootstrapper::StartRoblox";
|
||||
|
||||
SetStatus(Strings.Bootstrapper_Status_Starting);
|
||||
|
||||
if (_launchMode == LaunchMode.Player && App.Settings.Prop.ForceRobloxLanguage)
|
||||
if (_launchMode == LaunchMode.Player)
|
||||
{
|
||||
var match = Regex.Match(_launchCommandLine, "gameLocale:([a-z_]+)", RegexOptions.CultureInvariant);
|
||||
// this needs to be done before roblox launches
|
||||
if (App.Settings.Prop.MultiInstanceLaunching)
|
||||
LaunchMultiInstanceWatcher();
|
||||
|
||||
if (match.Groups.Count == 2)
|
||||
_launchCommandLine = _launchCommandLine.Replace(
|
||||
"robloxLocale:en_us",
|
||||
$"robloxLocale:{match.Groups[1].Value}",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
if (App.Settings.Prop.ForceRobloxLanguage)
|
||||
{
|
||||
var match = Regex.Match(_launchCommandLine, "gameLocale:([a-z_]+)", RegexOptions.CultureInvariant);
|
||||
|
||||
if (match.Groups.Count == 2)
|
||||
_launchCommandLine = _launchCommandLine.Replace(
|
||||
"robloxLocale:en_us",
|
||||
$"robloxLocale:{match.Groups[1].Value}",
|
||||
StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
}
|
||||
|
||||
var startInfo = new ProcessStartInfo()
|
||||
@ -1109,6 +1136,8 @@ namespace Bloxstrap
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Registered as {totalSize} KB");
|
||||
|
||||
App.State.Prop.ForceReinstall = false;
|
||||
|
||||
App.State.Save();
|
||||
App.RobloxState.Save();
|
||||
|
||||
|
@ -9,7 +9,7 @@ namespace Bloxstrap
|
||||
/// Should this version automatically open the release notes page?
|
||||
/// Recommended for major updates only.
|
||||
/// </summary>
|
||||
private const bool OpenReleaseNotes = false;
|
||||
private const bool OpenReleaseNotes = true;
|
||||
|
||||
private static string DesktopShortcut => Path.Combine(Paths.Desktop, $"{App.ProjectName}.lnk");
|
||||
|
||||
|
@ -59,6 +59,11 @@ namespace Bloxstrap
|
||||
App.Logger.WriteLine(LOG_IDENT, "Opening watcher");
|
||||
LaunchWatcher();
|
||||
}
|
||||
else if (App.LaunchSettings.MultiInstanceWatcherFlag.Active)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Opening multi-instance watcher");
|
||||
LaunchMultiInstanceWatcher();
|
||||
}
|
||||
else if (App.LaunchSettings.BackgroundUpdaterFlag.Active)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Opening background updater");
|
||||
@ -223,7 +228,7 @@ namespace Bloxstrap
|
||||
App.Terminate(ErrorCode.ERROR_FILE_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (App.Settings.Prop.ConfirmLaunches && Mutex.TryOpenExisting("ROBLOX_singletonMutex", out var _))
|
||||
if (App.Settings.Prop.ConfirmLaunches && Mutex.TryOpenExisting("ROBLOX_singletonMutex", out var _) && !App.Settings.Prop.MultiInstanceLaunching)
|
||||
{
|
||||
// this currently doesn't work very well since it relies on checking the existence of the singleton mutex
|
||||
// which often hangs around for a few seconds after the window closes
|
||||
@ -302,6 +307,28 @@ namespace Bloxstrap
|
||||
});
|
||||
}
|
||||
|
||||
public static void LaunchMultiInstanceWatcher()
|
||||
{
|
||||
const string LOG_IDENT = "LaunchHandler::LaunchMultiInstanceWatcher";
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, "Starting multi-instance watcher");
|
||||
|
||||
Task.Run(MultiInstanceWatcher.Run).ContinueWith(t =>
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Multi instance watcher task has finished");
|
||||
|
||||
if (t.IsFaulted)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "An exception occurred when running the multi-instance watcher");
|
||||
|
||||
if (t.Exception is not null)
|
||||
App.FinalizeExceptionHandling(t.Exception);
|
||||
}
|
||||
|
||||
App.Terminate();
|
||||
});
|
||||
}
|
||||
|
||||
public static void LaunchBackgroundUpdater()
|
||||
{
|
||||
const string LOG_IDENT = "LaunchHandler::LaunchBackgroundUpdater";
|
||||
|
@ -12,33 +12,35 @@ namespace Bloxstrap
|
||||
{
|
||||
public class LaunchSettings
|
||||
{
|
||||
public LaunchFlag MenuFlag { get; } = new("preferences,menu,settings");
|
||||
public LaunchFlag MenuFlag { get; } = new("preferences,menu,settings");
|
||||
|
||||
public LaunchFlag WatcherFlag { get; } = new("watcher");
|
||||
public LaunchFlag WatcherFlag { get; } = new("watcher");
|
||||
|
||||
public LaunchFlag BackgroundUpdaterFlag { get; } = new("backgroundupdater");
|
||||
public LaunchFlag MultiInstanceWatcherFlag { get; } = new("multiinstancewatcher");
|
||||
|
||||
public LaunchFlag QuietFlag { get; } = new("quiet");
|
||||
public LaunchFlag BackgroundUpdaterFlag { get; } = new("backgroundupdater");
|
||||
|
||||
public LaunchFlag UninstallFlag { get; } = new("uninstall");
|
||||
public LaunchFlag QuietFlag { get; } = new("quiet");
|
||||
|
||||
public LaunchFlag NoLaunchFlag { get; } = new("nolaunch");
|
||||
public LaunchFlag UninstallFlag { get; } = new("uninstall");
|
||||
|
||||
public LaunchFlag NoLaunchFlag { get; } = new("nolaunch");
|
||||
|
||||
public LaunchFlag TestModeFlag { get; } = new("testmode");
|
||||
public LaunchFlag TestModeFlag { get; } = new("testmode");
|
||||
|
||||
public LaunchFlag NoGPUFlag { get; } = new("nogpu");
|
||||
public LaunchFlag NoGPUFlag { get; } = new("nogpu");
|
||||
|
||||
public LaunchFlag UpgradeFlag { get; } = new("upgrade");
|
||||
public LaunchFlag UpgradeFlag { get; } = new("upgrade");
|
||||
|
||||
public LaunchFlag PlayerFlag { get; } = new("player");
|
||||
public LaunchFlag PlayerFlag { get; } = new("player");
|
||||
|
||||
public LaunchFlag StudioFlag { get; } = new("studio");
|
||||
public LaunchFlag StudioFlag { get; } = new("studio");
|
||||
|
||||
public LaunchFlag VersionFlag { get; } = new("version");
|
||||
public LaunchFlag VersionFlag { get; } = new("version");
|
||||
|
||||
public LaunchFlag ChannelFlag { get; } = new("channel");
|
||||
public LaunchFlag ChannelFlag { get; } = new("channel");
|
||||
|
||||
public LaunchFlag ForceFlag { get; } = new("force");
|
||||
public LaunchFlag ForceFlag { get; } = new("force");
|
||||
|
||||
#if DEBUG
|
||||
public bool BypassUpdateCheck => true;
|
||||
@ -55,11 +57,9 @@ namespace Bloxstrap
|
||||
/// </summary>
|
||||
public string[] Args { get; private set; }
|
||||
|
||||
private readonly Dictionary<string, LaunchFlag> _flagMap = new();
|
||||
|
||||
public LaunchSettings(string[] args)
|
||||
{
|
||||
const string LOG_IDENT = "LaunchSettings";
|
||||
const string LOG_IDENT = "LaunchSettings::LaunchSettings";
|
||||
|
||||
#if DEBUG
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Launched with arguments: {string.Join(' ', args)}");
|
||||
@ -67,6 +67,8 @@ namespace Bloxstrap
|
||||
|
||||
Args = args;
|
||||
|
||||
Dictionary<string, LaunchFlag> flagMap = new();
|
||||
|
||||
// build flag map
|
||||
foreach (var prop in this.GetType().GetProperties())
|
||||
{
|
||||
@ -77,7 +79,7 @@ namespace Bloxstrap
|
||||
continue;
|
||||
|
||||
foreach (string identifier in flag.Identifiers.Split(','))
|
||||
_flagMap.Add(identifier, flag);
|
||||
flagMap.Add(identifier, flag);
|
||||
}
|
||||
|
||||
int startIdx = 0;
|
||||
@ -117,7 +119,7 @@ namespace Bloxstrap
|
||||
|
||||
string identifier = arg[1..];
|
||||
|
||||
if (!_flagMap.TryGetValue(identifier, out LaunchFlag? flag) || flag is null)
|
||||
if (!flagMap.TryGetValue(identifier, out LaunchFlag? flag) || flag is null)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Unknown argument: {identifier}");
|
||||
continue;
|
||||
|
@ -11,6 +11,7 @@ namespace Bloxstrap.Models.Persistable
|
||||
public string BootstrapperIconCustomLocation { get; set; } = "";
|
||||
public Theme Theme { get; set; } = Theme.Default;
|
||||
public bool CheckForUpdates { get; set; } = true;
|
||||
public bool MultiInstanceLaunching { get; set; } = false;
|
||||
public bool ConfirmLaunches { get; set; } = false;
|
||||
public string Locale { get; set; } = "nil";
|
||||
public bool ForceRobloxLanguage { get; set; } = false;
|
||||
|
68
Bloxstrap/MultiInstanceWatcher.cs
Normal file
68
Bloxstrap/MultiInstanceWatcher.cs
Normal file
@ -0,0 +1,68 @@
|
||||
namespace Bloxstrap
|
||||
{
|
||||
internal static class MultiInstanceWatcher
|
||||
{
|
||||
private static int GetOpenProcessesCount()
|
||||
{
|
||||
const string LOG_IDENT = "MultiInstanceWatcher::GetOpenProcessesCount";
|
||||
|
||||
try
|
||||
{
|
||||
// prevent any possible race conditions by checking for bloxstrap processes too
|
||||
int count = Process.GetProcesses().Count(x => x.ProcessName is "RobloxPlayerBeta" or "Bloxstrap");
|
||||
count -= 1; // ignore the current process
|
||||
return count;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// everything process related can error at any time
|
||||
App.Logger.WriteException(LOG_IDENT, ex);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
private static void FireInitialisedEvent()
|
||||
{
|
||||
using EventWaitHandle initEventHandle = new EventWaitHandle(false, EventResetMode.AutoReset, "Bloxstrap-MultiInstanceWatcherInitialisationFinished");
|
||||
initEventHandle.Set();
|
||||
}
|
||||
|
||||
public static void Run()
|
||||
{
|
||||
const string LOG_IDENT = "MultiInstanceWatcher::Run";
|
||||
|
||||
// try to get the mutex
|
||||
bool acquiredMutex;
|
||||
using Mutex mutex = new Mutex(false, "ROBLOX_singletonMutex");
|
||||
try
|
||||
{
|
||||
acquiredMutex = mutex.WaitOne(0);
|
||||
}
|
||||
catch (AbandonedMutexException)
|
||||
{
|
||||
acquiredMutex = true;
|
||||
}
|
||||
|
||||
if (!acquiredMutex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Client singleton mutex is already acquired");
|
||||
FireInitialisedEvent();
|
||||
return;
|
||||
}
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, "Acquired mutex!");
|
||||
FireInitialisedEvent();
|
||||
|
||||
// watch for alive processes
|
||||
int count;
|
||||
do
|
||||
{
|
||||
Thread.Sleep(5000);
|
||||
count = GetOpenProcessesCount();
|
||||
}
|
||||
while (count == -1 || count > 0); // redo if -1 (one of the Process apis failed)
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, "All Roblox related processes have closed, exiting!");
|
||||
}
|
||||
}
|
||||
}
|
@ -26,7 +26,8 @@
|
||||
|
||||
public static string Application { get; private set; } = "";
|
||||
|
||||
public static string CustomFont => Path.Combine(Modifications, "content\\fonts\\CustomFont.ttf");
|
||||
public static string Fonts => Path.Combine("content\\fonts");
|
||||
public static string CustomFont => Path.Combine(Fonts, "CustomFont.ttf");
|
||||
|
||||
public static bool Initialized => !String.IsNullOrEmpty(Base);
|
||||
|
||||
|
18
Bloxstrap/Resources/Strings.Designer.cs
generated
18
Bloxstrap/Resources/Strings.Designer.cs
generated
@ -3425,6 +3425,24 @@ namespace Bloxstrap.Resources {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Allows for having more than one Roblox game client instance open simultaneously..
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_MultiInstanceLaunching_Description {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.MultiInstanceLaunching.Description", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Allow multi-instance launching.
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_MultiInstanceLaunching_Title {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.MultiInstanceLaunching.Title", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to When in-game, you'll be able to see where your server is located via [ipinfo.io]({0})..
|
||||
/// </summary>
|
||||
|
@ -1487,4 +1487,10 @@ Defaulting to {1}.</value>
|
||||
<value>Custom Theme {0}</value>
|
||||
<comment>{0} is a string (e.g. '1', '1-1234')</comment>
|
||||
</data>
|
||||
<data name="Menu.Integrations.MultiInstanceLaunching.Title" xml:space="preserve">
|
||||
<value>Allow multi-instance launching</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.MultiInstanceLaunching.Description" xml:space="preserve">
|
||||
<value>Allows for having more than one Roblox game client instance open simultaneously.</value>
|
||||
</data>
|
||||
</root>
|
@ -66,6 +66,14 @@
|
||||
<ui:ToggleSwitch IsChecked="{Binding DiscordAccountOnProfile, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<TextBlock Text="{x:Static resources:Strings.Common_Miscellaneous}" FontSize="20" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
|
||||
<controls:OptionControl
|
||||
Header="{x:Static resources:Strings.Menu_Integrations_MultiInstanceLaunching_Title}"
|
||||
Description="{x:Static resources:Strings.Menu_Integrations_MultiInstanceLaunching_Description}">
|
||||
<ui:ToggleSwitch IsChecked="{Binding MultiInstanceLaunchingEnabled, Mode=TwoWay}" />
|
||||
</controls:OptionControl>
|
||||
|
||||
<TextBlock Text="{x:Static resources:Strings.Menu_Integrations_Custom_Title}" FontSize="20" FontWeight="Medium" Margin="0,16,0,0" />
|
||||
<TextBlock Text="{x:Static resources:Strings.Menu_Integrations_Custom_Description}" TextWrapping="Wrap" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
<Grid Margin="0,8,0,0">
|
||||
|
@ -99,7 +99,7 @@
|
||||
Description="{x:Static resources:Strings.Menu_Mods_Misc_CustomFont_Description}">
|
||||
<StackPanel>
|
||||
<ui:Button Icon="DocumentAdd16" Content="{x:Static resources:Strings.Menu_Mods_Misc_CustomFont_Choose}" Command="{Binding ManageCustomFontCommand}" Visibility="{Binding ChooseCustomFontVisibility, Mode=OneWay}" />
|
||||
<ui:Button Icon="Delete16" Content="{x:Static resources:Strings.Menu_Mods_Misc_CustomFont_Remove}" Appearance="Danger" Command="{Binding ManageCustomFontCommand}" Visibility="{Binding DeleteCustomFontVisibility, Mode=OneWay}" />
|
||||
<ui:Button Icon="Delete16" FontFamily="{Binding DeleteCustomFontFontFamily}" Content="{x:Static resources:Strings.Menu_Mods_Misc_CustomFont_Remove}" Appearance="Danger" Command="{Binding ManageCustomFontCommand}" Visibility="{Binding DeleteCustomFontVisibility, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
</controls:OptionControl>
|
||||
</StackPanel>
|
||||
|
@ -194,11 +194,47 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
||||
|
||||
private void RenameCustomTheme()
|
||||
{
|
||||
if (SelectedCustomTheme is null)
|
||||
const string LOG_IDENT = "AppearanceViewModel::RenameCustomTheme";
|
||||
|
||||
if (SelectedCustomTheme is null || SelectedCustomTheme == SelectedCustomThemeName)
|
||||
return;
|
||||
|
||||
if (SelectedCustomTheme == SelectedCustomThemeName)
|
||||
if (string.IsNullOrEmpty(SelectedCustomThemeName))
|
||||
{
|
||||
Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameEmpty, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
var validationResult = PathValidator.IsFileNameValid(SelectedCustomThemeName);
|
||||
|
||||
if (validationResult != PathValidator.ValidationResult.Ok)
|
||||
{
|
||||
switch (validationResult)
|
||||
{
|
||||
case PathValidator.ValidationResult.IllegalCharacter:
|
||||
Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameIllegalCharacters, MessageBoxImage.Error);
|
||||
break;
|
||||
case PathValidator.ValidationResult.ReservedFileName:
|
||||
Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameReserved, MessageBoxImage.Error);
|
||||
break;
|
||||
default:
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Got unhandled PathValidator::ValidationResult {validationResult}");
|
||||
Debug.Assert(false);
|
||||
|
||||
Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_Unknown, MessageBoxImage.Error);
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// better to check for the file instead of the directory so broken themes can be overwritten
|
||||
string path = Path.Combine(Paths.CustomThemes, SelectedCustomThemeName, "Theme.xml");
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Frontend.ShowMessageBox(Strings.CustomTheme_Add_Errors_NameTaken, MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
@ -206,7 +242,7 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteException("AppearanceViewModel::RenameCustomTheme", ex);
|
||||
App.Logger.WriteException(LOG_IDENT, ex);
|
||||
Frontend.ShowMessageBox(string.Format(Strings.Menu_Appearance_CustomThemes_RenameFailed, SelectedCustomTheme, ex.Message), MessageBoxImage.Error);
|
||||
return;
|
||||
}
|
||||
|
@ -125,6 +125,12 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
||||
set => App.Settings.Prop.UseDisableAppPatch = value;
|
||||
}
|
||||
|
||||
public bool MultiInstanceLaunchingEnabled
|
||||
{
|
||||
get => App.Settings.Prop.MultiInstanceLaunching;
|
||||
set => App.Settings.Prop.MultiInstanceLaunching = value;
|
||||
}
|
||||
|
||||
public ObservableCollection<CustomIntegration> CustomIntegrations
|
||||
{
|
||||
get => App.Settings.Prop.CustomIntegrations;
|
||||
|
@ -9,8 +9,10 @@ using Windows.Win32.Foundation;
|
||||
|
||||
using CommunityToolkit.Mvvm.Input;
|
||||
|
||||
using Bloxstrap.Models.SettingTasks;
|
||||
using Bloxstrap.AppData;
|
||||
using System.Drawing.Text;
|
||||
using Wpf.Ui.Controls;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Bloxstrap.UI.ViewModels.Settings
|
||||
{
|
||||
@ -52,9 +54,12 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
||||
|
||||
TextFontTask.NewState = dialog.FileName;
|
||||
}
|
||||
|
||||
|
||||
OnPropertyChanged(nameof(ChooseCustomFontVisibility));
|
||||
OnPropertyChanged(nameof(DeleteCustomFontVisibility));
|
||||
OnPropertyChanged(nameof(CustomFontName));
|
||||
OnPropertyChanged(nameof(DeleteCustomFontFontFamily));
|
||||
}
|
||||
|
||||
public ICommand OpenModsFolderCommand => new RelayCommand(OpenModsFolder);
|
||||
@ -63,6 +68,18 @@ namespace Bloxstrap.UI.ViewModels.Settings
|
||||
|
||||
public Visibility DeleteCustomFontVisibility => !String.IsNullOrEmpty(TextFontTask.NewState) ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
public System.Windows.Media.FontFamily DeleteCustomFontFontFamily => new System.Windows.Media.FontFamily($"{TextFontTask.NewState}#{CustomFontName}");
|
||||
|
||||
public string CustomFontName
|
||||
{
|
||||
get
|
||||
{
|
||||
var families = Fonts.GetFontFamilies(TextFontTask.NewState);
|
||||
var first = families.ElementAt(0);
|
||||
return first.ToString().Split("#").ElementAt(first.ToString().Split("#").Count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
public ICommand ManageCustomFontCommand => new RelayCommand(ManageCustomFont);
|
||||
|
||||
public ICommand OpenCompatSettingsCommand => new RelayCommand(OpenCompatSettings);
|
||||
|
@ -28,21 +28,21 @@ namespace Bloxstrap
|
||||
|
||||
string? watcherDataArg = App.LaunchSettings.WatcherFlag.Data;
|
||||
|
||||
#if DEBUG
|
||||
if (String.IsNullOrEmpty(watcherDataArg))
|
||||
{
|
||||
#if DEBUG
|
||||
string path = new RobloxPlayerData().ExecutablePath;
|
||||
using var gameClientProcess = Process.Start(path);
|
||||
|
||||
_watcherData = new() { ProcessId = gameClientProcess.Id };
|
||||
}
|
||||
#else
|
||||
if (String.IsNullOrEmpty(watcherDataArg))
|
||||
throw new Exception("Watcher data not specified");
|
||||
#endif
|
||||
|
||||
if (!String.IsNullOrEmpty(watcherDataArg))
|
||||
}
|
||||
else
|
||||
{
|
||||
_watcherData = JsonSerializer.Deserialize<WatcherData>(Encoding.UTF8.GetString(Convert.FromBase64String(watcherDataArg)));
|
||||
}
|
||||
|
||||
if (_watcherData is null)
|
||||
throw new Exception("Watcher data is invalid");
|
||||
|
2
wpfui
2
wpfui
@ -1 +1 @@
|
||||
Subproject commit dca423b724ec24bd3377da3a27f4055ae317b50a
|
||||
Subproject commit f710123e72d9dcc8d09fccc4e2a783cc5cf5e652
|
Loading…
Reference in New Issue
Block a user