diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 294769d..66cfbae 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -13,10 +13,11 @@ jobs:
     steps:
       - uses: actions/checkout@v3
 
-      - name: Extract version
-        id: version
+      - name: Get build number
+        id: buildnumber
         run: |
-          $version = (Select-String -Path "AutoTrackR2/UpdatePage.xaml.cs" -Pattern 'currentVersion = "(.+?)"' | Select-Object -First 1).Matches.Groups[1].Value
+          $runNumber = $env:GITHUB_RUN_NUMBER
+          $version = "2.$runNumber"
           echo "version=$version" >> $env:GITHUB_OUTPUT
 
       - name: Setup .NET
@@ -28,44 +29,55 @@ jobs:
         run: dotnet restore AutoTrackR2.sln
 
       - name: Build
-        run: dotnet build AutoTrackR2.sln --configuration Release --no-restore
-
-      - name: List build output directories
         run: |
-          Write-Host "Listing build output directories:"
-          Get-ChildItem -Recurse -Directory -Filter "Release" | ForEach-Object { Write-Host $_.FullName }
+          dotnet build AutoTrackR2.sln --configuration Release --no-restore -p:Version=${{ steps.buildnumber.outputs.version }}
 
-      - name: Create artifacts directory
-        run: mkdir artifacts
-
-      - name: Copy build output
+      - name: Create release directory
         run: |
+          mkdir release
           $releaseDir = Get-ChildItem -Recurse -Directory -Filter "Release" | Select-Object -First 1
           if ($releaseDir) {
-            Write-Host "Copying from: $($releaseDir.FullName)"
-            Copy-Item "$($releaseDir.FullName)\*" "artifacts\" -Recurse
+            Write-Host "Release directory found at: $($releaseDir.FullName)"
+            
+            # Copy main application files (excluding .pdb)
+            Copy-Item "$($releaseDir.FullName)\AutoTrackR2.exe" "release\" -ErrorAction SilentlyContinue
+            Copy-Item "$($releaseDir.FullName)\AutoTrackR2.dll" "release\" -ErrorAction SilentlyContinue
+            Copy-Item "$($releaseDir.FullName)\AutoTrackR2.runtimeconfig.json" "release\" -ErrorAction SilentlyContinue
+            Copy-Item "$($releaseDir.FullName)\AutoTrackR2.deps.json" "release\" -ErrorAction SilentlyContinue
+            
+            # Copy resources
+            Copy-Item "$($releaseDir.FullName)\config.ini" "release\" -ErrorAction SilentlyContinue
+            Copy-Item "$($releaseDir.FullName)\themes.json" "release\" -ErrorAction SilentlyContinue
+            Copy-Item "$($releaseDir.FullName)\AutoTrackR2.ico" "release\" -ErrorAction SilentlyContinue
+            
+            # Create directories
+            mkdir "release\Fonts" -ErrorAction SilentlyContinue
+            mkdir "release\Assets" -ErrorAction SilentlyContinue
+            mkdir "release\sounds" -ErrorAction SilentlyContinue
+            mkdir "release\scripts" -ErrorAction SilentlyContinue
+            
+            # Copy directories
+            Copy-Item "$($releaseDir.FullName)\Fonts\*" "release\Fonts\" -Recurse -ErrorAction SilentlyContinue
+            Copy-Item "$($releaseDir.FullName)\Assets\*" "release\Assets\" -Recurse -ErrorAction SilentlyContinue
+            Copy-Item "$($releaseDir.FullName)\sounds\*" "release\sounds\" -Recurse -ErrorAction SilentlyContinue
+            Copy-Item "AutoTrackR2\scripts\*" "release\scripts\" -Recurse -ErrorAction SilentlyContinue
+            
+            # List contents of release directory for verification
+            Write-Host "Contents of release directory:"
+            Get-ChildItem -Path "release" -Recurse | ForEach-Object { Write-Host $_.FullName }
           } else {
             Write-Host "No Release directory found"
+            Get-ChildItem -Recurse -Directory | ForEach-Object { Write-Host $_.FullName }
             exit 1
           }
 
