Compare commits

...

2 commits

Author SHA1 Message Date
Heavy Bob
3c23f34d3f Fixed kill streak cleanup and added trackrver constant. 2025-04-13 05:58:44 +10:00
Heavy Bob
36cfdaba8a Kill Streaks and Multikills.
Implemented kill streaks and multikills. Need to do some cleaning up but should work great.
2025-04-13 04:58:31 +10:00
27 changed files with 272 additions and 31 deletions

View file

@ -20,6 +20,13 @@ namespace AutoTrackR2
"crash.log"
);
private StreamlinkHandler? _streamlinkHandler;
private KillStreakManager? _killStreakManager;
private void HandleException(Exception ex)
{
MessageBox.Show($"Failed to start AutoTrackR2: {ex.Message}", "AutoTrackR2 Error", MessageBoxButton.OK, MessageBoxImage.Error);
Current.Shutdown();
}
protected override void OnStartup(StartupEventArgs e)
{
@ -49,6 +56,10 @@ namespace AutoTrackR2
// Initialize StreamlinkHandler before creating the main window
_streamlinkHandler = new StreamlinkHandler();
// Initialize KillStreakManager
var soundsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sounds");
_killStreakManager = new KillStreakManager(soundsPath);
// Create and show the main window
var mainWindow = new MainWindow();
mainWindow.Show();
@ -57,8 +68,7 @@ namespace AutoTrackR2
}
catch (Exception ex)
{
MessageBox.Show($"Failed to start AutoTrackR2: {ex.Message}", "AutoTrackR2 Error", MessageBoxButton.OK, MessageBoxImage.Error);
Current.Shutdown();
HandleException(ex);
}
}
@ -110,24 +120,10 @@ namespace AutoTrackR2
protected override void OnExit(ExitEventArgs e)
{
try
{
if (_mutex != null && _mutexOwned)
{
_mutex.ReleaseMutex();
_mutex.Close();
_mutex = null;
}
}
catch (Exception ex)
{
// Log the error but don't prevent shutdown
File.AppendAllText(CrashLogPath, $"[{DateTime.Now}] Error during shutdown: {ex.Message}\n");
}
finally
{
base.OnExit(e);
}
// Clean up resources
_killStreakManager?.Cleanup();
_mutex?.Dispose();
base.OnExit(e);
}
}
}

View file

@ -38,4 +38,14 @@
</Resource>
</ItemGroup>
<ItemGroup>
<None Include="sounds\*.mp3">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<PackageReference Include="NAudio" Version="2.2.1" />
</ItemGroup>
</Project>

View file

@ -156,6 +156,19 @@
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Kill Streak Test Button -->
<!--
<Button Grid.Column="0"
Grid.Row="0"
Grid.ColumnSpan="2"
Content="Test Kill Streak Sounds"
Height="30"
FontFamily="{StaticResource Orbitron}"
Margin="0,0,0,10"
Style="{StaticResource ButtonStyle}"
Click="TestKillStreakButton_Click"/>
-->
<!-- Left Column Controls -->
<!-- Visor Wipe Toggle -->

View file

