diff --git a/AutoTrackR2/App.xaml.cs b/AutoTrackR2/App.xaml.cs index e84d792..115d332 100644 --- a/AutoTrackR2/App.xaml.cs +++ b/AutoTrackR2/App.xaml.cs @@ -1,9 +1,6 @@ using System.Configuration; using System.Data; using System.Windows; -using System.Threading; -using System.IO; -using System; namespace AutoTrackR2 { @@ -12,101 +9,5 @@ namespace AutoTrackR2 /// </summary> public partial class App : System.Windows.Application { - private static Mutex _mutex = null; - private static bool _mutexOwned = false; - private static readonly string CrashLogPath = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), - "AutoTrackR2", - "crash.log" - ); - - protected override void OnStartup(StartupEventArgs e) - { - // Ensure crash log directory exists - Directory.CreateDirectory(Path.GetDirectoryName(CrashLogPath)); - - // Set up unhandled exception handlers - AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException; - DispatcherUnhandledException += App_DispatcherUnhandledException; - - const string appName = "AutoTrackR2"; - bool createdNew; - - _mutex = new Mutex(true, appName, out createdNew); - _mutexOwned = createdNew; - - if (!createdNew) - { - // App is already running, silently exit - Current.Shutdown(); - return; - } - - base.OnStartup(e); - } - - private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e) - { - LogCrash(e.ExceptionObject as Exception); - } - - private void App_DispatcherUnhandledException(object sender, System.Windows.Threading.DispatcherUnhandledExceptionEventArgs e) - { - LogCrash(e.Exception); - e.Handled = true; // Prevent the application from crashing - } - - private void LogCrash(Exception? ex) - { - try - { - var timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); - var logMessage = $"[{timestamp}] CRASH: {ex?.Message}\n" + - $"Stack Trace:\n{ex?.StackTrace}\n" + - $"Source: {ex?.Source}\n" + - $"Target Site: {ex?.TargetSite}\n" + - "----------------------------------------\n"; - - File.AppendAllText(CrashLogPath, logMessage); - - // Show error message to user - MessageBox.Show( - "AutoTrackR2 has encountered an error. A crash log has been created.\n" + - $"Location: {CrashLogPath}", - "AutoTrackR2 Error", - MessageBoxButton.OK, - MessageBoxImage.Error - ); - } - catch (Exception logEx) - { - // If logging fails, at least show a basic error message - MessageBox.Show( - "AutoTrackR2 has encountered an error and failed to create a crash log.\n" + - $"Error: {ex?.Message}", - "AutoTrackR2 Error", - MessageBoxButton.OK, - MessageBoxImage.Error - ); - } - } - - protected override void OnExit(ExitEventArgs e) - { - if (_mutex != null && _mutexOwned) - { - try - { - _mutex.ReleaseMutex(); - } - catch (Exception ex) - { - // Log the mutex release error but don't throw - LogCrash(ex); - } - _mutex.Dispose(); - } - base.OnExit(e); - } } } diff --git a/AutoTrackR2/ConfigPage.xaml b/AutoTrackR2/ConfigPage.xaml index 70567a9..9114dfc 100644 --- a/AutoTrackR2/ConfigPage.xaml +++ b/AutoTrackR2/ConfigPage.xaml @@ -26,7 +26,7 @@ VerticalAlignment="Center" Height="389"> <!-- Log File --> - <StackPanel Margin="0,5,0,10" + <StackPanel Margin="0,10,0,15" Orientation="Horizontal"> <TextBlock Text="ⓘ" ToolTip="Set this to the Game.log file in your StarCitizen\LIVE directory." @@ -55,7 +55,7 @@ </StackPanel> <!-- API URL --> - <StackPanel Margin="0,0,0,10" + <StackPanel Margin="0,0,0,15" Orientation="Horizontal"> <TextBlock Text="ⓘ" ToolTip="Need a URL? No idea what to do? Contact heavy_bob on Discord!" @@ -83,7 +83,7 @@ </StackPanel> <!-- API Key --> - <StackPanel Margin="0,0,0,10" + <StackPanel Margin="0,0,0,15" Orientation="Horizontal"> <TextBlock Text="ⓘ" ToolTip="Need a key? No idea what to do? Contact heavy_bob on Discord!" @@ -102,7 +102,7 @@ </StackPanel> <!-- Video Path --> - <StackPanel Margin="0,0,0,10" + <StackPanel Margin="0,0,0,15" Orientation="Horizontal"> <TextBlock Text="ⓘ" ToolTip="The directory where your clipping software saves kills. Check the README." @@ -129,31 +129,18 @@ </StackPanel> </StackPanel> - <!-- Toggle Settings Grid --> - <Grid Margin="0,0,0,10"> - <Grid.ColumnDefinitions> - <ColumnDefinition Width="*"/> - <ColumnDefinition Width="*"/> - </Grid.ColumnDefinitions> - <Grid.RowDefinitions> - <RowDefinition Height="Auto"/> - <RowDefinition Height="Auto"/> - <RowDefinition Height="Auto"/> - </Grid.RowDefinitions> - - <!-- Visor Wipe Toggle --> - <StackPanel Grid.Column="0" Grid.Row="0" - Orientation="Horizontal" - Margin="0,0,5,5"> + <!-- Visor Wipe Toggle Slider --> + <StackPanel Margin="0,0,0,15" + Orientation="Horizontal"> <TextBlock Text="ⓘ" ToolTip="Perform a Visor Wipe animation on player kill. Requires AHKv2." Foreground="{DynamicResource TextBrush}" FontSize="20" - Margin="0,4,3,0"/> + Margin="0,4,3,5"/> <TextBlock Text="Visor Wipe:" Foreground="{DynamicResource TextBrush}" FontSize="16" - Margin="0,7,0,0"/> + Margin="0,7,0,5"/> <Slider Name="VisorWipeSlider" Minimum="0" Maximum="1" @@ -161,24 +148,22 @@ IsSnapToTickEnabled="True" Value="0" Style="{StaticResource ToggleSliderStyle}" - Margin="10,-4,0,0" - Width="100" + Margin="27,-4,0,0" ValueChanged="VisorWipeSlider_ValueChanged"/> - </StackPanel> + </StackPanel> - <!-- Video Record Toggle --> - <StackPanel Grid.Column="1" Grid.Row="0" - Orientation="Horizontal" - Margin="5,0,0,5"> + <!-- Video Record Toggle Slider --> + <StackPanel Margin="0,0,0,15" + Orientation="Horizontal"> <TextBlock Text="ⓘ" ToolTip="Automatically clip your last kill. Check the README for more info." Foreground="{DynamicResource TextBrush}" FontSize="20" - Margin="0,4,3,0"/> + Margin="0,4,3,5"/> <TextBlock Text="Video Record:" Foreground="{DynamicResource TextBrush}" FontSize="16" - Margin="0,7,0,0"/> + Margin="0,7,0,5"/> <Slider Name="VideoRecordSlider" Minimum="0" Maximum="1" @@ -187,23 +172,21 @@ Value="0" Style="{StaticResource ToggleSliderStyle}" Margin="10,-4,0,0" - Width="100" ValueChanged="VideoRecordSlider_ValueChanged"/> - </StackPanel> + </StackPanel> - <!-- Offline Mode Toggle --> - <StackPanel Grid.Column="0" Grid.Row="1" - Orientation="Horizontal" - Margin="0,0,5,5"> + <!-- Offline Mode Toggle Slider --> + <StackPanel Margin="0,0,0,10" + Orientation="Horizontal"> <TextBlock Text="ⓘ" ToolTip="With Offline Mode enabled, kills will not be submitted to the configured API." Foreground="{DynamicResource TextBrush}" FontSize="20" - Margin="0,4,3,0"/> + Margin="0,4,3,5"/> <TextBlock Text="Offline Mode:" Foreground="{DynamicResource TextBrush}" FontSize="16" - Margin="0,7,0,0"/> + Margin="0,7,0,5"/> <Slider Name="OfflineModeSlider" Minimum="0" Maximum="1" @@ -211,20 +194,17 @@ IsSnapToTickEnabled="True" Value="0" Style="{StaticResource ToggleSliderStyle}" - Margin="10,-4,0,0" - Width="100" + Margin="12,-4,0,0" ValueChanged="OfflineModeSlider_ValueChanged"/> - </StackPanel> + </StackPanel> - <!-- Theme Slider --> - <StackPanel Grid.Column="0" Grid.Row="2" - Grid.ColumnSpan="2" - Orientation="Horizontal" - Margin="0,0,0,5"> + <!-- 3-Position Toggle Slider --> + <StackPanel Margin="0,0,0,15" + Orientation="Horizontal"> <TextBlock Text="Theme:" Foreground="{DynamicResource TextBrush}" FontSize="16" - Margin="0,7,10,0"/> + Margin="0,7,0,5"/> <Slider x:Name="ThemeSlider" Minimum="0" Value="0" @@ -233,8 +213,8 @@ ValueChanged="ThemeSlider_ValueChanged" Width="447" Style="{StaticResource ThreePositionSlider}"/> - </StackPanel> - </Grid> + </StackPanel> + </StackPanel> <!-- Save Button --> diff --git a/AutoTrackR2/ConfigPage.xaml.cs b/AutoTrackR2/ConfigPage.xaml.cs index 1136f55..c4397ff 100644 --- a/AutoTrackR2/ConfigPage.xaml.cs +++ b/AutoTrackR2/ConfigPage.xaml.cs @@ -39,6 +39,7 @@ public partial class ConfigPage : UserControl ApplyToggleModeStyle(OfflineModeSlider.Value, VisorWipeSlider.Value, VideoRecordSlider.Value); + const string themeJsonPath = "themes.json"; var themeJson = File.ReadAllText(themeJsonPath); _themes = JsonSerializer.Deserialize<Dictionary<string, Theme>>(themeJson); @@ -77,19 +78,23 @@ public partial class ConfigPage : UserControl } // This method will set the loaded config values to the UI controls - public void SetConfigValues(string logFile, string apiUrl, string apiKey, string videoPath, int visorWipe, int videoRecord, int offlineMode, int theme) + public void SetConfigValues(string logFile, string apiUrl, string apiKey, string videoPath, + int visorWipe, int videoRecord, int offlineMode, int theme) { + // Set the textboxes with the loaded values LogFilePath.Text = logFile; ApiUrl.Text = apiUrl; ApiKey.Password = apiKey; VideoPath.Text = videoPath; - VisorWipeSlider.Value = visorWipe; + + // Set the sliders with the loaded values VideoRecordSlider.Value = videoRecord; + VisorWipeSlider.Value = visorWipe; OfflineModeSlider.Value = offlineMode; - ThemeSlider.Value = theme; // Handle themes ApplyTheme(theme); + } private void ApplyToggleModeStyle(double offlineModeValue, double visorWipeValue, double videoRecordValue) @@ -197,18 +202,18 @@ public partial class ConfigPage : UserControl // Video Path Browse Button Handler private void VideoPathBrowseButton_Click(object sender, RoutedEventArgs e) { - var dialog = new Microsoft.Win32.OpenFileDialog(); - dialog.ValidateNames = false; + var dialog = new OpenFileDialog(); dialog.CheckFileExists = false; - dialog.CheckPathExists = true; - dialog.FileName = "Folder Selection"; - - if (dialog.ShowDialog() == true) + dialog.ValidateNames = false; + dialog.Filter = "All files|*.*"; + + if (dialog.ShowDialog() == true && dialog.FileName != null) { + // Extract only the directory path from the file string? selectedFolder = Path.GetDirectoryName(dialog.FileName); if (selectedFolder != null) { - VideoPath.Text = selectedFolder; + VideoPath.Text = selectedFolder; // Set the folder path } } } @@ -315,8 +320,10 @@ public partial class ConfigPage : UserControl } } + private void SaveButton_Click(object sender, RoutedEventArgs e) { + ConfigManager.ApiKey = ApiKey.Password; ConfigManager.ApiUrl = ApiUrl.Text; ConfigManager.LogFile = LogFilePath.Text; @@ -325,7 +332,6 @@ public partial class ConfigPage : UserControl ConfigManager.VideoRecord = (int)VideoRecordSlider.Value; ConfigManager.OfflineMode = (int)OfflineModeSlider.Value; ConfigManager.Theme = (int)ThemeSlider.Value; - // Save the current config values ConfigManager.SaveConfig(); // Start the flashing effect @@ -398,11 +404,10 @@ public partial class ConfigPage : UserControl { // Set headers client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey); - client.DefaultRequestHeaders.UserAgent.ParseAdd("AutoTrackR2"); + client.DefaultRequestHeaders.UserAgent.ParseAdd("AutoTrackR"); - // Create JSON body with version - var jsonBody = new { version = "2.10" }; - var content = new StringContent(JsonSerializer.Serialize(jsonBody), Encoding.UTF8, "application/json"); + // Empty JSON body + var content = new StringContent("{}", Encoding.UTF8, "application/json"); // Send POST var response = await client.PostAsync(modifiedUrl, content); diff --git a/AutoTrackR2/HomePage.xaml b/AutoTrackR2/HomePage.xaml index 58c0e95..9c08122 100644 --- a/AutoTrackR2/HomePage.xaml +++ b/AutoTrackR2/HomePage.xaml @@ -42,20 +42,19 @@ </ScrollViewer> </Border> - <!-- Border and StackPanel for player info --> + <!-- StackPanel for Start and Stop buttons --> <Border Background="{DynamicResource BackgroundDarkBrush}" BorderBrush="{DynamicResource AccentBrush}" Grid.Row="0" Grid.Column="1" BorderThickness="2" CornerRadius="5" - Margin="0,0,0,10" - VerticalAlignment="Top"> - <StackPanel - VerticalAlignment="Top" + Margin="0,0,0,82"/> + <StackPanel Grid.Column="1" + VerticalAlignment="Center" HorizontalAlignment="Center" - Width="152" - Margin="10,5,10,5"> + Height="269" + Width="152"> <TextBlock Name="PilotNameTitle" Text="Pilot" Width="152" @@ -113,25 +112,6 @@ Foreground="{DynamicResource TextBrush}" FontSize="10" TextAlignment="Center"/> - <TextBlock Name="LocationTitle" - Text="Location" - Width="152" - Height="20" - Background="Transparent" - FontFamily="{StaticResource Orbitron}" - Margin="0,5,0,0" - Foreground="{DynamicResource AltTextBrush}" - FontSize="14"/> - <TextBlock Name="LocationTextBox" - Text="Unknown" - Width="152" - Height="20" - Background="Transparent" - FontFamily="{StaticResource Orbitron}" - Margin="0,0,0,0" - Foreground="{DynamicResource TextBrush}" - FontSize="10" - TextAlignment="Center"/> <TextBlock Name="KillTallyTitle" Text="Kill Tally" Width="152" @@ -161,8 +141,7 @@ FontSize="8" BorderThickness="0" Margin="0,9,0,0"/> - </StackPanel> - </Border> + </StackPanel> <StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" diff --git a/AutoTrackR2/HomePage.xaml.cs b/AutoTrackR2/HomePage.xaml.cs index f727a62..b765f0a 100644 --- a/AutoTrackR2/HomePage.xaml.cs +++ b/AutoTrackR2/HomePage.xaml.cs @@ -77,11 +77,9 @@ public partial class HomePage : UserControl GameModeTextBox.Text = "Unknown"; PlayerShipTextBox.Text = "Unknown"; PilotNameTextBox.Text = "Unknown"; - LocationTextBox.Text = "Unknown"; LocalPlayerData.CurrentGameMode = GameMode.Unknown; LocalPlayerData.PlayerShip = string.Empty; LocalPlayerData.Username = string.Empty; - LocalPlayerData.LastSeenVehicleLocation = "Unknown"; // Stop log monitoring if it's running if (_isLogHandlerRunning) @@ -141,8 +139,6 @@ public partial class HomePage : UserControl AdjustFontSize(PlayerShipTextBox); LocalPlayerData.PlayerShip = data.ShipName; LocalPlayerData.LastSeenVehicleLocation = data.Location; - LocationTextBox.Text = data.Location; - AdjustFontSize(LocationTextBox); }); }; @@ -220,12 +216,7 @@ public partial class HomePage : UserControl // Vehicle Destruction TrackREventDispatcher.VehicleDestructionEvent += (data) => { - Dispatcher.Invoke(() => - { - LocalPlayerData.LastSeenVehicleLocation = data.VehicleZone; - LocationTextBox.Text = data.VehicleZone; - AdjustFontSize(LocationTextBox); - }); + LocalPlayerData.LastSeenVehicleLocation = data.VehicleZone; }; _UIEventsRegistered = true; @@ -233,51 +224,67 @@ public partial class HomePage : UserControl private void AddKillToScreen(KillData killData) { - // Use resource references instead of creating new brushes + // Fetch the dynamic resource for AltTextColor + var altTextColorBrush = new SolidColorBrush((Color)Application.Current.Resources["AltTextColor"]); + var accentColorBrush = new SolidColorBrush((Color)Application.Current.Resources["AccentColor"]); + + // Fetch the Orbitron FontFamily from resources + var orbitronFontFamily = (FontFamily)Application.Current.Resources["Orbitron"]; + var gemunuFontFamily = (FontFamily)Application.Current.Resources["Gemunu"]; + + // Create a new TextBlock for each kill var killTextBlock = new TextBlock { Margin = new Thickness(0, 10, 0, 10), - Style = (Style)Application.Current.Resources["RoundedTextBlock"], + Style = (Style)Application.Current.Resources["RoundedTextBlock"], // Apply style for text FontSize = 14, FontWeight = FontWeights.Bold, - FontFamily = (FontFamily)Application.Current.Resources["Gemunu"], + FontFamily = gemunuFontFamily, }; - // Add styled content using Run elements with resource references - var titleRun = new Run("Victim Name: "); - titleRun.SetResourceReference(TextElement.ForegroundProperty, "AltTextBrush"); - titleRun.FontFamily = (FontFamily)Application.Current.Resources["Orbitron"]; - killTextBlock.Inlines.Add(titleRun); + // Add styled content using Run elements + killTextBlock.Inlines.Add(new Run("Victim Name: ") + { + Foreground = altTextColorBrush, + FontFamily = orbitronFontFamily, + }); killTextBlock.Inlines.Add(new Run($"{killData.EnemyPilot}\n")); - titleRun = new Run("Victim Ship: "); - titleRun.SetResourceReference(TextElement.ForegroundProperty, "AltTextBrush"); - titleRun.FontFamily = (FontFamily)Application.Current.Resources["Orbitron"]; - killTextBlock.Inlines.Add(titleRun); + // Repeat for other lines + killTextBlock.Inlines.Add(new Run("Victim Ship: ") + { + Foreground = altTextColorBrush, + FontFamily = orbitronFontFamily, + }); killTextBlock.Inlines.Add(new Run($"{killData.EnemyShip}\n")); - titleRun = new Run("Victim Org: "); - titleRun.SetResourceReference(TextElement.ForegroundProperty, "AltTextBrush"); - titleRun.FontFamily = (FontFamily)Application.Current.Resources["Orbitron"]; - killTextBlock.Inlines.Add(titleRun); + killTextBlock.Inlines.Add(new Run("Victim Org: ") + { + Foreground = altTextColorBrush, + FontFamily = orbitronFontFamily, + }); killTextBlock.Inlines.Add(new Run($"{killData.OrgAffiliation}\n")); - titleRun = new Run("Join Date: "); - titleRun.SetResourceReference(TextElement.ForegroundProperty, "AltTextBrush"); - titleRun.FontFamily = (FontFamily)Application.Current.Resources["Orbitron"]; - killTextBlock.Inlines.Add(titleRun); + killTextBlock.Inlines.Add(new Run("Join Date: ") + { + Foreground = altTextColorBrush, + FontFamily = orbitronFontFamily, + }); killTextBlock.Inlines.Add(new Run($"{killData.Enlisted}\n")); - titleRun = new Run("UEE Record: "); - titleRun.SetResourceReference(TextElement.ForegroundProperty, "AltTextBrush"); - titleRun.FontFamily = (FontFamily)Application.Current.Resources["Orbitron"]; - killTextBlock.Inlines.Add(titleRun); + killTextBlock.Inlines.Add(new Run("UEE Record: ") + { + Foreground = altTextColorBrush, + FontFamily = orbitronFontFamily, + }); + killTextBlock.Inlines.Add(new Run($"{killData.RecordNumber}\n")); - titleRun = new Run("Kill Time: "); - titleRun.SetResourceReference(TextElement.ForegroundProperty, "AltTextBrush"); - titleRun.FontFamily = (FontFamily)Application.Current.Resources["Orbitron"]; - killTextBlock.Inlines.Add(titleRun); + killTextBlock.Inlines.Add(new Run("Kill Time: ") + { + Foreground = altTextColorBrush, + FontFamily = orbitronFontFamily, + }); killTextBlock.Inlines.Add(new Run($"{killData.KillTime}")); // Create a Border and apply the RoundedTextBlockWithBorder style