-      - name: Upload application artifact
-        uses: actions/upload-artifact@v4
-        with:
-          name: AutoTrackR2-${{ steps.version.outputs.version }}
-          path: artifacts/
-          retention-days: 5
+      - name: Create zip file
+        run: |
+          Compress-Archive -Path "release\*" -DestinationPath "AutoTrackR2-${{ steps.buildnumber.outputs.version }}.zip" -Force
 
-      - name: Upload visorwipe script
+      - name: Upload release artifact
         uses: actions/upload-artifact@v4
         with:
-          name: visorwipe.ahk
-          path: AutoTrackR2/scripts/visorwipe.ahk
-          retention-days: 5
-
-      - name: Upload videorecord script
-        uses: actions/upload-artifact@v4
-        with:
-          name: videorecord.ahk
-          path: AutoTrackR2/scripts/videorecord.ahk
+          name: AutoTrackR2-${{ steps.buildnumber.outputs.version }}
+          path: AutoTrackR2-${{ steps.buildnumber.outputs.version }}.zip
           retention-days: 5
diff --git a/AutoTrackR2/AutoTrackR2.csproj b/AutoTrackR2/AutoTrackR2.csproj
index 6e88f61..ac8984c 100644
--- a/AutoTrackR2/AutoTrackR2.csproj
+++ b/AutoTrackR2/AutoTrackR2.csproj
@@ -10,6 +10,10 @@
     <Configurations>Debug;Release;Test</Configurations>
     <Platforms>AnyCPU;x64</Platforms>
     <ApplicationIcon>AutoTrackR2.ico</ApplicationIcon>
+    <Version>2.0</Version>
+    <GeneratePackageOnBuild>false</GeneratePackageOnBuild>
+    <GenerateAssemblyInfo>true</GenerateAssemblyInfo>
+    <Deterministic>true</Deterministic>
   </PropertyGroup>
 
   <ItemGroup>
diff --git a/AutoTrackR2/Constants.cs b/AutoTrackR2/Constants.cs
index 14a8c8a..af4cfba 100644
--- a/AutoTrackR2/Constants.cs
+++ b/AutoTrackR2/Constants.cs
@@ -2,5 +2,5 @@ namespace AutoTrackR2.Constants;
 
 public static class AppConstants
 {
-  public const string Version = "2.11";
+  public static string Version => System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "2.0";
 }
