diff --git a/Bloxstrap/Bootstrapper.cs b/Bloxstrap/Bootstrapper.cs index 13f2b1f..504990a 100644 --- a/Bloxstrap/Bootstrapper.cs +++ b/Bloxstrap/Bootstrapper.cs @@ -201,28 +201,41 @@ namespace Bloxstrap private bool CheckIfRunning(bool shutdown) { + App.Logger.WriteLine($"[Bootstrapper::CheckIfRunning] Checking if Roblox is running... (shutdown={shutdown})"); + Process[] processes = Process.GetProcessesByName("RobloxPlayerBeta"); if (processes.Length == 0) - return false; - - if (shutdown) { - Dialog?.PromptShutdown(); - - try - { - // try/catch just in case process was closed before prompt was answered - - foreach (Process process in processes) - { - process.CloseMainWindow(); - process.Close(); - } - } - catch (Exception) { } + App.Logger.WriteLine($"[Bootstrapper::CheckIfRunning] Roblox is not running"); + return false; } + App.Logger.WriteLine($"[Bootstrapper::CheckIfRunning] Roblox is running, found {processes.Length} process(es)"); + + if (!shutdown) + return true; + + App.Logger.WriteLine($"[Bootstrapper::CheckIfRunning] Attempting to shutdown Roblox..."); + + Dialog?.PromptShutdown(); + + try + { + // try/catch just in case process was closed before prompt was answered + + foreach (Process process in processes) + { + process.CloseMainWindow(); + process.Close(); + } + } + catch (Exception e) + { + App.Logger.WriteLine($"[Bootstrapper::CheckIfRunning] Failed to close process! {e}"); + } + + App.Logger.WriteLine($"[Bootstrapper::CheckIfRunning] All Roblox processes closed"); return true; } @@ -246,12 +259,15 @@ namespace Bloxstrap _launchCommandLine += " -startEvent " + startEventName; + // whether we should wait for roblox to exit to handle stuff in the background or clean up after roblox closes bool shouldWait = false; Process gameClient = Process.Start(Path.Combine(_versionFolder, "RobloxPlayerBeta.exe"), _launchCommandLine); - Process? rbxFpsUnlocker = null; + List autocloseProcesses = new(); DiscordRichPresence? richPresence = null; Mutex? singletonMutex = null; + App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Started Roblox (PID {gameClient.Id})"); + using (SystemEvent startEvent = new(startEventName)) { bool startEventFired = await startEvent.WaitForEvent(); @@ -262,7 +278,7 @@ namespace Bloxstrap return; } - if (App.Settings.Prop.RFUEnabled && Process.GetProcessesByName("rbxfpsunlocker").Length == 0) + if (App.Settings.Prop.RFUEnabled && Process.GetProcessesByName(RbxFpsUnlocker.ApplicationName).Length == 0) { App.Logger.WriteLine("[Bootstrapper::StartRoblox] Using rbxfpsunlocker"); @@ -272,10 +288,13 @@ namespace Bloxstrap FileName = Path.Combine(Directories.Integrations, @"rbxfpsunlocker\rbxfpsunlocker.exe") }; - rbxFpsUnlocker = Process.Start(startInfo); - - if (App.Settings.Prop.RFUAutoclose) + Process process = Process.Start(startInfo)!; + + if (App.Settings.Prop.RFUAutoclose) + { shouldWait = true; + autocloseProcesses.Add(process); + } } if (App.Settings.Prop.UseDiscordRichPresence) @@ -293,6 +312,19 @@ namespace Bloxstrap shouldWait = true; } + // launch custom integrations now + foreach (CustomIntegration integration in App.Settings.Prop.CustomIntegrations) + { + App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Launching custom integration '{integration.Name}' ({integration.Location} {integration.LaunchArgs} - autoclose is {integration.AutoClose})"); + Process process = Process.Start(integration.Location, integration.LaunchArgs); + + if (integration.AutoClose) + { + shouldWait = true; + autocloseProcesses.Add(process); + } + } + // event fired, wait for 3 seconds then close await Task.Delay(3000); Dialog?.CloseBootstrapper(); @@ -305,11 +337,15 @@ namespace Bloxstrap App.Logger.WriteLine("[Bootstrapper::StartRoblox] Waiting for Roblox to close"); await gameClient.WaitForExitAsync(); + App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Roblox exited with code {gameClient.ExitCode}"); richPresence?.Dispose(); - if (App.Settings.Prop.RFUAutoclose) - rbxFpsUnlocker?.Kill(); + foreach (Process process in autocloseProcesses) + { + App.Logger.WriteLine($"[Bootstrapper::StartRoblox] Autoclosing process '{process.ProcessName}' (PID {process.Id})"); + process.Kill(); + } } public void CancelInstall() diff --git a/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs b/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs index 23362ff..77b4a36 100644 --- a/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs +++ b/Bloxstrap/Helpers/Integrations/DiscordRichPresence.cs @@ -39,11 +39,11 @@ namespace Bloxstrap.Helpers.Integrations App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Updated presence"); RichPresence.OnConnectionEstablished += (_, e) => - App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Established connection with Discord RPC!"); + App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Established connection with Discord RPC"); //spams log as it tries to connect every ~15 sec when discord is closed so not now //RichPresence.OnConnectionFailed += (_, e) => - // App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Failed to establish connection with Discord RPC!"); + // App.Logger.WriteLine("[DiscordRichPresence::DiscordRichPresence] Failed to establish connection with Discord RPC"); RichPresence.OnClose += (_, e) => App.Logger.WriteLine($"[DiscordRichPresence::DiscordRichPresence] Lost connection to Discord RPC - {e.Reason} ({e.Code})"); @@ -219,6 +219,7 @@ namespace Bloxstrap.Helpers.Integrations public void Dispose() { + App.Logger.WriteLine("[DiscordRichPresence::Dispose] Cleaning up Discord RPC and Presence"); RichPresence.ClearPresence(); RichPresence.Dispose(); } diff --git a/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs index b75f2d0..d61eb32 100644 --- a/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs +++ b/Bloxstrap/Helpers/Integrations/RbxFpsUnlocker.cs @@ -31,14 +31,14 @@ namespace Bloxstrap.Helpers.Integrations if (processes.Length == 0) return; + + App.Logger.WriteLine("[RbxFpsUnlocker::CheckIfRunning] Closing currently running rbxfpsunlocker processes..."); try { - // try/catch just in case process was closed before prompt was answered - foreach (Process process in processes) { - if (process.MainModule is null || process.MainModule.FileName is null) + if (process.MainModule?.FileName is null) continue; if (!process.MainModule.FileName.Contains(App.BaseDirectory)) @@ -48,7 +48,10 @@ namespace Bloxstrap.Helpers.Integrations process.Close(); } } - catch (Exception) { } + catch (Exception e) + { + App.Logger.WriteLine($"[RbxFpsUnlocker::CheckIfRunning] Could not close rbxfpsunlocker process! {e}"); + } } public static async Task CheckInstall() diff --git a/Bloxstrap/Helpers/Integrations/ReShade.cs b/Bloxstrap/Helpers/Integrations/ReShade.cs index ddaf95f..efe0951 100644 --- a/Bloxstrap/Helpers/Integrations/ReShade.cs +++ b/Bloxstrap/Helpers/Integrations/ReShade.cs @@ -303,7 +303,7 @@ namespace Bloxstrap.Helpers.Integrations if (!Directory.Exists(PresetsFolder)) return; - App.Logger.WriteLine("[ReShade::UninstallExtraviPresets] Uninstalling Extravi's presets..."); + App.Logger.WriteLine("[ReShade::UninstallExtraviPresets] Uninstalling Extravi's ReShade presets..."); FileInfo[] presets = new DirectoryInfo(PresetsFolder).GetFiles(); @@ -319,32 +319,39 @@ namespace Bloxstrap.Helpers.Integrations public static async Task CheckModifications() { - App.Logger.WriteLine("[ReShade::CheckModifications] Checking ReShade modifications... "); + App.Logger.WriteLine("[ReShade::CheckModifications] Checking ReShade modifications..."); string injectorLocation = Path.Combine(Directories.Modifications, "dxgi.dll"); - if (!App.Settings.Prop.UseReShadeExtraviPresets) + if (!App.Settings.Prop.UseReShadeExtraviPresets && !String.IsNullOrEmpty(App.State.Prop.ExtraviReShadePresetsVersion)) { UninstallExtraviPresets(); + App.State.Prop.ExtraviReShadePresetsVersion = ""; App.State.Save(); } if (!App.Settings.Prop.UseReShade) { + App.Logger.WriteLine("[ReShade::CheckModifications] ReShade is not enabled"); + + // we should already be uninstalled + // we want to ensure this is done one-time only as this could possibly interfere with other rendering hooks using dxgi.dll + if (String.IsNullOrEmpty(App.State.Prop.ReShadeConfigVersion)) + return; + App.Logger.WriteLine("[ReShade::CheckModifications] Uninstalling ReShade..."); // delete any stock config files File.Delete(injectorLocation); File.Delete(ConfigLocation); - App.State.Prop.ReShadeConfigVersion = ""; - App.State.Save(); - - //DeleteShaders("Stock"); if (Directory.Exists(BaseDirectory)) Directory.Delete(BaseDirectory, true); + App.State.Prop.ReShadeConfigVersion = ""; + App.State.Save(); + return; } diff --git a/Bloxstrap/Models/CustomIntegration.cs b/Bloxstrap/Models/CustomIntegration.cs new file mode 100644 index 0000000..998daee --- /dev/null +++ b/Bloxstrap/Models/CustomIntegration.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json.Linq; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Bloxstrap.Models +{ + public class CustomIntegration + { + public string Name { get; set; } = null!; + public string Location { get; set; } = null!; + public string LaunchArgs { get; set; } = null!; + public bool AutoClose { get; set; } = false; + + public override string ToString() + { + return Name; + } + } +} diff --git a/Bloxstrap/Models/Settings.cs b/Bloxstrap/Models/Settings.cs index 4effd66..ff1a6ae 100644 --- a/Bloxstrap/Models/Settings.cs +++ b/Bloxstrap/Models/Settings.cs @@ -1,4 +1,5 @@ -using Bloxstrap.Enums; +using System.Collections.Generic; +using Bloxstrap.Enums; using Bloxstrap.Helpers; namespace Bloxstrap.Models @@ -24,6 +25,7 @@ namespace Bloxstrap.Models public bool RFUAutoclose { get; set; } = false; public bool UseReShade { get; set; } = false; public bool UseReShadeExtraviPresets { get; set; } = false; + public List CustomIntegrations { get; set; } = new(); // mod preset configuration public bool UseOldDeathSound { get; set; } = true; diff --git a/Bloxstrap/ViewModels/IntegrationsViewModel.cs b/Bloxstrap/ViewModels/IntegrationsViewModel.cs index c7013d5..225c24b 100644 --- a/Bloxstrap/ViewModels/IntegrationsViewModel.cs +++ b/Bloxstrap/ViewModels/IntegrationsViewModel.cs @@ -1,4 +1,5 @@ -using System.ComponentModel; +using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Windows; @@ -8,6 +9,7 @@ using CommunityToolkit.Mvvm.Input; using Wpf.Ui.Mvvm.Contracts; using Bloxstrap.Helpers; +using Bloxstrap.Models; using Bloxstrap.Views.Pages; namespace Bloxstrap.ViewModels @@ -27,6 +29,12 @@ namespace Bloxstrap.ViewModels public IntegrationsViewModel(Page page) { _page = page; + + if (CustomIntegrations.Count > 0) + { + CustomIntegrationsVisibility = Visibility.Visible; + OnPropertyChanged(nameof(CustomIntegrationsVisibility)); + } } private void OpenReShadeFolder() @@ -93,5 +101,15 @@ namespace Bloxstrap.ViewModels get => App.Settings.Prop.RFUAutoclose; set => App.Settings.Prop.RFUAutoclose = value; } + + public Visibility CustomIntegrationsVisibility { get; set; } = Visibility.Collapsed; + + public List CustomIntegrations + { + get => App.Settings.Prop.CustomIntegrations; + set => App.Settings.Prop.CustomIntegrations = value; + } + + public CustomIntegration SelectedCustomIntegration { get; set; } } } diff --git a/Bloxstrap/Views/MainWindow.xaml b/Bloxstrap/Views/MainWindow.xaml index b15106a..ef4c2a7 100644 --- a/Bloxstrap/Views/MainWindow.xaml +++ b/Bloxstrap/Views/MainWindow.xaml @@ -10,7 +10,7 @@ mc:Ignorable="d" Title="Bloxstrap Menu" MinWidth="880" - Width="920" + Width="960" Height="580" Background="{ui:ThemeResource ApplicationBackgroundBrush}" ExtendsContentIntoTitleBar="True" @@ -58,9 +58,9 @@ - - - + + + diff --git a/Bloxstrap/Views/Pages/InstallationPage.xaml b/Bloxstrap/Views/Pages/InstallationPage.xaml index c97a6c4..1c5372b 100644 --- a/Bloxstrap/Views/Pages/InstallationPage.xaml +++ b/Bloxstrap/Views/Pages/InstallationPage.xaml @@ -12,7 +12,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml b/Bloxstrap/Views/Pages/IntegrationsPage.xaml index feb62e6..8ebb3ec 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml @@ -114,5 +114,26 @@ + + + + Using custom integrations, you can have other programs launch with Roblox automatically like how rbxfpsunlocker does. + To manage custom integrations, you'll have to manually edit your Settings.json configuration file in your Bloxstrap folder. If you have any configured, you'll be able to preview them here. + + + + + + + + + + + + + + + + diff --git a/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs b/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs index caf7cfb..eb5121d 100644 --- a/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs +++ b/Bloxstrap/Views/Pages/IntegrationsPage.xaml.cs @@ -1,5 +1,7 @@ using System; using System.Windows; +using System.Windows.Controls; +using Bloxstrap.Models; using Bloxstrap.ViewModels; namespace Bloxstrap.Views.Pages @@ -18,5 +20,12 @@ namespace Bloxstrap.Views.Pages if (!Environment.Is64BitOperatingSystem) this.RbxFpsUnlockerOptions.Visibility = Visibility.Collapsed; } + + public void CustomIntegrationSelection(object sender, SelectionChangedEventArgs e) + { + IntegrationsViewModel viewModel = (IntegrationsViewModel)DataContext; + viewModel.SelectedCustomIntegration = (CustomIntegration)((ListBox)sender).SelectedItem; + viewModel.OnPropertyChanged(nameof(viewModel.SelectedCustomIntegration)); + } } }