mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-21 10:01:27 -07:00
Merge d7e5912eb9
into 1f21e8ce0b
This commit is contained in:
commit
d220f2c46c
@ -39,6 +39,8 @@
|
|||||||
<converters:StringFormatConverter x:Key="StringFormatConverter" />
|
<converters:StringFormatConverter x:Key="StringFormatConverter" />
|
||||||
<converters:RangeConverter x:Key="RangeConverter" />
|
<converters:RangeConverter x:Key="RangeConverter" />
|
||||||
<converters:EnumNameConverter x:Key="EnumNameConverter" />
|
<converters:EnumNameConverter x:Key="EnumNameConverter" />
|
||||||
|
<converters:BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
|
||||||
|
<converters:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter" />
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</Application.Resources>
|
</Application.Resources>
|
||||||
</Application>
|
</Application>
|
||||||
|
@ -605,6 +605,7 @@ namespace Bloxstrap
|
|||||||
// launch custom integrations now
|
// launch custom integrations now
|
||||||
foreach (var integration in App.Settings.Prop.CustomIntegrations)
|
foreach (var integration in App.Settings.Prop.CustomIntegrations)
|
||||||
{
|
{
|
||||||
|
if (!integration.SpecifyGame) {
|
||||||
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
|
App.Logger.WriteLine(LOG_IDENT, $"Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})");
|
||||||
|
|
||||||
int pid = 0;
|
int pid = 0;
|
||||||
@ -630,6 +631,7 @@ namespace Bloxstrap
|
|||||||
if (integration.AutoClose && pid != 0)
|
if (integration.AutoClose && pid != 0)
|
||||||
autoclosePids.Add(pid);
|
autoclosePids.Add(pid);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (App.Settings.Prop.EnableActivityTracking || App.LaunchSettings.TestModeFlag.Active || autoclosePids.Any())
|
if (App.Settings.Prop.EnableActivityTracking || App.LaunchSettings.TestModeFlag.Active || autoclosePids.Any())
|
||||||
{
|
{
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,6 +5,9 @@
|
|||||||
public string Name { get; set; } = "";
|
public string Name { get; set; } = "";
|
||||||
public string Location { get; set; } = "";
|
public string Location { get; set; } = "";
|
||||||
public string LaunchArgs { 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;
|
public bool AutoClose { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
27
Bloxstrap/Resources/Strings.Designer.cs
generated
27
Bloxstrap/Resources/Strings.Designer.cs
generated
@ -3335,6 +3335,33 @@ namespace Bloxstrap.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <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>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Auto close when Roblox closes.
|
/// Looks up a localized string similar to Auto close when Roblox closes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -689,6 +689,15 @@ Selecting 'No' will ignore this warning and continue installation.</value>
|
|||||||
<data name="Menu.Integrations.Custom.AppLocation" xml:space="preserve">
|
<data name="Menu.Integrations.Custom.AppLocation" xml:space="preserve">
|
||||||
<value>Application Location</value>
|
<value>Application Location</value>
|
||||||
</data>
|
</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">
|
<data name="Menu.Integrations.Custom.AutoClose" xml:space="preserve">
|
||||||
<value>Auto close when Roblox closes</value>
|
<value>Auto close when Roblox closes</value>
|
||||||
</data>
|
</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="[Redusofficial](https://github.com/Redusofficial)" />
|
||||||
<controls:MarkdownTextBlock MarkdownText="[srthMD](https://github.com/srthMD)" />
|
<controls:MarkdownTextBlock MarkdownText="[srthMD](https://github.com/srthMD)" />
|
||||||
<controls:MarkdownTextBlock MarkdownText="[axellse](https://github.com/axellse)" />
|
<controls:MarkdownTextBlock MarkdownText="[axellse](https://github.com/axellse)" />
|
||||||
|
<controls:MarkdownTextBlock MarkdownText="[CubesterYT](https://github.com/CubesterYT)" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</controls:Expander>
|
</controls:Expander>
|
||||||
|
|
||||||
|
@ -76,7 +76,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_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}" />
|
<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>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
@ -117,7 +117,11 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
<TextBlock Margin="0,8,0,0" Text="{x:Static resources:Strings.Menu_Integrations_Custom_LaunchArgs}" Foreground="{DynamicResource TextFillColorSecondaryBrush}" />
|
<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" />
|
<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>
|
</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 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>
|
<TextBlock.Style>
|
||||||
|
@ -16,6 +16,8 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
public readonly DiscordRichPresence? RichPresence;
|
public readonly DiscordRichPresence? RichPresence;
|
||||||
|
|
||||||
|
public readonly IntegrationWatcher? IntegrationWatcher;
|
||||||
|
|
||||||
public Watcher()
|
public Watcher()
|
||||||
{
|
{
|
||||||
const string LOG_IDENT = "Watcher";
|
const string LOG_IDENT = "Watcher";
|
||||||
@ -63,6 +65,8 @@ namespace Bloxstrap
|
|||||||
|
|
||||||
if (App.Settings.Prop.UseDiscordRichPresence)
|
if (App.Settings.Prop.UseDiscordRichPresence)
|
||||||
RichPresence = new(ActivityWatcher);
|
RichPresence = new(ActivityWatcher);
|
||||||
|
|
||||||
|
IntegrationWatcher = new IntegrationWatcher(ActivityWatcher);
|
||||||
}
|
}
|
||||||
|
|
||||||
_notifyIcon = new(this);
|
_notifyIcon = new(this);
|
||||||
@ -122,6 +126,7 @@ namespace Bloxstrap
|
|||||||
{
|
{
|
||||||
App.Logger.WriteLine("Watcher::Dispose", "Disposing Watcher");
|
App.Logger.WriteLine("Watcher::Dispose", "Disposing Watcher");
|
||||||
|
|
||||||
|
IntegrationWatcher?.Dispose();
|
||||||
_notifyIcon?.Dispose();
|
_notifyIcon?.Dispose();
|
||||||
RichPresence?.Dispose();
|
RichPresence?.Dispose();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user