\ No newline at end of file
diff --git a/AutoTrackR2/KillHistoryManager.cs b/AutoTrackR2/KillHistoryManager.cs
index abf8b61..a96edd2 100644
--- a/AutoTrackR2/KillHistoryManager.cs
+++ b/AutoTrackR2/KillHistoryManager.cs
@@ -97,7 +97,7 @@ public class KillHistoryManager
         // Check file can be written to
         try
         {
-            using var fileStream = new FileStream(_killHistoryPath, FileMode.Append, FileAccess.Write, FileShare.None);
+            using var fileStream = new FileStream(_killHistoryPath, FileMode.Append, FileAccess.Write, FileShare.Read);
             using var writer = new StreamWriter(fileStream);
             writer.Write(csv.ToString());
 
@@ -123,7 +123,7 @@ public class KillHistoryManager
     {
         var kills = new List<KillData>();
 
-        using var reader = new StreamReader(_killHistoryPath);
+        using var reader = new StreamReader(new FileStream(_killHistoryPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
         reader.ReadLine(); // Skip headers
             
         while (reader.Peek() >= 0)
diff --git a/AutoTrackR2/KillStreakManager.cs b/AutoTrackR2/KillStreakManager.cs
index 98650dd..d85e6ce 100644
--- a/AutoTrackR2/KillStreakManager.cs
+++ b/AutoTrackR2/KillStreakManager.cs
@@ -16,6 +16,7 @@ public class KillStreakManager : IDisposable
   private WaveOutEvent? _waveOut;
   private bool _isPlaying = false;
   private bool _disposed = false;
+  private Task? _currentPlaybackTask;
 
   public KillStreakManager(string soundsPath)
   {
@@ -82,7 +83,7 @@ public class KillStreakManager : IDisposable
       // Only start playing if not already playing
       if (!_isPlaying && _soundQueue.Count > 0)
       {
-        PlayNextSound();
+        _currentPlaybackTask = Task.Run(() => PlayNextSound());
       }
     }
   }
@@ -116,7 +117,14 @@ public class KillStreakManager : IDisposable
   {
     if (_soundQueue.Count == 0 || _disposed) return;
 
-    string soundPath = _soundQueue.Dequeue();
+    string soundPath;
+    lock (_lock)
+    {
+      if (_soundQueue.Count == 0 || _disposed) return;
+      soundPath = _soundQueue.Dequeue();
+      _isPlaying = true;
+    }
+
     Console.WriteLine($"Attempting to play sound: {soundPath}");
 
     try
@@ -124,28 +132,34 @@ public class KillStreakManager : IDisposable
       if (!File.Exists(soundPath))
       {
         Console.WriteLine($"Sound file not found: {soundPath}");
-        _isPlaying = false;
-        if (_soundQueue.Count > 0)
+        lock (_lock)
         {
-          PlayNextSound();
+          _isPlaying = false;
+          if (_soundQueue.Count > 0)
+          {
+            _currentPlaybackTask = Task.Run(() => PlayNextSound());
+          }
         }
         return;
       }
 
       // Stop any currently playing sound
-      _waveOut?.Stop();
-      _waveOut?.Dispose();
-      _waveOut = null;
+      lock (_lock)
+      {
+        _waveOut?.Stop();
+        _waveOut?.Dispose();
+        _waveOut = null;
+      }
 
       // Create a new WaveOutEvent
-      _waveOut = new WaveOutEvent();
+      var waveOut = new WaveOutEvent();
 
       // Create a new AudioFileReader for the MP3 file
       using var audioFile = new AudioFileReader(soundPath);
-      _waveOut.Init(audioFile);
+      waveOut.Init(audioFile);
 
       // Set up event handler for when playback finishes
-      _waveOut.PlaybackStopped += (sender, e) =>
+      waveOut.PlaybackStopped += (sender, e) =>
       {
         lock (_lock)
         {
@@ -154,23 +168,35 @@ public class KillStreakManager : IDisposable
           _isPlaying = false;
           if (_soundQueue.Count > 0)
           {
-            PlayNextSound();
+            _currentPlaybackTask = Task.Run(() => PlayNextSound());
           }
         }
       };
 
-      _isPlaying = true;
-      _waveOut.Play();
+      lock (_lock)
+      {
+        if (_disposed)
+        {
+          waveOut.Dispose();
+          return;
+        }
+        _waveOut = waveOut;
+      }
+
+      waveOut.Play();
 
       Console.WriteLine($"Successfully played sound: {soundPath}");
     }
     catch (Exception ex)
     {
       Console.WriteLine($"Error playing sound {soundPath}: {ex.Message}");
-      _isPlaying = false;
-      if (_soundQueue.Count > 0)
+      lock (_lock)
       {
-        PlayNextSound();
+        _isPlaying = false;
+        if (_soundQueue.Count > 0)
+        {
+          _currentPlaybackTask = Task.Run(() => PlayNextSound());
+        }
       }
     }
   }
@@ -195,6 +221,7 @@ public class KillStreakManager : IDisposable
         _waveOut?.Stop();
         _waveOut?.Dispose();
         _waveOut = null;
+        _currentPlaybackTask?.Wait();
       }
     }
   }