From 60fbaa99ac5c3f634c4be6acc3a36f8de2b7f4bd Mon Sep 17 00:00:00 2001
From: Heavy Bob <ferrettclay@gmail.com>
Date: Mon, 7 Jul 2025 04:01:49 +1000
Subject: [PATCH] Pushing last changes
---
AutoTrackR2/AutoTrackR2.csproj | 10 +-
AutoTrackR2/AutoTrackR2.sln | 24 ++
AutoTrackR2/Constants/Weapons.cs | 10 +-
AutoTrackR2/HomePage.xaml.cs | 29 ++-
AutoTrackR2/KillHistoryManager.cs | 246 +++++++++---------
.../JumpDriveStateChangedEvent.cs | 11 +-
.../RequestJumpFailedEvent.cs | 16 +-
.../LogEventHandlers/VehicleControlEvent.cs | 80 ++++++
.../VehicleDestructionEvent.cs | 63 ++---
AutoTrackR2/LogHandler.cs | 4 +-
AutoTrackR2/TrackREventDispatcher.cs | 18 +-
11 files changed, 328 insertions(+), 183 deletions(-)
create mode 100644 AutoTrackR2/AutoTrackR2.sln
create mode 100644 AutoTrackR2/LogEventHandlers/VehicleControlEvent.cs
diff --git a/AutoTrackR2/AutoTrackR2.csproj b/AutoTrackR2/AutoTrackR2.csproj
index 3110af0..0089026 100644
--- a/AutoTrackR2/AutoTrackR2.csproj
+++ b/AutoTrackR2/AutoTrackR2.csproj
@@ -10,10 +10,14 @@
<Configurations>Debug;Release;Test</Configurations>
<Platforms>AnyCPU;x64</Platforms>
<ApplicationIcon>AutoTrackR2.ico</ApplicationIcon>
- <Version>2.12</Version>
+ <Version>2.13</Version>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
<Deterministic>true</Deterministic>
+ <RuntimeIdentifier>win-x64</RuntimeIdentifier>
+ <SelfContained>false</SelfContained>
+ <PublishSingleFile>true</PublishSingleFile>
+ <IncludeNativeLibrariesForSelfExtract>false</IncludeNativeLibrariesForSelfExtract>
</PropertyGroup>
<ItemGroup>
@@ -48,4 +52,8 @@
</None>
</ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.6" />
+ </ItemGroup>
+
</Project>
diff --git a/AutoTrackR2/AutoTrackR2.sln b/AutoTrackR2/AutoTrackR2.sln
new file mode 100644
index 0000000..eb3096a
--- /dev/null
+++ b/AutoTrackR2/AutoTrackR2.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutoTrackR2", "AutoTrackR2.csproj", "{E22C9485-B9D3-1444-D963-459CE2284B32}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {E22C9485-B9D3-1444-D963-459CE2284B32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E22C9485-B9D3-1444-D963-459CE2284B32}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E22C9485-B9D3-1444-D963-459CE2284B32}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E22C9485-B9D3-1444-D963-459CE2284B32}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {BBD4E112-AC22-4175-9EAB-009EB91E395B}
+ EndGlobalSection
+EndGlobal
diff --git a/AutoTrackR2/Constants/Weapons.cs b/AutoTrackR2/Constants/Weapons.cs
index c3e97d8..3aab4d5 100644
--- a/AutoTrackR2/Constants/Weapons.cs
+++ b/AutoTrackR2/Constants/Weapons.cs
@@ -14,7 +14,15 @@ public static class Weapons
"*repair*",
"*cutter*",
"*tractor*",
- "*carryable*"
+ "*carryable*",
+ "*shotgun*",
+ "*sniper*",
+ "*rifle*",
+ "*smg*",
+ "*pistol*",
+ "*sniper*",
+ "*lmg*",
+ "*volt*",
};
public static bool IsKnownWeapon(string weaponName)
diff --git a/AutoTrackR2/HomePage.xaml.cs b/AutoTrackR2/HomePage.xaml.cs
index b4a8dcf..81a401b 100644
--- a/AutoTrackR2/HomePage.xaml.cs
+++ b/AutoTrackR2/HomePage.xaml.cs
@@ -34,6 +34,9 @@ public partial class HomePage : UserControl
{
InitializeComponent();
+ // Initialize default values
+ LocalPlayerData.PlayerShip = "Player";
+
if (string.IsNullOrEmpty(ConfigManager.KillHistoryFile))
{
throw new InvalidOperationException("KillHistoryFile path is not configured.");
@@ -119,11 +122,11 @@ public partial class HomePage : UserControl
{
// Game is not running, set everything to Unknown
GameModeTextBox.Text = "Unknown";
- PlayerShipTextBox.Text = "Unknown";
+ PlayerShipTextBox.Text = "Player";
PilotNameTextBox.Text = "Unknown";
LocationTextBox.Text = "Unknown";
LocalPlayerData.CurrentGameMode = GameMode.Unknown;
- LocalPlayerData.PlayerShip = string.Empty;
+ LocalPlayerData.PlayerShip = "Player";
LocalPlayerData.Username = string.Empty;
LocalPlayerData.LastSeenVehicleLocation = "Unknown";
@@ -197,6 +200,28 @@ public partial class HomePage : UserControl
});
};
+ // Vehicle Control
+ TrackREventDispatcher.VehicleControlEvent += (data) =>
+ {
+ Dispatcher.Invoke(() =>
+ {
+ PlayerShipTextBox.Text = data.Ship ?? "Player";
+ AdjustFontSize(PlayerShipTextBox);
+ LocalPlayerData.PlayerShip = data.Ship ?? "Player";
+ });
+ };
+
+ // Jump Drive State Changed (Location Only)
+ TrackREventDispatcher.JumpDriveStateChangedEvent += (data) =>
+ {
+ Dispatcher.Invoke(() =>
+ {
+ LocalPlayerData.LastSeenVehicleLocation = data.Location;
+ LocationTextBox.Text = data.Location;
+ AdjustFontSize(LocationTextBox);
+ });
+ };
+
// Game Mode
TrackREventDispatcher.PlayerChangedGameModeEvent += (mode) =>
{
diff --git a/AutoTrackR2/KillHistoryManager.cs b/AutoTrackR2/KillHistoryManager.cs
index 14c1cfb..cb6f63c 100644
--- a/AutoTrackR2/KillHistoryManager.cs
+++ b/AutoTrackR2/KillHistoryManager.cs
@@ -1,4 +1,5 @@
-using System.Globalization;
+using Microsoft.Data.Sqlite;
+using System.Globalization;
using System.IO;
using System.Text;
using System.Linq;
@@ -11,8 +12,7 @@ namespace AutoTrackR2;
public class KillHistoryManager
{
- private readonly 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 string _dbPath;
private readonly KillStreakManager _killStreakManager;
private readonly ConcurrentQueue<KillData> _killQueue;
private readonly CancellationTokenSource _cancellationTokenSource;
@@ -23,13 +23,9 @@ public class KillHistoryManager
{
var appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AutoTrackR2");
Directory.CreateDirectory(appDataPath); // Ensure the directory exists
- _killHistoryPath = Path.Combine(appDataPath, "Kill-log.csv");
+ _dbPath = Path.Combine(appDataPath, "kills.db");
- // Create the CSV file with headers if it doesn't exist
- if (!File.Exists(_killHistoryPath))
- {
- File.WriteAllText(_killHistoryPath, _headers);
- }
+ InitializeDatabase();
_killStreakManager = new KillStreakManager(soundsPath);
_killQueue = new ConcurrentQueue<KillData>();
@@ -39,6 +35,34 @@ public class KillHistoryManager
_processingTask = Task.Run(ProcessKillQueue);
}
+ private void InitializeDatabase()
+ {
+ using var connection = new SqliteConnection($"Data Source={_dbPath}");
+ connection.Open();
+ var command = connection.CreateCommand();
+ command.CommandText = @"
+ CREATE TABLE IF NOT EXISTS kills (
+ Hash TEXT PRIMARY KEY,
+ KillTime TEXT,
+ EnemyPilot TEXT,
+ EnemyShip TEXT,
+ Enlisted TEXT,
+ RecordNumber TEXT,
+ OrgAffiliation TEXT,
+ Weapon TEXT,
+ Ship TEXT,
+ Method TEXT,
+ Location TEXT,
+ Mode TEXT,
+ GameVersion TEXT,
+ TrackRver TEXT,
+ Logged TEXT,
+ PFP TEXT
+ );
+ ";
+ command.ExecuteNonQuery();
+ }
+
private async Task ProcessKillQueue()
{
while (!_cancellationTokenSource.Token.IsCancellationRequested)
@@ -70,56 +94,41 @@ public class KillHistoryManager
{
try
{
- // Ensure all fields are properly escaped for CSV
- var fields = new[]
- {
- kill.KillTime.ToString(),
- EscapeCsvField(kill.EnemyPilot),
- EscapeCsvField(kill.EnemyShip),
- EscapeCsvField(kill.Enlisted),
- EscapeCsvField(kill.RecordNumber),
- EscapeCsvField(kill.OrgAffiliation),
- EscapeCsvField(kill.Player),
- EscapeCsvField(kill.Weapon),
- EscapeCsvField(kill.Ship),
- EscapeCsvField(kill.Method),
- EscapeCsvField(kill.Mode),
- EscapeCsvField(kill.GameVersion),
- EscapeCsvField(kill.TrackRver),
- EscapeCsvField(kill.Logged),
- EscapeCsvField(kill.PFP),
- EscapeCsvField(kill.Hash)
- };
-
- var csvLine = string.Join(",", fields);
-
- // Use FileShare.Read to allow other processes to read while we write
- using var stream = new FileStream(_killHistoryPath, FileMode.Append, FileAccess.Write, FileShare.Read);
- using var writer = new StreamWriter(stream);
- await writer.WriteLineAsync(csvLine);
+ using var connection = new SqliteConnection($"Data Source={_dbPath}");
+ await connection.OpenAsync();
+ var command = connection.CreateCommand();
+ command.CommandText = @"
+ INSERT OR IGNORE INTO kills (
+ Hash, KillTime, EnemyPilot, EnemyShip, Enlisted, RecordNumber, OrgAffiliation, Weapon, Ship, Method, Location, Mode, GameVersion, TrackRver, Logged, PFP
+ ) VALUES (
+ $Hash, $KillTime, $EnemyPilot, $EnemyShip, $Enlisted, $RecordNumber, $OrgAffiliation, $Weapon, $Ship, $Method, $Location, $Mode, $GameVersion, $TrackRver, $Logged, $PFP
+ );
+ ";
+ command.Parameters.AddWithValue("$Hash", kill.Hash ?? "");
+ command.Parameters.AddWithValue("$KillTime", kill.KillTime ?? "");
+ command.Parameters.AddWithValue("$EnemyPilot", kill.EnemyPilot ?? "");
+ command.Parameters.AddWithValue("$EnemyShip", kill.EnemyShip ?? "");
+ command.Parameters.AddWithValue("$Enlisted", kill.Enlisted ?? "");
+ command.Parameters.AddWithValue("$RecordNumber", kill.RecordNumber ?? "");
+ command.Parameters.AddWithValue("$OrgAffiliation", kill.OrgAffiliation ?? "");
+ command.Parameters.AddWithValue("$Weapon", kill.Weapon ?? "");
+ command.Parameters.AddWithValue("$Ship", kill.Ship ?? "");
+ command.Parameters.AddWithValue("$Method", kill.Method ?? "");
+ command.Parameters.AddWithValue("$Location", kill.Location ?? "");
+ command.Parameters.AddWithValue("$Mode", kill.Mode ?? "");
+ command.Parameters.AddWithValue("$GameVersion", kill.GameVersion ?? "");
+ command.Parameters.AddWithValue("$TrackRver", kill.TrackRver ?? "");
+ command.Parameters.AddWithValue("$Logged", kill.Logged ?? "");
+ command.Parameters.AddWithValue("$PFP", kill.PFP ?? "");
+ await command.ExecuteNonQueryAsync();
}
catch (Exception ex)
{
- Debug.WriteLine($"Error writing kill to CSV: {ex.Message}");
+ Debug.WriteLine($"Error writing kill to SQLite: {ex.Message}");
throw;
}
}
- private string EscapeCsvField(string field)
- {
- if (string.IsNullOrEmpty(field)) return "";
-
- // If the field contains any special characters, wrap it in quotes
- if (field.Contains(",") || field.Contains("\"") || field.Contains("\n") || field.Contains("\r"))
- {
- // Double up any quotes
- field = field.Replace("\"", "\"\"");
- return $"\"{field}\"";
- }
-
- return field;
- }
-
public void AddKill(KillData kill)
{
_killQueue.Enqueue(kill);
@@ -145,47 +154,38 @@ public class KillHistoryManager
public List<KillData> GetKills()
{
var kills = new List<KillData>();
-
- using var reader = new StreamReader(new FileStream(_killHistoryPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
- reader.ReadLine(); // Skip headers
-
- while (reader.Peek() >= 0)
+ using var connection = new SqliteConnection($"Data Source={_dbPath}");
+ connection.Open();
+ var command = connection.CreateCommand();
+ command.CommandText = "SELECT Hash, KillTime, EnemyPilot, EnemyShip, Enlisted, RecordNumber, OrgAffiliation, Weapon, Ship, Method, Location, Mode, GameVersion, TrackRver, Logged, PFP FROM kills";
+ using var reader = command.ExecuteReader();
+ while (reader.Read())
{
- var line = reader.ReadLine();
-
- // Remove extra quotes from CSV data
- // Todo: These quotes are for handling commas in the data, but not sure if they're necessary
- line = line?.Replace("\"", string.Empty);
-
- var data = line?.Split(',');
-
kills.Add(new KillData
{
- KillTime = data?[0],
- EnemyPilot = data?[1],
- EnemyShip = data?[2],
- Enlisted = data?[3],
- RecordNumber = data?[4],
- OrgAffiliation = data?[5],
- Player = data?[6],
- Weapon = data?[7],
- Ship = data?[8],
- Method = data?[9],
- Mode = data?[10],
- GameVersion = data?[11],
- TrackRver = data?[12],
- Logged = data?[13],
- PFP = data?[14],
- Hash = data?[15]
+ Hash = reader.GetString(0),
+ KillTime = reader.GetString(1),
+ EnemyPilot = reader.GetString(2),
+ EnemyShip = reader.GetString(3),
+ Enlisted = reader.GetString(4),
+ RecordNumber = reader.GetString(5),
+ OrgAffiliation = reader.GetString(6),
+ Weapon = reader.GetString(7),
+ Ship = reader.GetString(8),
+ Method = reader.GetString(9),
+ Location = reader.GetString(10),
+ Mode = reader.GetString(11),
+ GameVersion = reader.GetString(12),
+ TrackRver = reader.GetString(13),
+ Logged = reader.GetString(14),
+ PFP = reader.GetString(15)
});
}
-
// Apply KillFeedLimit if specified
if (ConfigManager.KillFeedLimit.HasValue && ConfigManager.KillFeedLimit.Value > 0)
{
kills = kills.TakeLast(ConfigManager.KillFeedLimit.Value).ToList();
}
-
return kills;
}
@@ -193,57 +193,45 @@ public class KillHistoryManager
{
string currentMonth = DateTime.Now.ToString("MMM", CultureInfo.InvariantCulture);
var kills = new List<KillData>();
-
- // Read all kills directly from file, ignoring KillFeedLimit
- using var reader = new StreamReader(new FileStream(_killHistoryPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
- reader.ReadLine(); // Skip headers
-
- while (reader.Peek() >= 0)
+ using var connection = new SqliteConnection($"Data Source={_dbPath}");
+ connection.Open();
+ var command = connection.CreateCommand();
+ command.CommandText = "SELECT Hash, KillTime, EnemyPilot, EnemyShip, Enlisted, RecordNumber, OrgAffiliation, Weapon, Ship, Method, Location, Mode, GameVersion, TrackRver, Logged, PFP FROM kills";
+ using var reader = command.ExecuteReader();
+ while (reader.Read())
{
- var line = reader.ReadLine();
-
- // Remove extra quotes from CSV data
- line = line?.Replace("\"", string.Empty);
-
- var data = line?.Split(',');
-
+ var kill = new KillData
+ {
+ Hash = reader.GetString(0),
+ KillTime = reader.GetString(1),
+ EnemyPilot = reader.GetString(2),
+ EnemyShip = reader.GetString(3),
+ Enlisted = reader.GetString(4),
+ RecordNumber = reader.GetString(5),
+ OrgAffiliation = reader.GetString(6),
+ Weapon = reader.GetString(7),
+ Ship = reader.GetString(8),
+ Method = reader.GetString(9),
+ Location = reader.GetString(10),
+ Mode = reader.GetString(11),
+ GameVersion = reader.GetString(12),
+ TrackRver = reader.GetString(13),
+ Logged = reader.GetString(14),
+ PFP = reader.GetString(15)
+ };
// Check if the kill is from the current month before adding it
- var killTime = data?[0];
- if (string.IsNullOrEmpty(killTime)) continue;
-
- // Try to parse as Unix timestamp first
- if (long.TryParse(killTime, out long unixTime))
+ if (!string.IsNullOrEmpty(kill.KillTime))
{
- var date = DateTimeOffset.FromUnixTimeSeconds(unixTime);
- if (date.ToString("MMM", CultureInfo.InvariantCulture) != currentMonth) continue;
+ if (long.TryParse(kill.KillTime, out long unixTime))
+ {
+ var date = DateTimeOffset.FromUnixTimeSeconds(unixTime).DateTime;
+ if (date.ToString("MMM", CultureInfo.InvariantCulture) == currentMonth)
+ {
+ kills.Add(kill);
+ }
+ }
}
- else if (!killTime.Contains(currentMonth))
- {
- // Fall back to checking if it contains the month name (old format)
- continue;
- }
-
- kills.Add(new KillData
- {
- KillTime = killTime,
- EnemyPilot = data?[1],
- EnemyShip = data?[2],
- Enlisted = data?[3],
- RecordNumber = data?[4],
- OrgAffiliation = data?[5],
- Player = data?[6],
- Weapon = data?[7],
- Ship = data?[8],
- Method = data?[9],
- Mode = data?[10],
- GameVersion = data?[11],
- TrackRver = data?[12],
- Logged = data?[13],
- PFP = data?[14],
- Hash = data?[15]
- });
}
-
return kills;
}
}
\ No newline at end of file
diff --git a/AutoTrackR2/LogEventHandlers/JumpDriveStateChangedEvent.cs b/AutoTrackR2/LogEventHandlers/JumpDriveStateChangedEvent.cs
index 2adf26f..01135d7 100644
--- a/AutoTrackR2/LogEventHandlers/JumpDriveStateChangedEvent.cs
+++ b/AutoTrackR2/LogEventHandlers/JumpDriveStateChangedEvent.cs
@@ -12,12 +12,12 @@ public class JumpDriveStateChangedEvent : ILogEventHandler
{
public Regex Pattern { get; }
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
-
+
public JumpDriveStateChangedEvent()
{
Pattern = new Regex(@"<Jump Drive State Changed>.*.adam: (?<ShipName>.*.) in zone (?<Location>.*.)\)");
}
-
+
public void Handle(LogEntry entry)
{
if (entry.Message is null) return;
@@ -34,6 +34,13 @@ public class JumpDriveStateChangedEvent : ILogEventHandler
{
data.ShipName = match.Groups[1].Value;
}
+
+ // Skip applying loadout if ship name matches "Default"
+ if (data.ShipName?.Equals("Default", StringComparison.OrdinalIgnoreCase) == true)
+ {
+ return;
+ }
+
if (!string.IsNullOrEmpty(data.ShipName) && !string.IsNullOrEmpty(data.Location))
{
TrackREventDispatcher.OnJumpDriveStateChangedEvent(data);
diff --git a/AutoTrackR2/LogEventHandlers/RequestJumpFailedEvent.cs b/AutoTrackR2/LogEventHandlers/RequestJumpFailedEvent.cs
index aaef3e3..b096992 100644
--- a/AutoTrackR2/LogEventHandlers/RequestJumpFailedEvent.cs
+++ b/AutoTrackR2/LogEventHandlers/RequestJumpFailedEvent.cs
@@ -6,29 +6,35 @@ public class RequestJumpFailedEvent : ILogEventHandler
{
public Regex Pattern { get; }
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
-
+
public RequestJumpFailedEvent()
{
Pattern = new Regex(@"<Request Jump Failed>.*.adam: (?<ShipName>.*.) in zone (?<Location>.*.)\)");
}
-
+
public void Handle(LogEntry entry)
{
if (entry.Message is null) return;
var match = Pattern.Match(entry.Message);
if (!match.Success) return;
-
+
var data = new JumpDriveStateChangedData
{
Location = match.Groups["Location"].Value
};
-
+
match = _cleanUpPattern.Match(match.Groups["ShipName"].Value);
if (match.Success)
{
data.ShipName = match.Groups[1].Value;
}
-
+
+ // Skip applying loadout if ship name matches "Default"
+ if (data.ShipName?.Equals("Default", StringComparison.OrdinalIgnoreCase) == true)
+ {
+ return;
+ }
+
if (!string.IsNullOrEmpty(data.ShipName) && !string.IsNullOrEmpty(data.Location))
{
TrackREventDispatcher.OnJumpDriveStateChangedEvent(data);
diff --git a/AutoTrackR2/LogEventHandlers/VehicleControlEvent.cs b/AutoTrackR2/LogEventHandlers/VehicleControlEvent.cs
new file mode 100644
index 0000000..60ed34f
--- /dev/null
+++ b/AutoTrackR2/LogEventHandlers/VehicleControlEvent.cs
@@ -0,0 +1,80 @@
+using System.Text.RegularExpressions;
+using AutoTrackR2.Constants;
+
+namespace AutoTrackR2.LogEventHandlers;
+
+public struct VehicleControlData
+{
+ public string Action { get; set; } // "SetDriver" or "ClearDriver"
+ public string VehicleName { get; set; }
+ public string? Ship { get; set; }
+}
+
+public class VehicleControlEvent : ILogEventHandler
+{
+ public Regex Pattern { get; }
+ private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
+
+ public VehicleControlEvent()
+ {
+ // Pattern for entering vehicle (granted control)
+ Pattern = new Regex(@"granted control token for '(?<vehicle_name>[^']+)'", RegexOptions.Compiled);
+ }
+
+ public void Handle(LogEntry entry)
+ {
+ if (entry.Message is null) return;
+
+ // Check for vehicle entry (granted control)
+ var enterMatch = Pattern.Match(entry.Message);
+ if (enterMatch.Success)
+ {
+ var vehicleName = enterMatch.Groups["vehicle_name"].Value;
+ var cleanedShipName = CleanShipName(vehicleName);
+ LocalPlayerData.PlayerShip = cleanedShipName;
+ var data = new VehicleControlData
+ {
+ Action = "SetDriver",
+ VehicleName = vehicleName,
+ Ship = cleanedShipName
+ };
+ TrackREventDispatcher.OnVehicleControlEvent(data);
+ return;
+ }
+ }
+
+ private string CleanShipName(string vehicleName)
+ {
+ var cleanMatch = _cleanUpPattern.Match(vehicleName);
+ return cleanMatch.Success ? cleanMatch.Groups[1].Value : vehicleName;
+ }
+}
+
+public class VehicleControlClearEvent : ILogEventHandler
+{
+ public Regex Pattern { get; }
+
+ public VehicleControlClearEvent()
+ {
+ // Pattern for exiting vehicle (releasing control)
+ Pattern = new Regex(@"releasing control token", RegexOptions.Compiled);
+ }
+
+ public void Handle(LogEntry entry)
+ {
+ if (entry.Message is null) return;
+
+ var match = Pattern.Match(entry.Message);
+ if (match.Success)
+ {
+ LocalPlayerData.PlayerShip = "Player";
+ var data = new VehicleControlData
+ {
+ Action = "ClearDriver",
+ VehicleName = "Player",
+ Ship = "Player"
+ };
+ TrackREventDispatcher.OnVehicleControlEvent(data);
+ }
+ }
+}
\ No newline at end of file
diff --git a/AutoTrackR2/LogEventHandlers/VehicleDestructionEvent.cs b/AutoTrackR2/LogEventHandlers/VehicleDestructionEvent.cs
index 47b808a..1af55b6 100644
--- a/AutoTrackR2/LogEventHandlers/VehicleDestructionEvent.cs
+++ b/AutoTrackR2/LogEventHandlers/VehicleDestructionEvent.cs
@@ -1,64 +1,55 @@
using System.Text.RegularExpressions;
+using AutoTrackR2.Constants;
namespace AutoTrackR2.LogEventHandlers;
public struct VehicleDestructionData
{
- public string Vehicle { get; set; }
+ public string VehicleName { get; set; }
+ public string VehicleId { get; set; }
+ public string Team { get; set; }
public string VehicleZone { get; set; }
- public float PosX { get; set; }
- public float PosY { get; set; }
- public float PosZ { get; set; }
- public string Driver { get; set; }
- public int DestroyLevelFrom { get; set; }
- public int DestroyLevelTo { get; set; }
- public string CausedBy { get; set; }
- public string DamageType { get; set; }
+ public string? Ship { get; set; }
}
public class VehicleDestructionEvent : ILogEventHandler
{
public Regex Pattern { get; }
+ private Regex _shipManufacturerPattern;
+ private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
+
public VehicleDestructionEvent()
{
- const string patternStr = """
- <(?<timestamp>[^>]+)> \[Notice\] <Vehicle Destruction> CVehicle::OnAdvanceDestroyLevel:
- Vehicle '(?<vehicle>[^']+)' \[\d+\] in zone '(?<vehicle_zone>[^']+)'
- \[pos x: (?<pos_x>[-\d\.]+), y: (?<pos_y>[-\d\.]+), z: (?<pos_z>[-\d\.]+)
- vel x: [^,]+, y: [^,]+, z: [^\]]+\] driven by '(?<driver>[^']+)' \[\d+\]
- advanced from destroy level (?<destroy_level_from>\d+) to (?<destroy_level_to>\d+)
- caused by '(?<caused_by>[^']+)' \[\d+\] with '(?<damage_type>[^']+)'
- """;
-
- Pattern = new Regex(Regex.Replace(patternStr, @"\t|\n|\r", ""));
+ Pattern = new Regex(@"<Vehicle Destruction> Vehicle '(?<vehicle_name>[^']+)' \[(?<vehicle_id>\d+)\] \[(?<team>[^\]]+)\] in zone '(?<vehicle_zone>[^']+)' has been destroyed");
+ _shipManufacturerPattern = new Regex($"^({string.Join("|", ShipManufacturers.List)})");
}
public void Handle(LogEntry entry)
{
- if (entry.Message == null)
- {
- return;
- }
+ if (entry.Message is null) return;
+
var match = Pattern.Match(entry.Message);
- if (!match.Success)
- {
- return;
- }
+ if (!match.Success) return;
var data = new VehicleDestructionData
{
- Vehicle = match.Groups["vehicle"].Value,
+ VehicleName = match.Groups["vehicle_name"].Value,
+ VehicleId = match.Groups["vehicle_id"].Value,
+ Team = match.Groups["team"].Value,
VehicleZone = match.Groups["vehicle_zone"].Value,
- PosX = float.Parse(match.Groups["pos_x"].Value),
- PosY = float.Parse(match.Groups["pos_y"].Value),
- PosZ = float.Parse(match.Groups["pos_z"].Value),
- Driver = match.Groups["driver"].Value,
- DestroyLevelFrom = int.Parse(match.Groups["destroy_level_from"].Value),
- DestroyLevelTo = int.Parse(match.Groups["destroy_level_to"].Value),
- CausedBy = match.Groups["caused_by"].Value,
- DamageType = match.Groups["damage_type"].Value,
};
+ // Extract ship name from vehicle name if it's a ship
+ var shipMatch = _shipManufacturerPattern.Match(data.VehicleName);
+ if (shipMatch.Success)
+ {
+ var cleanMatch = _cleanUpPattern.Match(data.VehicleName);
+ if (cleanMatch.Success)
+ {
+ data.Ship = cleanMatch.Groups[1].Value;
+ }
+ }
+
TrackREventDispatcher.OnVehicleDestructionEvent(data);
}
}
\ No newline at end of file
diff --git a/AutoTrackR2/LogHandler.cs b/AutoTrackR2/LogHandler.cs
index c8da3c7..79f5b20 100644
--- a/AutoTrackR2/LogHandler.cs
+++ b/AutoTrackR2/LogHandler.cs
@@ -47,7 +47,9 @@ public class LogHandler
new JumpDriveStateChangedEvent(),
new RequestJumpFailedEvent(),
new VehicleDestructionEvent(),
- new ActorDeathEvent()
+ new ActorDeathEvent(),
+ new VehicleControlEvent(),
+ new VehicleControlClearEvent()
];
public LogHandler(string? logPath)
diff --git a/AutoTrackR2/TrackREventDispatcher.cs b/AutoTrackR2/TrackREventDispatcher.cs
index 36823ac..cf51a88 100644
--- a/AutoTrackR2/TrackREventDispatcher.cs
+++ b/AutoTrackR2/TrackREventDispatcher.cs
@@ -18,37 +18,36 @@ public static class TrackREventDispatcher
{
InstancedInteriorEvent?.Invoke(data);
}
-
+
// Player changed GameMode (AC or PU)
public static event Action<GameMode>? PlayerChangedGameModeEvent;
public static void OnPlayerChangedGameModeEvent(GameMode mode)
{
PlayerChangedGameModeEvent?.Invoke(mode);
}
-
+
// Game version has been detected
public static event Action<string>? GameVersionEvent;
public static void OnGameVersionEvent(string value)
{
GameVersionEvent?.Invoke(value);
}
-
+
// Actor has died
public static event Action<ActorDeathData>? ActorDeathEvent;
public static void OnActorDeathEvent(ActorDeathData data)
{
ActorDeathEvent?.Invoke(data);
}
-
+
// Vehicle has been destroyed
public static event Action<VehicleDestructionData>? VehicleDestructionEvent;
public static void OnVehicleDestructionEvent(VehicleDestructionData data)
{
VehicleDestructionEvent?.Invoke(data);
}
-
+
// Jump Drive state has changed
- // Todo: Add proper data for this event. Right now only ship name is used.
public static event Action<JumpDriveStateChangedData>? JumpDriveStateChangedEvent;
public static void OnJumpDriveStateChangedEvent(JumpDriveStateChangedData data)
{
@@ -61,4 +60,11 @@ public static class TrackREventDispatcher
{
StreamlinkRecordEvent?.Invoke(streamerHandle);
}
+
+ // Vehicle control has changed
+ public static event Action<VehicleControlData>? VehicleControlEvent;
+ public static void OnVehicleControlEvent(VehicleControlData data)
+ {
+ VehicleControlEvent?.Invoke(data);
+ }
}
\ No newline at end of file