@ -12,6 +12,7 @@ using System.Windows.Media.Effects;
using System.Windows.Threading;
using Microsoft.Win32;
using System.Threading.Tasks;
using AutoTrackR2.Constants;
namespace AutoTrackR2;
@ -24,6 +25,10 @@ public partial class ConfigPage : UserControl
Dictionary<string, Theme>? _themes = null;
private KillStreakManager? _testKillStreakManager;
private bool _isTestRunning = false;
private int _currentTestStep = 0;
public ConfigPage(MainWindow mainWindow)
{
InitializeComponent();
@ -215,7 +220,7 @@ public partial class ConfigPage : UserControl
dialog.CheckFileExists = false;
dialog.CheckPathExists = true;
dialog.FileName = "Folder Selection";
if (dialog.ShowDialog() == true)
{
string? selectedFolder = Path.GetDirectoryName(dialog.FileName);
@ -338,7 +343,7 @@ 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
@ -414,7 +419,7 @@ public partial class ConfigPage : UserControl
client.DefaultRequestHeaders.UserAgent.ParseAdd("AutoTrackR2");
// Create JSON body with version
var jsonBody = new { version = "2.10" };
var jsonBody = new { version = AppConstants.Version };
var content = new StringContent(JsonSerializer.Serialize(jsonBody), Encoding.UTF8, "application/json");
// Send POST
@ -502,7 +507,7 @@ public partial class ConfigPage : UserControl
client.DefaultRequestHeaders.UserAgent.ParseAdd("AutoTrackR2");
// Create JSON body with version
var jsonBody = new { version = "2.10" };
var jsonBody = new { version = AppConstants.Version };
var content = new StringContent(JsonSerializer.Serialize(jsonBody), Encoding.UTF8, "application/json");
// Send POST to test endpoint
@ -562,6 +567,26 @@ public partial class ConfigPage : UserControl
MessageBox.Show("Directory does not exist.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private async void TestKillStreakButton_Click(object sender, RoutedEventArgs e)
{
// Create a single KillStreakManager instance if it doesn't exist
if (_testKillStreakManager == null)
{
var soundsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sounds");
_testKillStreakManager = new KillStreakManager(soundsPath);
}
// Simulate 5 quick kills
for (int i = 0; i < 5; i++)
{
_testKillStreakManager.OnKill();
}
// Reset the streak after all sounds have played
await Task.Delay(1000);
_testKillStreakManager.OnDeath();
}
}
public class Theme

6
AutoTrackR2/Constants.cs Normal file
View file

@ -0,0 +1,6 @@
namespace AutoTrackR2.Constants;
public static class AppConstants
{
public const string Version = "2.11";
}

View file

@ -11,7 +11,7 @@ using System.Windows.Media.Imaging;
using AutoTrackR2.LogEventHandlers;
using System.Timers;
using System.Linq;
using AutoTrackR2.Constants;
namespace AutoTrackR2;
@ -37,7 +37,7 @@ public partial class HomePage : UserControl
{
throw new InvalidOperationException("KillHistoryFile path is not configured.");
}
_killHistoryManager = new KillHistoryManager(ConfigManager.KillHistoryFile);
_killHistoryManager = new KillHistoryManager(ConfigManager.KillHistoryFile, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sounds"));
// Set the TextBlock text
KillTallyTitle.Text = $"Kill Tally - {DateTime.Now.ToString("MMMM")}";
@ -231,7 +231,7 @@ public partial class HomePage : UserControl
Method = actorDeathData.DamageType,
RecordNumber = playerData?.UEERecord,
GameVersion = LocalPlayerData.GameVersion ?? "Unknown",
TrackRver = "2.10",
TrackRver = AppConstants.Version,
Enlisted = playerData?.JoinDate,
KillTime = ((DateTimeOffset)DateTime.ParseExact(actorDeathData.Timestamp, "yyyy-MM-ddTHH:mm:ss.fffZ", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal)).ToUnixTimeSeconds().ToString(),
PFP = playerData?.PFPURL ?? "https://cdn.robertsspaceindustries.com/static/images/account/avatar_default_big.jpg",
@ -279,6 +279,11 @@ public partial class HomePage : UserControl
});
}
}
else
{
// Player died, reset kill streak
_killHistoryManager.ResetKillStreak();
}
};
// Vehicle Destruction

View file

@ -8,11 +8,13 @@ public class KillHistoryManager
{
private string _killHistoryPath;
private readonly string _headers = "KillTime,EnemyPilot,EnemyShip,Enlisted,RecordNumber,OrgAffiliation,Player,Weapon,Ship,Method,Mode,GameVersion,TrackRver,Logged,PFP,Hash\n";
private readonly KillStreakManager _killStreakManager;
public KillHistoryManager(string logPath)
public KillHistoryManager(string logPath, string soundsPath)
{
_killHistoryPath = logPath;
_killStreakManager = new KillStreakManager(soundsPath);
if (!File.Exists(_killHistoryPath))
{
File.WriteAllText(_killHistoryPath, _headers);
@ -97,6 +99,9 @@ public class KillHistoryManager
using var fileStream = new FileStream(_killHistoryPath, FileMode.Append, FileAccess.Write, FileShare.None);
using var writer = new StreamWriter(fileStream);
writer.Write(csv.ToString());
// Trigger kill streak sound
_killStreakManager.OnKill();
}
catch (IOException ex)
{
@ -104,7 +109,12 @@ public class KillHistoryManager
Console.WriteLine($"Error writing to file: {ex.Message}");
}
}
public void ResetKillStreak()
{
_killStreakManager.OnDeath();
}
public List<KillData> GetKills()
{
var kills = new List<KillData>();

View file

@ -0,0 +1,176 @@
using System.Media;
using System.Timers;
using System.IO;
using NAudio.Wave;
namespace AutoTrackR2;
public class KillStreakManager
{
private readonly Queue<string> _soundQueue = new();
private readonly System.Timers.Timer _killStreakTimer = new(5000); // 5 seconds between kills for streak
private int _currentKills = 0;
private int _totalKills = 0;
private readonly string _soundsPath;
private readonly object _lock = new();
private WaveOutEvent? _waveOut;
private bool _isPlaying = false;
public KillStreakManager(string soundsPath)
{
_soundsPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "sounds");
_killStreakTimer.Elapsed += OnKillStreakTimerElapsed;
Console.WriteLine($"KillStreakManager initialized with sounds path: {_soundsPath}");
}
public void OnKill()
{
lock (_lock)
{
_currentKills++;
_totalKills++;
_killStreakTimer.Stop();
_killStreakTimer.Start();
// Handle multi-kill announcements
string multiKillSound = _currentKills switch
{
2 => "double_kill.mp3",
3 => "triple_kill.mp3",
4 => "overkill.mp3",
5 => "killtacular.mp3",
6 => "killtrocity.mp3",
7 => "killimanjaro.mp3",
8 => "killtastrophe.mp3",
9 => "killpocalypse.mp3",
10 => "killionaire.mp3",
_ => null
};
// Handle spree announcements
string spreeSound = _totalKills switch
{
5 => "killing_spree.mp3",
10 => "killing_frenzy.mp3",
15 => "running_riot.mp3",
20 => "rampage.mp3",
25 => "untouchable.mp3",
30 => "invincible.mp3",
35 => "unstoppable.mp3",
40 => "hells_janitor.mp3",
45 => "perfection.mp3",
_ => null
};
// Queue up the sounds if they exist
if (multiKillSound != null)
{
string soundPath = Path.Combine(_soundsPath, multiKillSound);
Console.WriteLine($"Queueing multi-kill sound: {soundPath}");
_soundQueue.Enqueue(soundPath);
}
if (spreeSound != null)
{
string soundPath = Path.Combine(_soundsPath, spreeSound);
Console.WriteLine($"Queueing spree sound: {soundPath}");
_soundQueue.Enqueue(soundPath);
}
// Only start playing if not already playing
if (!_isPlaying && _soundQueue.Count > 0)
{
PlayNextSound();
}
}
}
public void OnDeath()
{
lock (_lock)
{
_totalKills = 0;
_currentKills = 0;
_killStreakTimer.Stop();
Console.WriteLine("Kill streak reset due to death");
}
}
private void OnKillStreakTimerElapsed(object? sender, ElapsedEventArgs e)
{
lock (_lock)
{
_currentKills = 0;
_killStreakTimer.Stop();
Console.WriteLine("Kill streak reset due to timeout");
}
}
public void Cleanup()
{
lock (_lock)
{
_killStreakTimer.Stop();
_killStreakTimer.Dispose();
_waveOut?.Dispose();
_waveOut = null;
}
}
private void PlayNextSound()
{
if (_soundQueue.Count > 0)
{
string soundPath = _soundQueue.Dequeue();
Console.WriteLine($"Attempting to play sound: {soundPath}");
try
{
if (File.Exists(soundPath))
{
// Stop any currently playing sound
_waveOut?.Stop();
_waveOut?.Dispose();
// Create a new WaveOutEvent
_waveOut = new WaveOutEvent();
// Create a new AudioFileReader for the MP3 file
using var audioFile = new AudioFileReader(soundPath);
_waveOut.Init(audioFile);
// Set up event handler for when playback finishes
_waveOut.PlaybackStopped += (sender, e) =>
{
_isPlaying = false;
if (_soundQueue.Count > 0)
{
PlayNextSound();
}
};
_isPlaying = true;
_waveOut.Play();
Console.WriteLine($"Successfully played sound: {soundPath}");
}
else
{
Console.WriteLine($"Sound file not found: {soundPath}");
_isPlaying = false;
if (_soundQueue.Count > 0)
{
PlayNextSound();
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Error playing sound {soundPath}: {ex.Message}");
_isPlaying = false;
if (_soundQueue.Count > 0)
{
PlayNextSound();
}
}
}
}
}

View file

@ -181,7 +181,7 @@ public class LogHandler
{
// Wait for new lines to be written to the log file
Thread.Sleep(1000);
Thread.Sleep(500);
}
}
Console.WriteLine("Monitor thread stopped");

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.