mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-06-23 23:00:23 -07:00
Compare commits
7 Commits
2376911253
...
eca47f686a
Author | SHA1 | Date | |
---|---|---|---|
|
eca47f686a | ||
|
893aecbdd1 | ||
|
d7e5912eb9 | ||
|
c78b04dce7 | ||
|
9700c61523 | ||
|
c9dabd6b4f | ||
|
9318813bdb |
@ -39,6 +39,8 @@
|
||||
<converters:StringFormatConverter x:Key="StringFormatConverter" />
|
||||
<converters:RangeConverter x:Key="RangeConverter" />
|
||||
<converters:EnumNameConverter x:Key="EnumNameConverter" />
|
||||
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
|
@ -45,8 +45,8 @@ namespace Bloxstrap
|
||||
private readonly FastZipEvents _fastZipEvents = new();
|
||||
private readonly CancellationTokenSource _cancelTokenSource = new();
|
||||
|
||||
private readonly IAppData AppData;
|
||||
private readonly LaunchMode _launchMode;
|
||||
private IAppData AppData = default!;
|
||||
private LaunchMode _launchMode;
|
||||
|
||||
private string _launchCommandLine = App.LaunchSettings.RobloxLaunchArgs;
|
||||
private string _latestVersionGuid = null!;
|
||||
@ -60,7 +60,7 @@ namespace Bloxstrap
|
||||
private long _totalDownloadedBytes = 0;
|
||||
private bool _packageExtractionSuccess = true;
|
||||
|
||||
private bool _mustUpgrade => String.IsNullOrEmpty(AppData.State.VersionGuid) || !File.Exists(AppData.ExecutablePath);
|
||||
private bool _mustUpgrade => App.LaunchSettings.ForceFlag.Active || String.IsNullOrEmpty(AppData.State.VersionGuid) || !File.Exists(AppData.ExecutablePath);
|
||||
private bool _noConnection = false;
|
||||
|
||||
private AsyncMutex? _mutex;
|
||||
@ -91,6 +91,11 @@ namespace Bloxstrap
|
||||
_fastZipEvents.DirectoryFailure += (_, e) => throw e.Exception;
|
||||
_fastZipEvents.ProcessFile += (_, e) => e.ContinueRunning = !_cancelTokenSource.IsCancellationRequested;
|
||||
|
||||
SetupAppData();
|
||||
}
|
||||
|
||||
private void SetupAppData()
|
||||
{
|
||||
AppData = IsStudioLaunch ? new RobloxStudioData() : new RobloxPlayerData();
|
||||
Deployment.BinaryType = AppData.BinaryType;
|
||||
}
|
||||
@ -288,12 +293,17 @@ namespace Bloxstrap
|
||||
using var key = Registry.CurrentUser.CreateSubKey($"SOFTWARE\\ROBLOX Corporation\\Environments\\{AppData.RegistryName}\\Channel");
|
||||
|
||||
var match = Regex.Match(
|
||||
App.LaunchSettings.RobloxLaunchArgs,
|
||||
"channel:([a-zA-Z0-9-_]+)",
|
||||
App.LaunchSettings.RobloxLaunchArgs,
|
||||
"channel:([a-zA-Z0-9-_]+)",
|
||||
RegexOptions.IgnoreCase | RegexOptions.CultureInvariant
|
||||
);
|
||||
|
||||
if (match.Groups.Count == 2)
|
||||
if (App.LaunchSettings.ChannelFlag.Active && !string.IsNullOrEmpty(App.LaunchSettings.ChannelFlag.Data))
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Channel set to {App.LaunchSettings.ChannelFlag.Data} from arguments");
|
||||
Deployment.Channel = App.LaunchSettings.ChannelFlag.Data.ToLowerInvariant();
|
||||
}
|
||||
else if (match.Groups.Count == 2)
|
||||
{
|
||||
Deployment.Channel = match.Groups[1].Value.ToLowerInvariant();
|
||||
}
|
||||
@ -310,29 +320,50 @@ namespace Bloxstrap
|
||||
if (!Deployment.IsDefaultChannel)
|
||||
App.SendStat("robloxChannel", Deployment.Channel);
|
||||
|
||||
ClientVersion clientVersion;
|
||||
|
||||
try
|
||||
if (!App.LaunchSettings.VersionFlag.Active || string.IsNullOrEmpty(App.LaunchSettings.VersionFlag.Data))
|
||||
{
|
||||
clientVersion = await Deployment.GetInfo();
|
||||
ClientVersion clientVersion;
|
||||
|
||||
try
|
||||
{
|
||||
clientVersion = await Deployment.GetInfo();
|
||||
}
|
||||
catch (InvalidChannelException ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Resetting channel from {Deployment.Channel} because {ex.StatusCode}");
|
||||
|
||||
Deployment.Channel = Deployment.DefaultChannel;
|
||||
clientVersion = await Deployment.GetInfo();
|
||||
}
|
||||
|
||||
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
|
||||
|
||||
_latestVersionGuid = clientVersion.VersionGuid;
|
||||
}
|
||||
catch (InvalidChannelException ex)
|
||||
else
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Resetting channel from {Deployment.Channel} because {ex.StatusCode}");
|
||||
|
||||
Deployment.Channel = Deployment.DefaultChannel;
|
||||
clientVersion = await Deployment.GetInfo();
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Version set to {App.LaunchSettings.VersionFlag.Data} from arguments");
|
||||
_latestVersionGuid = App.LaunchSettings.VersionFlag.Data;
|
||||
}
|
||||
|
||||
key.SetValueSafe("www.roblox.com", Deployment.IsDefaultChannel ? "" : Deployment.Channel);
|
||||
|
||||
_latestVersionGuid = clientVersion.VersionGuid;
|
||||
_latestVersionDirectory = Path.Combine(Paths.Versions, _latestVersionGuid);
|
||||
|
||||
string pkgManifestUrl = Deployment.GetLocation($"/{_latestVersionGuid}-rbxPkgManifest.txt");
|
||||
var pkgManifestData = await App.HttpClient.GetStringAsync(pkgManifestUrl);
|
||||
|
||||
_versionPackageManifest = new(pkgManifestData);
|
||||
|
||||
// this can happen if version is set through arguments
|
||||
if (_launchMode == LaunchMode.Unknown)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Identifying launch mode from package manifest");
|
||||
|
||||
bool isPlayer = _versionPackageManifest.Exists(x => x.Name == "RobloxApp.zip");
|
||||
App.Logger.WriteLine(LOG_IDENT, $"isPlayer: {isPlayer}");
|
||||
|
||||
_launchMode = isPlayer ? LaunchMode.Player : LaunchMode.Studio;
|
||||
SetupAppData(); // we need to set it up again
|
||||
}
|
||||
}
|
||||
|
||||
private void StartRoblox()
|
||||
@ -439,30 +470,32 @@ namespace Bloxstrap
|
||||
// launch custom integrations now
|
||||
foreach (var integration in App.Settings.Prop.CustomIntegrations)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
|
||||
if (!integration.SpecifyGame) {
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
|
||||
|
||||
int pid = 0;
|
||||
int pid = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
try
|
||||
{
|
||||
FileName = integration.Location,
|
||||
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
||||
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
||||
UseShellExecute = true
|
||||
})!;
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = integration.Location,
|
||||
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
||||
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
||||
UseShellExecute = true
|
||||
})!;
|
||||
|
||||
pid = process.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}'!");
|
||||
App.Logger.WriteLine(LOG_IDENT, ex.Message);
|
||||
}
|
||||
pid = process.Id;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}'!");
|
||||
App.Logger.WriteLine(LOG_IDENT, ex.Message);
|
||||
}
|
||||
|
||||
if (integration.AutoClose && pid != 0)
|
||||
autoclosePids.Add(pid);
|
||||
if (integration.AutoClose && pid != 0)
|
||||
autoclosePids.Add(pid);
|
||||
}
|
||||
}
|
||||
|
||||
if (App.Settings.Prop.EnableActivityTracking || App.LaunchSettings.TestModeFlag.Active || autoclosePids.Any())
|
||||
@ -930,20 +963,23 @@ namespace Bloxstrap
|
||||
allPackageHashes.AddRange(App.State.Prop.Player.PackageHashes.Values);
|
||||
allPackageHashes.AddRange(App.State.Prop.Studio.PackageHashes.Values);
|
||||
|
||||
foreach (string hash in cachedPackageHashes)
|
||||
if (!App.Settings.Prop.DebugDisableVersionPackageCleanup)
|
||||
{
|
||||
if (!allPackageHashes.Contains(hash))
|
||||
foreach (string hash in cachedPackageHashes)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Deleting unused package {hash}");
|
||||
|
||||
try
|
||||
if (!allPackageHashes.Contains(hash))
|
||||
{
|
||||
File.Delete(Path.Combine(Paths.Downloads, hash));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to delete {hash}!");
|
||||
App.Logger.WriteException(LOG_IDENT, ex);
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Deleting unused package {hash}");
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(Path.Combine(Paths.Downloads, hash));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to delete {hash}!");
|
||||
App.Logger.WriteException(LOG_IDENT, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,10 @@
|
||||
public enum LaunchMode
|
||||
{
|
||||
None,
|
||||
/// <summary>
|
||||
/// Launch mode will be determined inside the bootstrapper. Only works if the VersionFlag is set.
|
||||
/// </summary>
|
||||
Unknown,
|
||||
Player,
|
||||
Studio,
|
||||
StudioAuth
|
||||
|
100
Bloxstrap/Integrations/IntegrationWatcher.cs
Normal file
100
Bloxstrap/Integrations/IntegrationWatcher.cs
Normal file
@ -0,0 +1,100 @@
|
||||
namespace Bloxstrap.Integrations
|
||||
{
|
||||
public class IntegrationWatcher : IDisposable
|
||||
{
|
||||
private readonly ActivityWatcher _activityWatcher;
|
||||
private readonly Dictionary<int, CustomIntegration> _activeIntegrations = new();
|
||||
|
||||
public IntegrationWatcher(ActivityWatcher activityWatcher)
|
||||
{
|
||||
_activityWatcher = activityWatcher;
|
||||
|
||||
_activityWatcher.OnGameJoin += OnGameJoin;
|
||||
_activityWatcher.OnGameLeave += OnGameLeave;
|
||||
}
|
||||
|
||||
private void OnGameJoin(object? sender, EventArgs e)
|
||||
{
|
||||
if (!_activityWatcher.InGame)
|
||||
return;
|
||||
|
||||
long currentGameId = _activityWatcher.Data.PlaceId;
|
||||
|
||||
foreach (var integration in App.Settings.Prop.CustomIntegrations)
|
||||
{
|
||||
if (!integration.SpecifyGame || integration.GameID != currentGameId.ToString())
|
||||
continue;
|
||||
|
||||
LaunchIntegration(integration);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGameLeave(object? sender, EventArgs e)
|
||||
{
|
||||
foreach (var pid in _activeIntegrations.Keys.ToList())
|
||||
{
|
||||
var integration = _activeIntegrations[pid];
|
||||
if (integration.AutoCloseOnGame)
|
||||
{
|
||||
TerminateProcess(pid);
|
||||
_activeIntegrations.Remove(pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void LaunchIntegration(CustomIntegration integration)
|
||||
{
|
||||
const string LOG_IDENT = "IntegrationWatcher::LaunchIntegration";
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = integration.Location,
|
||||
Arguments = integration.LaunchArgs.Replace("\r\n", " "),
|
||||
WorkingDirectory = Path.GetDirectoryName(integration.Location),
|
||||
UseShellExecute = true
|
||||
});
|
||||
|
||||
if (process != null)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Integration '{integration.Name}' launched for game ID '{integration.GameID}' (PID {process.Id}).");
|
||||
_activeIntegrations[process.Id] = integration;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to launch integration '{integration.Name}': {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void TerminateProcess(int pid)
|
||||
{
|
||||
const string LOG_IDENT = "IntegrationWatcher::TerminateProcess";
|
||||
|
||||
try
|
||||
{
|
||||
var process = Process.GetProcessById(pid);
|
||||
process.Kill();
|
||||
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Terminated integration process (PID {pid}).");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Failed to terminate process (PID {pid}), likely already exited.");
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var pid in _activeIntegrations.Keys)
|
||||
{
|
||||
TerminateProcess(pid);
|
||||
}
|
||||
|
||||
_activeIntegrations.Clear();
|
||||
_activityWatcher.Dispose();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
@ -32,6 +32,12 @@ namespace Bloxstrap
|
||||
|
||||
public LaunchFlag StudioFlag { get; } = new("studio");
|
||||
|
||||
public LaunchFlag VersionFlag { get; } = new("version");
|
||||
|
||||
public LaunchFlag ChannelFlag { get; } = new("channel");
|
||||
|
||||
public LaunchFlag ForceFlag { get; } = new("force");
|
||||
|
||||
#if DEBUG
|
||||
public bool BypassUpdateCheck => true;
|
||||
#else
|
||||
@ -87,6 +93,13 @@ namespace Bloxstrap
|
||||
RobloxLaunchArgs = arg;
|
||||
startIdx = 1;
|
||||
}
|
||||
else if (arg.StartsWith("version-"))
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, "Got version argument");
|
||||
VersionFlag.Active = true;
|
||||
VersionFlag.Data = arg;
|
||||
startIdx = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// parse
|
||||
@ -108,6 +121,12 @@ namespace Bloxstrap
|
||||
continue;
|
||||
}
|
||||
|
||||
if (flag.Active)
|
||||
{
|
||||
App.Logger.WriteLine(LOG_IDENT, $"Tried to set {identifier} flag twice");
|
||||
continue;
|
||||
}
|
||||
|
||||
flag.Active = true;
|
||||
|
||||
if (i < Args.Length - 1 && Args[i+1] is string nextArg && !nextArg.StartsWith('-'))
|
||||
@ -122,6 +141,9 @@ namespace Bloxstrap
|
||||
}
|
||||
}
|
||||
|
||||
if (VersionFlag.Active)
|
||||
RobloxLaunchMode = LaunchMode.Unknown; // determine in bootstrapper
|
||||
|
||||
if (PlayerFlag.Active)
|
||||
ParsePlayer(PlayerFlag.Data);
|
||||
else if (StudioFlag.Active)
|
||||
|
@ -5,6 +5,9 @@
|
||||
public string Name { get; set; } = "";
|
||||
public string Location { get; set; } = "";
|
||||
public string LaunchArgs { get; set; } = "";
|
||||
public bool SpecifyGame { get; set; } = false;
|
||||
public string GameID { get; set; } = "";
|
||||
public bool AutoCloseOnGame { get; set; } = true;
|
||||
public bool AutoClose { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@ namespace Bloxstrap.Models.Persistable
|
||||
public bool UseFastFlagManager { get; set; } = true;
|
||||
public bool WPFSoftwareRender { get; set; } = false;
|
||||
public bool EnableAnalytics { get; set; } = true;
|
||||
public bool DebugDisableVersionPackageCleanup { get; set; } = false;
|
||||
public string? SelectedCustomTheme { get; set; } = null;
|
||||
|
||||
// integration configuration
|
||||
|
29
Bloxstrap/Resources/Strings.Designer.cs
generated
29
Bloxstrap/Resources/Strings.Designer.cs
generated
@ -3262,7 +3262,34 @@ namespace Bloxstrap.Resources {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.AppLocation", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Run on specific games.
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_Custom_SpecifyGame {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.SpecifyGame", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Game ID.
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_Custom_GameID {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.GameID", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Auto close when game closes.
|
||||
/// </summary>
|
||||
public static string Menu_Integrations_Custom_AutoCloseOnGame {
|
||||
get {
|
||||
return ResourceManager.GetString("Menu.Integrations.Custom.AutoCloseOnGame", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Auto close when Roblox closes.
|
||||
/// </summary>
|
||||
|
@ -689,6 +689,15 @@ Selecting 'No' will ignore this warning and continue installation.</value>
|
||||
<data name="Menu.Integrations.Custom.AppLocation" xml:space="preserve">
|
||||
<value>Application Location</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.SpecifyGame" xml:space="preserve">
|
||||
<value>Run on a specific game</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.GameID" xml:space="preserve">
|
||||
<value>Game ID</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.AutoCloseOnGame" xml:space="preserve">
|
||||
<value>Auto close when the game closes</value>
|
||||
</data>
|
||||
<data name="Menu.Integrations.Custom.AutoClose" xml:space="preserve">
|
||||
<value>Auto close when Roblox closes</value>
|
||||
</data>
|
||||
|
21
Bloxstrap/UI/Converters/BooleanToVisibilityConverter.cs
Normal file
21
Bloxstrap/UI/Converters/BooleanToVisibilityConverter.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Bloxstrap.UI.Converters
|
||||
{
|
||||
public class BooleanToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
return boolValue ? Visibility.Visible : Visibility.Collapsed;
|
||||
|
||||
return Visibility.Collapsed;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Bloxstrap.UI.Converters
|
||||
{
|
||||
public class InverseBooleanToVisibilityConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is bool boolValue)
|
||||
return boolValue ? Visibility.Collapsed : Visibility.Visible;
|
||||
|
||||
return Visibility.Visible;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
@ -110,6 +110,7 @@
|
||||
<controls:MarkdownTextBlock MarkdownText="[Redusofficial](https://github.com/Redusofficial)" />
|
||||
<controls:MarkdownTextBlock MarkdownText="[srthMD](https://github.com/srthMD)" />
|
||||
<controls:MarkdownTextBlock MarkdownText="[axellse](https://github.com/axellse)" />
|
||||
<controls:MarkdownTextBlock MarkdownText="[CubesterYT](https://github.com/CubesterYT)" />
|
||||
</StackPanel>
|
||||
</controls:Expander>
|
||||
|
||||
|
@ -68,7 +68,7 @@
|
||||
|
||||
<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">
|
||||
<Grid Margin="0,8,0,0" MinHeight="325">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
@ -109,7 +109,11 @@
|
||||
</Grid>
|
||||
<TextBlock Margin="0,8,0,0" Text="{x:Static resources:Strings.Menu_Integrations_Custom_LaunchArgs}" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
||||
<ui:TextBox Margin="0,4,0,0" PlaceholderText="{Binding Source='/k echo {0}', Converter={StaticResource StringFormatConverter}, ConverterParameter={x:Static resources:Strings.Menu_Integrations_Custom_LaunchArgs_Placeholder}}" Text="{Binding SelectedCustomIntegration.LaunchArgs}" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_AutoClose}" IsChecked="{Binding SelectedCustomIntegration.AutoClose}" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_SpecifyGame}" IsChecked="{Binding SelectedCustomIntegration.SpecifyGame, UpdateSourceTrigger=PropertyChanged}" />
|
||||
<TextBlock Margin="0,8,0,0" Text="{x:Static resources:Strings.Menu_Integrations_Custom_GameID}" Foreground="{DynamicResource TextFillColorSecondaryBrush}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<ui:TextBox Margin="0,4,0,0" PlaceholderText="1818" Text="{Binding SelectedCustomIntegration.GameID}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_AutoCloseOnGame}" IsChecked="{Binding SelectedCustomIntegration.AutoCloseOnGame, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource BooleanToVisibilityConverter}}" />
|
||||
<CheckBox Margin="0,8,0,0" Content="{x:Static resources:Strings.Menu_Integrations_Custom_AutoClose}" IsChecked="{Binding SelectedCustomIntegration.AutoClose, UpdateSourceTrigger=PropertyChanged}" Visibility="{Binding SelectedCustomIntegration.SpecifyGame, Converter={StaticResource InverseBooleanToVisibilityConverter}}" />
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Row="0" Grid.RowSpan="2" Grid.Column="1" Text="{x:Static resources:Strings.Menu_Integrations_Custom_NoneSelected}" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center">
|
||||
<TextBlock.Style>
|
||||
|
@ -9,13 +9,15 @@ namespace Bloxstrap
|
||||
private readonly InterProcessLock _lock = new("Watcher");
|
||||
|
||||
private readonly WatcherData? _watcherData;
|
||||
|
||||
|
||||
private readonly NotifyIconWrapper? _notifyIcon;
|
||||
|
||||
public readonly ActivityWatcher? ActivityWatcher;
|
||||
|
||||
public readonly DiscordRichPresence? RichPresence;
|
||||
|
||||
public readonly IntegrationWatcher? IntegrationWatcher;
|
||||
|
||||
public Watcher()
|
||||
{
|
||||
const string LOG_IDENT = "Watcher";
|
||||
@ -63,6 +65,8 @@ namespace Bloxstrap
|
||||
|
||||
if (App.Settings.Prop.UseDiscordRichPresence)
|
||||
RichPresence = new(ActivityWatcher);
|
||||
|
||||
IntegrationWatcher = new IntegrationWatcher(ActivityWatcher);
|
||||
}
|
||||
|
||||
_notifyIcon = new(this);
|
||||
@ -122,6 +126,7 @@ namespace Bloxstrap
|
||||
{
|
||||
App.Logger.WriteLine("Watcher::Dispose", "Disposing Watcher");
|
||||
|
||||
IntegrationWatcher?.Dispose();
|
||||
_notifyIcon?.Dispose();
|
||||
RichPresence?.Dispose();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user