mirror of
https://github.com/BubbaGumpShrump/AutoTrackR2.git
synced 2025-07-30 20:59:12 +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>
|
||||
<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>
|
||||
|
|
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*",
|
||||
"*cutter*",
|
||||
"*tractor*",
|
||||
"*carryable*"
|
||||
"*carryable*",
|
||||
"*shotgun*",
|
||||
"*sniper*",
|
||||
"*rifle*",
|
||||
"*smg*",
|
||||
"*pistol*",
|
||||
"*sniper*",
|
||||
"*lmg*",
|
||||
"*volt*",
|
||||
};
|
||||
|
||||
public static bool IsKnownWeapon(string weaponName)
|
||||
|
|
|
@ -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) =>
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
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 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);
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue