mirror of
https://github.com/BubbaGumpShrump/AutoTrackR2.git
synced 2025-08-25 10:58:48 +00:00
Pushing last changes
This commit is contained in:
parent
0f97d758f8
commit
60fbaa99ac
11 changed files with 328 additions and 183 deletions
|
@ -10,10 +10,14 @@
|
||||||
<Configurations>Debug;Release;Test</Configurations>
|
<Configurations>Debug;Release;Test</Configurations>
|
||||||
<Platforms>AnyCPU;x64</Platforms>
|
<Platforms>AnyCPU;x64</Platforms>
|
||||||
<ApplicationIcon>AutoTrackR2.ico</ApplicationIcon>
|
<ApplicationIcon>AutoTrackR2.ico</ApplicationIcon>
|
||||||
<Version>2.12</Version>
|
<Version>2.13</Version>
|
||||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
|
||||||
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
<GenerateAssemblyInfo>true</GenerateAssemblyInfo>
|
||||||
<Deterministic>true</Deterministic>
|
<Deterministic>true</Deterministic>
|
||||||
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<SelfContained>false</SelfContained>
|
||||||
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
<IncludeNativeLibrariesForSelfExtract>false</IncludeNativeLibrariesForSelfExtract>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -48,4 +52,8 @@
|
||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="9.0.6" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
24
AutoTrackR2/AutoTrackR2.sln
Normal file
24
AutoTrackR2/AutoTrackR2.sln
Normal file
|
@ -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
|
|
@ -14,7 +14,15 @@ public static class Weapons
|
||||||
"*repair*",
|
"*repair*",
|
||||||
"*cutter*",
|
"*cutter*",
|
||||||
"*tractor*",
|
"*tractor*",
|
||||||
"*carryable*"
|
"*carryable*",
|
||||||
|
"*shotgun*",
|
||||||
|
"*sniper*",
|
||||||
|
"*rifle*",
|
||||||
|
"*smg*",
|
||||||
|
"*pistol*",
|
||||||
|
"*sniper*",
|
||||||
|
"*lmg*",
|
||||||
|
"*volt*",
|
||||||
};
|
};
|
||||||
|
|
||||||
public static bool IsKnownWeapon(string weaponName)
|
public static bool IsKnownWeapon(string weaponName)
|
||||||
|
|
|
@ -34,6 +34,9 @@ public partial class HomePage : UserControl
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
// Initialize default values
|
||||||
|
LocalPlayerData.PlayerShip = "Player";
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ConfigManager.KillHistoryFile))
|
if (string.IsNullOrEmpty(ConfigManager.KillHistoryFile))
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("KillHistoryFile path is not configured.");
|
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
|
// Game is not running, set everything to Unknown
|
||||||
GameModeTextBox.Text = "Unknown";
|
GameModeTextBox.Text = "Unknown";
|
||||||
PlayerShipTextBox.Text = "Unknown";
|
PlayerShipTextBox.Text = "Player";
|
||||||
PilotNameTextBox.Text = "Unknown";
|
PilotNameTextBox.Text = "Unknown";
|
||||||
LocationTextBox.Text = "Unknown";
|
LocationTextBox.Text = "Unknown";
|
||||||
LocalPlayerData.CurrentGameMode = GameMode.Unknown;
|
LocalPlayerData.CurrentGameMode = GameMode.Unknown;
|
||||||
LocalPlayerData.PlayerShip = string.Empty;
|
LocalPlayerData.PlayerShip = "Player";
|
||||||
LocalPlayerData.Username = string.Empty;
|
LocalPlayerData.Username = string.Empty;
|
||||||
LocalPlayerData.LastSeenVehicleLocation = "Unknown";
|
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
|
// Game Mode
|
||||||
TrackREventDispatcher.PlayerChangedGameModeEvent += (mode) =>
|
TrackREventDispatcher.PlayerChangedGameModeEvent += (mode) =>
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
using System.Globalization;
|
using Microsoft.Data.Sqlite;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -11,8 +12,7 @@ namespace AutoTrackR2;
|
||||||
|
|
||||||
public class KillHistoryManager
|
public class KillHistoryManager
|
||||||
{
|
{
|
||||||
private readonly string _killHistoryPath;
|
private readonly string _dbPath;
|
||||||
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;
|
private readonly KillStreakManager _killStreakManager;
|
||||||
private readonly ConcurrentQueue<KillData> _killQueue;
|
private readonly ConcurrentQueue<KillData> _killQueue;
|
||||||
private readonly CancellationTokenSource _cancellationTokenSource;
|
private readonly CancellationTokenSource _cancellationTokenSource;
|
||||||
|
@ -23,13 +23,9 @@ public class KillHistoryManager
|
||||||
{
|
{
|
||||||
var appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AutoTrackR2");
|
var appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "AutoTrackR2");
|
||||||
Directory.CreateDirectory(appDataPath); // Ensure the directory exists
|
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
|
InitializeDatabase();
|
||||||
if (!File.Exists(_killHistoryPath))
|
|
||||||
{
|
|
||||||
File.WriteAllText(_killHistoryPath, _headers);
|
|
||||||
}
|
|
||||||
|
|
||||||
_killStreakManager = new KillStreakManager(soundsPath);
|
_killStreakManager = new KillStreakManager(soundsPath);
|
||||||
_killQueue = new ConcurrentQueue<KillData>();
|
_killQueue = new ConcurrentQueue<KillData>();
|
||||||
|
@ -39,6 +35,34 @@ public class KillHistoryManager
|
||||||
_processingTask = Task.Run(ProcessKillQueue);
|
_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()
|
private async Task ProcessKillQueue()
|
||||||
{
|
{
|
||||||
while (!_cancellationTokenSource.Token.IsCancellationRequested)
|
while (!_cancellationTokenSource.Token.IsCancellationRequested)
|
||||||
|
@ -70,56 +94,41 @@ public class KillHistoryManager
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Ensure all fields are properly escaped for CSV
|
using var connection = new SqliteConnection($"Data Source={_dbPath}");
|
||||||
var fields = new[]
|
await connection.OpenAsync();
|
||||||
{
|
var command = connection.CreateCommand();
|
||||||
kill.KillTime.ToString(),
|
command.CommandText = @"
|
||||||
EscapeCsvField(kill.EnemyPilot),
|
INSERT OR IGNORE INTO kills (
|
||||||
EscapeCsvField(kill.EnemyShip),
|
Hash, KillTime, EnemyPilot, EnemyShip, Enlisted, RecordNumber, OrgAffiliation, Weapon, Ship, Method, Location, Mode, GameVersion, TrackRver, Logged, PFP
|
||||||
EscapeCsvField(kill.Enlisted),
|
) VALUES (
|
||||||
EscapeCsvField(kill.RecordNumber),
|
$Hash, $KillTime, $EnemyPilot, $EnemyShip, $Enlisted, $RecordNumber, $OrgAffiliation, $Weapon, $Ship, $Method, $Location, $Mode, $GameVersion, $TrackRver, $Logged, $PFP
|
||||||
EscapeCsvField(kill.OrgAffiliation),
|
);
|
||||||
EscapeCsvField(kill.Player),
|
";
|
||||||
EscapeCsvField(kill.Weapon),
|
command.Parameters.AddWithValue("$Hash", kill.Hash ?? "");
|
||||||
EscapeCsvField(kill.Ship),
|
command.Parameters.AddWithValue("$KillTime", kill.KillTime ?? "");
|
||||||
EscapeCsvField(kill.Method),
|
command.Parameters.AddWithValue("$EnemyPilot", kill.EnemyPilot ?? "");
|
||||||
EscapeCsvField(kill.Mode),
|
command.Parameters.AddWithValue("$EnemyShip", kill.EnemyShip ?? "");
|
||||||
EscapeCsvField(kill.GameVersion),
|
command.Parameters.AddWithValue("$Enlisted", kill.Enlisted ?? "");
|
||||||
EscapeCsvField(kill.TrackRver),
|
command.Parameters.AddWithValue("$RecordNumber", kill.RecordNumber ?? "");
|
||||||
EscapeCsvField(kill.Logged),
|
command.Parameters.AddWithValue("$OrgAffiliation", kill.OrgAffiliation ?? "");
|
||||||
EscapeCsvField(kill.PFP),
|
command.Parameters.AddWithValue("$Weapon", kill.Weapon ?? "");
|
||||||
EscapeCsvField(kill.Hash)
|
command.Parameters.AddWithValue("$Ship", kill.Ship ?? "");
|
||||||
};
|
command.Parameters.AddWithValue("$Method", kill.Method ?? "");
|
||||||
|
command.Parameters.AddWithValue("$Location", kill.Location ?? "");
|
||||||
var csvLine = string.Join(",", fields);
|
command.Parameters.AddWithValue("$Mode", kill.Mode ?? "");
|
||||||
|
command.Parameters.AddWithValue("$GameVersion", kill.GameVersion ?? "");
|
||||||
// Use FileShare.Read to allow other processes to read while we write
|
command.Parameters.AddWithValue("$TrackRver", kill.TrackRver ?? "");
|
||||||
using var stream = new FileStream(_killHistoryPath, FileMode.Append, FileAccess.Write, FileShare.Read);
|
command.Parameters.AddWithValue("$Logged", kill.Logged ?? "");
|
||||||
using var writer = new StreamWriter(stream);
|
command.Parameters.AddWithValue("$PFP", kill.PFP ?? "");
|
||||||
await writer.WriteLineAsync(csvLine);
|
await command.ExecuteNonQueryAsync();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Debug.WriteLine($"Error writing kill to CSV: {ex.Message}");
|
Debug.WriteLine($"Error writing kill to SQLite: {ex.Message}");
|
||||||
throw;
|
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)
|
public void AddKill(KillData kill)
|
||||||
{
|
{
|
||||||
_killQueue.Enqueue(kill);
|
_killQueue.Enqueue(kill);
|
||||||
|
@ -145,47 +154,38 @@ public class KillHistoryManager
|
||||||
public List<KillData> GetKills()
|
public List<KillData> GetKills()
|
||||||
{
|
{
|
||||||
var kills = new List<KillData>();
|
var kills = new List<KillData>();
|
||||||
|
using var connection = new SqliteConnection($"Data Source={_dbPath}");
|
||||||
using var reader = new StreamReader(new FileStream(_killHistoryPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
|
connection.Open();
|
||||||
reader.ReadLine(); // Skip headers
|
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";
|
||||||
while (reader.Peek() >= 0)
|
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
|
kills.Add(new KillData
|
||||||
{
|
{
|
||||||
KillTime = data?[0],
|
Hash = reader.GetString(0),
|
||||||
EnemyPilot = data?[1],
|
KillTime = reader.GetString(1),
|
||||||
EnemyShip = data?[2],
|
EnemyPilot = reader.GetString(2),
|
||||||
Enlisted = data?[3],
|
EnemyShip = reader.GetString(3),
|
||||||
RecordNumber = data?[4],
|
Enlisted = reader.GetString(4),
|
||||||
OrgAffiliation = data?[5],
|
RecordNumber = reader.GetString(5),
|
||||||
Player = data?[6],
|
OrgAffiliation = reader.GetString(6),
|
||||||
Weapon = data?[7],
|
Weapon = reader.GetString(7),
|
||||||
Ship = data?[8],
|
Ship = reader.GetString(8),
|
||||||
Method = data?[9],
|
Method = reader.GetString(9),
|
||||||
Mode = data?[10],
|
Location = reader.GetString(10),
|
||||||
GameVersion = data?[11],
|
Mode = reader.GetString(11),
|
||||||
TrackRver = data?[12],
|
GameVersion = reader.GetString(12),
|
||||||
Logged = data?[13],
|
TrackRver = reader.GetString(13),
|
||||||
PFP = data?[14],
|
Logged = reader.GetString(14),
|
||||||
Hash = data?[15]
|
PFP = reader.GetString(15)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply KillFeedLimit if specified
|
// Apply KillFeedLimit if specified
|
||||||
if (ConfigManager.KillFeedLimit.HasValue && ConfigManager.KillFeedLimit.Value > 0)
|
if (ConfigManager.KillFeedLimit.HasValue && ConfigManager.KillFeedLimit.Value > 0)
|
||||||
{
|
{
|
||||||
kills = kills.TakeLast(ConfigManager.KillFeedLimit.Value).ToList();
|
kills = kills.TakeLast(ConfigManager.KillFeedLimit.Value).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return kills;
|
return kills;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,57 +193,45 @@ public class KillHistoryManager
|
||||||
{
|
{
|
||||||
string currentMonth = DateTime.Now.ToString("MMM", CultureInfo.InvariantCulture);
|
string currentMonth = DateTime.Now.ToString("MMM", CultureInfo.InvariantCulture);
|
||||||
var kills = new List<KillData>();
|
var kills = new List<KillData>();
|
||||||
|
using var connection = new SqliteConnection($"Data Source={_dbPath}");
|
||||||
// Read all kills directly from file, ignoring KillFeedLimit
|
connection.Open();
|
||||||
using var reader = new StreamReader(new FileStream(_killHistoryPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite));
|
var command = connection.CreateCommand();
|
||||||
reader.ReadLine(); // Skip headers
|
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.Peek() >= 0)
|
while (reader.Read())
|
||||||
{
|
{
|
||||||
var line = reader.ReadLine();
|
var kill = new KillData
|
||||||
|
{
|
||||||
// Remove extra quotes from CSV data
|
Hash = reader.GetString(0),
|
||||||
line = line?.Replace("\"", string.Empty);
|
KillTime = reader.GetString(1),
|
||||||
|
EnemyPilot = reader.GetString(2),
|
||||||
var data = line?.Split(',');
|
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
|
// Check if the kill is from the current month before adding it
|
||||||
var killTime = data?[0];
|
if (!string.IsNullOrEmpty(kill.KillTime))
|
||||||
if (string.IsNullOrEmpty(killTime)) continue;
|
|
||||||
|
|
||||||
// Try to parse as Unix timestamp first
|
|
||||||
if (long.TryParse(killTime, out long unixTime))
|
|
||||||
{
|
{
|
||||||
var date = DateTimeOffset.FromUnixTimeSeconds(unixTime);
|
if (long.TryParse(kill.KillTime, out long unixTime))
|
||||||
if (date.ToString("MMM", CultureInfo.InvariantCulture) != currentMonth) continue;
|
{
|
||||||
|
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;
|
return kills;
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,12 +12,12 @@ public class JumpDriveStateChangedEvent : ILogEventHandler
|
||||||
{
|
{
|
||||||
public Regex Pattern { get; }
|
public Regex Pattern { get; }
|
||||||
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
|
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
|
||||||
|
|
||||||
public JumpDriveStateChangedEvent()
|
public JumpDriveStateChangedEvent()
|
||||||
{
|
{
|
||||||
Pattern = new Regex(@"<Jump Drive State Changed>.*.adam: (?<ShipName>.*.) in zone (?<Location>.*.)\)");
|
Pattern = new Regex(@"<Jump Drive State Changed>.*.adam: (?<ShipName>.*.) in zone (?<Location>.*.)\)");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(LogEntry entry)
|
public void Handle(LogEntry entry)
|
||||||
{
|
{
|
||||||
if (entry.Message is null) return;
|
if (entry.Message is null) return;
|
||||||
|
@ -34,6 +34,13 @@ public class JumpDriveStateChangedEvent : ILogEventHandler
|
||||||
{
|
{
|
||||||
data.ShipName = match.Groups[1].Value;
|
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))
|
if (!string.IsNullOrEmpty(data.ShipName) && !string.IsNullOrEmpty(data.Location))
|
||||||
{
|
{
|
||||||
TrackREventDispatcher.OnJumpDriveStateChangedEvent(data);
|
TrackREventDispatcher.OnJumpDriveStateChangedEvent(data);
|
||||||
|
|
|
@ -6,29 +6,35 @@ public class RequestJumpFailedEvent : ILogEventHandler
|
||||||
{
|
{
|
||||||
public Regex Pattern { get; }
|
public Regex Pattern { get; }
|
||||||
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
|
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
|
||||||
|
|
||||||
public RequestJumpFailedEvent()
|
public RequestJumpFailedEvent()
|
||||||
{
|
{
|
||||||
Pattern = new Regex(@"<Request Jump Failed>.*.adam: (?<ShipName>.*.) in zone (?<Location>.*.)\)");
|
Pattern = new Regex(@"<Request Jump Failed>.*.adam: (?<ShipName>.*.) in zone (?<Location>.*.)\)");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(LogEntry entry)
|
public void Handle(LogEntry entry)
|
||||||
{
|
{
|
||||||
if (entry.Message is null) return;
|
if (entry.Message is null) return;
|
||||||
var match = Pattern.Match(entry.Message);
|
var match = Pattern.Match(entry.Message);
|
||||||
if (!match.Success) return;
|
if (!match.Success) return;
|
||||||
|
|
||||||
var data = new JumpDriveStateChangedData
|
var data = new JumpDriveStateChangedData
|
||||||
{
|
{
|
||||||
Location = match.Groups["Location"].Value
|
Location = match.Groups["Location"].Value
|
||||||
};
|
};
|
||||||
|
|
||||||
match = _cleanUpPattern.Match(match.Groups["ShipName"].Value);
|
match = _cleanUpPattern.Match(match.Groups["ShipName"].Value);
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
data.ShipName = match.Groups[1].Value;
|
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))
|
if (!string.IsNullOrEmpty(data.ShipName) && !string.IsNullOrEmpty(data.Location))
|
||||||
{
|
{
|
||||||
TrackREventDispatcher.OnJumpDriveStateChangedEvent(data);
|
TrackREventDispatcher.OnJumpDriveStateChangedEvent(data);
|
||||||
|
|
80
AutoTrackR2/LogEventHandlers/VehicleControlEvent.cs
Normal file
80
AutoTrackR2/LogEventHandlers/VehicleControlEvent.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,64 +1,55 @@
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using AutoTrackR2.Constants;
|
||||||
|
|
||||||
namespace AutoTrackR2.LogEventHandlers;
|
namespace AutoTrackR2.LogEventHandlers;
|
||||||
|
|
||||||
public struct VehicleDestructionData
|
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 string VehicleZone { get; set; }
|
||||||
public float PosX { get; set; }
|
public string? Ship { 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 class VehicleDestructionEvent : ILogEventHandler
|
public class VehicleDestructionEvent : ILogEventHandler
|
||||||
{
|
{
|
||||||
public Regex Pattern { get; }
|
public Regex Pattern { get; }
|
||||||
|
private Regex _shipManufacturerPattern;
|
||||||
|
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
|
||||||
|
|
||||||
public VehicleDestructionEvent()
|
public VehicleDestructionEvent()
|
||||||
{
|
{
|
||||||
const string patternStr = """
|
Pattern = new Regex(@"<Vehicle Destruction> Vehicle '(?<vehicle_name>[^']+)' \[(?<vehicle_id>\d+)\] \[(?<team>[^\]]+)\] in zone '(?<vehicle_zone>[^']+)' has been destroyed");
|
||||||
<(?<timestamp>[^>]+)> \[Notice\] <Vehicle Destruction> CVehicle::OnAdvanceDestroyLevel:
|
_shipManufacturerPattern = new Regex($"^({string.Join("|", ShipManufacturers.List)})");
|
||||||
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", ""));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Handle(LogEntry entry)
|
public void Handle(LogEntry entry)
|
||||||
{
|
{
|
||||||
if (entry.Message == null)
|
if (entry.Message is null) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var match = Pattern.Match(entry.Message);
|
var match = Pattern.Match(entry.Message);
|
||||||
if (!match.Success)
|
if (!match.Success) return;
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = new VehicleDestructionData
|
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,
|
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);
|
TrackREventDispatcher.OnVehicleDestructionEvent(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -47,7 +47,9 @@ public class LogHandler
|
||||||
new JumpDriveStateChangedEvent(),
|
new JumpDriveStateChangedEvent(),
|
||||||
new RequestJumpFailedEvent(),
|
new RequestJumpFailedEvent(),
|
||||||
new VehicleDestructionEvent(),
|
new VehicleDestructionEvent(),
|
||||||
new ActorDeathEvent()
|
new ActorDeathEvent(),
|
||||||
|
new VehicleControlEvent(),
|
||||||
|
new VehicleControlClearEvent()
|
||||||
];
|
];
|
||||||
|
|
||||||
public LogHandler(string? logPath)
|
public LogHandler(string? logPath)
|
||||||
|
|
|
@ -18,37 +18,36 @@ public static class TrackREventDispatcher
|
||||||
{
|
{
|
||||||
InstancedInteriorEvent?.Invoke(data);
|
InstancedInteriorEvent?.Invoke(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player changed GameMode (AC or PU)
|
// Player changed GameMode (AC or PU)
|
||||||
public static event Action<GameMode>? PlayerChangedGameModeEvent;
|
public static event Action<GameMode>? PlayerChangedGameModeEvent;
|
||||||
public static void OnPlayerChangedGameModeEvent(GameMode mode)
|
public static void OnPlayerChangedGameModeEvent(GameMode mode)
|
||||||
{
|
{
|
||||||
PlayerChangedGameModeEvent?.Invoke(mode);
|
PlayerChangedGameModeEvent?.Invoke(mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Game version has been detected
|
// Game version has been detected
|
||||||
public static event Action<string>? GameVersionEvent;
|
public static event Action<string>? GameVersionEvent;
|
||||||
public static void OnGameVersionEvent(string value)
|
public static void OnGameVersionEvent(string value)
|
||||||
{
|
{
|
||||||
GameVersionEvent?.Invoke(value);
|
GameVersionEvent?.Invoke(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actor has died
|
// Actor has died
|
||||||
public static event Action<ActorDeathData>? ActorDeathEvent;
|
public static event Action<ActorDeathData>? ActorDeathEvent;
|
||||||
public static void OnActorDeathEvent(ActorDeathData data)
|
public static void OnActorDeathEvent(ActorDeathData data)
|
||||||
{
|
{
|
||||||
ActorDeathEvent?.Invoke(data);
|
ActorDeathEvent?.Invoke(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vehicle has been destroyed
|
// Vehicle has been destroyed
|
||||||
public static event Action<VehicleDestructionData>? VehicleDestructionEvent;
|
public static event Action<VehicleDestructionData>? VehicleDestructionEvent;
|
||||||
public static void OnVehicleDestructionEvent(VehicleDestructionData data)
|
public static void OnVehicleDestructionEvent(VehicleDestructionData data)
|
||||||
{
|
{
|
||||||
VehicleDestructionEvent?.Invoke(data);
|
VehicleDestructionEvent?.Invoke(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jump Drive state has changed
|
// 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 event Action<JumpDriveStateChangedData>? JumpDriveStateChangedEvent;
|
||||||
public static void OnJumpDriveStateChangedEvent(JumpDriveStateChangedData data)
|
public static void OnJumpDriveStateChangedEvent(JumpDriveStateChangedData data)
|
||||||
{
|
{
|
||||||
|
@ -61,4 +60,11 @@ public static class TrackREventDispatcher
|
||||||
{
|
{
|
||||||
StreamlinkRecordEvent?.Invoke(streamerHandle);
|
StreamlinkRecordEvent?.Invoke(streamerHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Vehicle control has changed
|
||||||
|
public static event Action<VehicleControlData>? VehicleControlEvent;
|
||||||
|
public static void OnVehicleControlEvent(VehicleControlData data)
|
||||||
|
{
|
||||||
|
VehicleControlEvent?.Invoke(data);
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue