mirror of
https://github.com/BubbaGumpShrump/AutoTrackR2.git
synced 2025-05-20 07:55:30 +00:00
Initial refactor to C# from PS
This commit is contained in:
parent
77a3c936fd
commit
a08de59a73
15 changed files with 855 additions and 300 deletions
.gitignore
AutoTrackR2
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -360,4 +360,7 @@ MigrationBackup/
|
|||
.ionide/
|
||||
|
||||
# Fody - auto-generated XML schema
|
||||
FodyWeavers.xsd
|
||||
FodyWeavers.xsd
|
||||
|
||||
### Rider ###
|
||||
.idea/
|
|
@ -3,309 +3,313 @@ using System.Windows;
|
|||
using System.Windows.Controls;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Effects;
|
||||
using System.IO;
|
||||
using System.Windows.Documents;
|
||||
using System.Globalization;
|
||||
using System.Windows.Media.Imaging;
|
||||
using AutoTrackR2.LogEventHandlers;
|
||||
|
||||
namespace AutoTrackR2
|
||||
namespace AutoTrackR2;
|
||||
|
||||
public struct PlayerData
|
||||
{
|
||||
public partial class HomePage : UserControl
|
||||
public string? PFPURL;
|
||||
public string? UEERecord;
|
||||
public string? OrgURL;
|
||||
public string? OrgName;
|
||||
public string? JoinDate;
|
||||
}
|
||||
|
||||
public partial class HomePage : UserControl
|
||||
{
|
||||
public HomePage()
|
||||
{
|
||||
public HomePage()
|
||||
InitializeComponent();
|
||||
|
||||
// Get the current month
|
||||
string currentMonth = DateTime.Now.ToString("MMMM", CultureInfo.InvariantCulture);
|
||||
|
||||
// Set the TextBlock text
|
||||
KillTallyTitle.Text = $"Kill Tally - {currentMonth}";
|
||||
}
|
||||
|
||||
private Process runningProcess; // Field to store the running process
|
||||
private LogHandler _logHandler;
|
||||
private bool _UIEventsRegistered = false;
|
||||
|
||||
|
||||
// Update Start/Stop button states based on the isRunning flag
|
||||
public void UpdateButtonState(bool isRunning)
|
||||
{
|
||||
var accentColor = (Color)Application.Current.Resources["AccentColor"];
|
||||
|
||||
if (isRunning)
|
||||
{
|
||||
InitializeComponent();
|
||||
// Set Start button to "Running..." and apply glow effect
|
||||
StartButton.Content = "Running...";
|
||||
StartButton.IsEnabled = false; // Disable Start button
|
||||
StartButton.Style = (Style)FindResource("DisabledButtonStyle");
|
||||
|
||||
// Get the current month
|
||||
string currentMonth = DateTime.Now.ToString("MMMM", CultureInfo.InvariantCulture);
|
||||
|
||||
// Set the TextBlock text
|
||||
KillTallyTitle.Text = $"Kill Tally - {currentMonth}";
|
||||
}
|
||||
|
||||
private Process runningProcess; // Field to store the running process
|
||||
|
||||
// Update Start/Stop button states based on the isRunning flag
|
||||
public void UpdateButtonState(bool isRunning)
|
||||
{
|
||||
var accentColor = (Color)Application.Current.Resources["AccentColor"];
|
||||
|
||||
if (isRunning)
|
||||
// Add glow effect to the Start button
|
||||
StartButton.Effect = new DropShadowEffect
|
||||
{
|
||||
// Set Start button to "Running..." and apply glow effect
|
||||
StartButton.Content = "Running...";
|
||||
StartButton.IsEnabled = false; // Disable Start button
|
||||
StartButton.Style = (Style)FindResource("DisabledButtonStyle");
|
||||
Color = accentColor,
|
||||
BlurRadius = 30, // Adjust blur radius for desired glow intensity
|
||||
ShadowDepth = 0, // Set shadow depth to 0 for a pure glow effect
|
||||
Opacity = 1, // Set opacity for glow visibility
|
||||
Direction = 0 // Direction doesn't matter for glow
|
||||
};
|
||||
|
||||
// Add glow effect to the Start button
|
||||
StartButton.Effect = new DropShadowEffect
|
||||
{
|
||||
Color = accentColor,
|
||||
BlurRadius = 30, // Adjust blur radius for desired glow intensity
|
||||
ShadowDepth = 0, // Set shadow depth to 0 for a pure glow effect
|
||||
Opacity = 1, // Set opacity for glow visibility
|
||||
Direction = 0 // Direction doesn't matter for glow
|
||||
};
|
||||
|
||||
StopButton.Style = (Style)FindResource("ButtonStyle");
|
||||
StopButton.IsEnabled = true; // Enable Stop button
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reset Start button back to its original state
|
||||
StartButton.Content = "Start";
|
||||
StartButton.IsEnabled = true; // Enable Start button
|
||||
|
||||
// Remove the glow effect from Start button
|
||||
StartButton.Effect = null;
|
||||
|
||||
StopButton.Style = (Style)FindResource("DisabledButtonStyle");
|
||||
StartButton.Style = (Style)FindResource("ButtonStyle");
|
||||
StopButton.IsEnabled = false; // Disable Stop button
|
||||
}
|
||||
StopButton.Style = (Style)FindResource("ButtonStyle");
|
||||
StopButton.IsEnabled = true; // Enable Stop button
|
||||
}
|
||||
|
||||
public void StartButton_Click(object sender, RoutedEventArgs e)
|
||||
else
|
||||
{
|
||||
UpdateButtonState(true);
|
||||
string scriptPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "KillTrackR_MainScript.ps1");
|
||||
TailFileAsync(scriptPath);
|
||||
// Reset Start button back to its original state
|
||||
StartButton.Content = "Start";
|
||||
StartButton.IsEnabled = true; // Enable Start button
|
||||
|
||||
// Remove the glow effect from Start button
|
||||
StartButton.Effect = null;
|
||||
|
||||
StopButton.Style = (Style)FindResource("DisabledButtonStyle");
|
||||
StartButton.Style = (Style)FindResource("ButtonStyle");
|
||||
StopButton.IsEnabled = false; // Disable Stop button
|
||||
}
|
||||
|
||||
RegisterUIEventHandlers();
|
||||
}
|
||||
|
||||
private async void TailFileAsync(string scriptPath)
|
||||
{
|
||||
await Task.Run(() =>
|
||||
public void StartButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
UpdateButtonState(true);
|
||||
//string scriptPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "KillTrackR_MainScript.ps1");
|
||||
// TailFileAsync(scriptPath);
|
||||
|
||||
// _logHandler = new LogHandler(@"U:\\StarCitizen\\StarCitizen\\LIVE\\Game.log");
|
||||
_logHandler = new LogHandler(ConfigManager.LogFile);
|
||||
_logHandler.Initialize();
|
||||
}
|
||||
|
||||
private void RegisterUIEventHandlers()
|
||||
{
|
||||
if (_UIEventsRegistered)
|
||||
return;
|
||||
|
||||
// Username
|
||||
TrackREventDispatcher.PlayerLoginEvent += (username) => {
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo psi = new ProcessStartInfo
|
||||
{
|
||||
FileName = "powershell.exe",
|
||||
Arguments = $"-NoProfile -ExecutionPolicy Bypass -File \"{scriptPath}\"",
|
||||
WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
|
||||
RedirectStandardOutput = true,
|
||||
RedirectStandardError = true,
|
||||
UseShellExecute = false,
|
||||
CreateNoWindow = true
|
||||
};
|
||||
|
||||
runningProcess = new Process { StartInfo = psi }; // Store the process in the field
|
||||
|
||||
runningProcess.OutputDataReceived += (s, e) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
// Parse and display key-value pairs in the OutputTextBox
|
||||
if (e.Data.Contains("PlayerName="))
|
||||
{
|
||||
string pilotName = e.Data.Split('=')[1].Trim();
|
||||
PilotNameTextBox.Text = pilotName; // Update the Button's Content
|
||||
AdjustFontSize(PilotNameTextBox);
|
||||
}
|
||||
else if (e.Data.Contains("PlayerShip="))
|
||||
{
|
||||
string playerShip = e.Data.Split('=')[1].Trim();
|
||||
PlayerShipTextBox.Text = playerShip;
|
||||
AdjustFontSize(PlayerShipTextBox);
|
||||
}
|
||||
else if (e.Data.Contains("GameMode="))
|
||||
{
|
||||
string gameMode = e.Data.Split('=')[1].Trim();
|
||||
GameModeTextBox.Text = gameMode;
|
||||
AdjustFontSize(GameModeTextBox);
|
||||
}
|
||||
else if (e.Data.Contains("KillTally="))
|
||||
{
|
||||
string killTally = e.Data.Split('=')[1].Trim();
|
||||
KillTallyTextBox.Text = killTally;
|
||||
AdjustFontSize(KillTallyTextBox);
|
||||
}
|
||||
else if (e.Data.Contains("NewKill="))
|
||||
{
|
||||
// Parse the kill data
|
||||
var killData = e.Data.Split('=')[1].Trim(); // Assume the kill data follows after "NewKill="
|
||||
var killParts = killData.Split(',');
|
||||
|
||||
// Fetch the dynamic resource for AltTextColor
|
||||
var altTextColorBrush = new SolidColorBrush((Color)Application.Current.Resources["AltTextColor"]);
|
||||
var accentColorBrush = new SolidColorBrush((Color)Application.Current.Resources["AccentColor"]);
|
||||
|
||||
// Fetch the Orbitron FontFamily from resources
|
||||
var orbitronFontFamily = (FontFamily)Application.Current.Resources["Orbitron"];
|
||||
var gemunuFontFamily = (FontFamily)Application.Current.Resources["Gemunu"];
|
||||
|
||||
// Create a new TextBlock for each kill
|
||||
var killTextBlock = new TextBlock
|
||||
{
|
||||
Margin = new Thickness(0, 10, 0, 10),
|
||||
Style = (Style)Application.Current.Resources["RoundedTextBlock"], // Apply style for text
|
||||
FontSize = 14,
|
||||
FontWeight = FontWeights.Bold,
|
||||
FontFamily = gemunuFontFamily,
|
||||
};
|
||||
|
||||
// Add styled content using Run elements
|
||||
killTextBlock.Inlines.Add(new Run("Victim Name: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{killParts[1]}\n"));
|
||||
|
||||
// Repeat for other lines
|
||||
killTextBlock.Inlines.Add(new Run("Victim Ship: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{killParts[2]}\n"));
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("Victim Org: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{killParts[3]}\n"));
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("Join Date: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{killParts[4]}\n"));
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("UEE Record: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{killParts[5]}\n"));
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("Kill Time: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{killParts[6]}"));
|
||||
|
||||
// Create a Border and apply the RoundedTextBlockWithBorder style
|
||||
var killBorder = new Border
|
||||
{
|
||||
Style = (Style)Application.Current.Resources["RoundedTextBlockWithBorder"], // Apply border style
|
||||
};
|
||||
|
||||
// Create a Grid to hold the TextBlock and the Image
|
||||
var killGrid = new Grid
|
||||
{
|
||||
Width = 400, // Adjust the width of the Grid
|
||||
Height = 130, // Adjust the height as needed
|
||||
};
|
||||
|
||||
// Define two columns in the Grid: one for the text and one for the image
|
||||
killGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(3, GridUnitType.Star) }); // Text column
|
||||
killGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) }); // Image column
|
||||
|
||||
// Add the TextBlock to the first column of the Grid
|
||||
Grid.SetColumn(killTextBlock, 0);
|
||||
killGrid.Children.Add(killTextBlock);
|
||||
|
||||
// Create the Image for the profile
|
||||
var profileImage = new Image
|
||||
{
|
||||
Source = new BitmapImage(new Uri(killParts[7])), // Assuming the 8th part contains the profile image URL
|
||||
Width = 90,
|
||||
Height = 90,
|
||||
Stretch = Stretch.Fill, // Adjust how the image fits
|
||||
};
|
||||
|
||||
// Create a Border around the Image
|
||||
var imageBorder = new Border
|
||||
{
|
||||
BorderBrush = accentColorBrush, // Set the border color
|
||||
BorderThickness = new Thickness(2), // Set the border thickness
|
||||
Padding = new Thickness(0), // Optional padding inside the border
|
||||
CornerRadius = new CornerRadius(5),
|
||||
Margin = new Thickness(10,18,15,18),
|
||||
Child = profileImage // Set the Image as the content of the Border
|
||||
};
|
||||
|
||||
// Add the Border (with the image inside) to the Grid
|
||||
Grid.SetColumn(imageBorder, 1);
|
||||
killGrid.Children.Add(imageBorder);
|
||||
|
||||
// Set the Grid as the child of the Border
|
||||
killBorder.Child = killGrid;
|
||||
|
||||
// Add the new Border to the StackPanel inside the Border
|
||||
KillFeedStackPanel.Children.Insert(0, killBorder);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DebugPanel.AppendText(e.Data + Environment.NewLine);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
runningProcess.ErrorDataReceived += (s, e) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
DebugPanel.AppendText(e.Data + Environment.NewLine);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
runningProcess.Start();
|
||||
runningProcess.BeginOutputReadLine();
|
||||
runningProcess.BeginErrorReadLine();
|
||||
|
||||
runningProcess.WaitForExit();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
MessageBox.Show($"Error running script: {ex.Message}");
|
||||
});
|
||||
}
|
||||
PilotNameTextBox.Text = username;
|
||||
AdjustFontSize(PilotNameTextBox);
|
||||
LocalPlayerData.Username = username;
|
||||
});
|
||||
}
|
||||
|
||||
public void StopButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (runningProcess != null && !runningProcess.HasExited)
|
||||
};
|
||||
|
||||
// Ship
|
||||
TrackREventDispatcher.InstancedInteriorEvent += (data) => {
|
||||
if (data.OwnerGEID == LocalPlayerData.Username && data.Ship != null)
|
||||
{
|
||||
// Kill the running process
|
||||
runningProcess.Kill();
|
||||
runningProcess = null; // Clear the reference to the process
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
PlayerShipTextBox.Text = data.Ship;
|
||||
AdjustFontSize(PlayerShipTextBox);
|
||||
LocalPlayerData.PlayerShip = data.Ship;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Game Mode
|
||||
TrackREventDispatcher.PlayerChangedGameModeEvent += (mode) => {
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
GameModeTextBox.Text = mode.ToString();
|
||||
AdjustFontSize(GameModeTextBox);
|
||||
LocalPlayerData.CurrentGameMode = mode;
|
||||
});
|
||||
};
|
||||
|
||||
// Game Version
|
||||
TrackREventDispatcher.GameVersionEvent += (version) => {
|
||||
LocalPlayerData.GameVersion = version;
|
||||
};
|
||||
|
||||
// Actor Death
|
||||
TrackREventDispatcher.ActorDeathEvent += async (data) => {
|
||||
if (data.VictimPilot != LocalPlayerData.Username)
|
||||
{
|
||||
var playerData = await WebHandler.GetPlayerData(data.VictimPilot);
|
||||
|
||||
// Clear the text boxes
|
||||
System.Threading.Thread.Sleep(200);
|
||||
PilotNameTextBox.Text = string.Empty;
|
||||
PlayerShipTextBox.Text = string.Empty;
|
||||
GameModeTextBox.Text = string.Empty;
|
||||
KillTallyTextBox.Text = string.Empty;
|
||||
KillFeedStackPanel.Children.Clear();
|
||||
}
|
||||
if (playerData != null)
|
||||
{
|
||||
Dispatcher.Invoke(() => { AddKillToScreen(data, playerData); });
|
||||
await WebHandler.SubmitKill(data, playerData);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_UIEventsRegistered = true;
|
||||
}
|
||||
|
||||
private void AdjustFontSize(TextBlock textBlock)
|
||||
private void AddKillToScreen(ActorDeathData deathData, PlayerData? playerData)
|
||||
{
|
||||
// Fetch the dynamic resource for AltTextColor
|
||||
var altTextColorBrush = new SolidColorBrush((Color)Application.Current.Resources["AltTextColor"]);
|
||||
var accentColorBrush = new SolidColorBrush((Color)Application.Current.Resources["AccentColor"]);
|
||||
|
||||
// Fetch the Orbitron FontFamily from resources
|
||||
var orbitronFontFamily = (FontFamily)Application.Current.Resources["Orbitron"];
|
||||
var gemunuFontFamily = (FontFamily)Application.Current.Resources["Gemunu"];
|
||||
|
||||
// Create a new TextBlock for each kill
|
||||
var killTextBlock = new TextBlock
|
||||
{
|
||||
// Set a starting font size
|
||||
double fontSize = 14;
|
||||
double maxWidth = textBlock.Width;
|
||||
Margin = new Thickness(0, 10, 0, 10),
|
||||
Style = (Style)Application.Current.Resources["RoundedTextBlock"], // Apply style for text
|
||||
FontSize = 14,
|
||||
FontWeight = FontWeights.Bold,
|
||||
FontFamily = gemunuFontFamily,
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(textBlock.Text) || double.IsNaN(maxWidth))
|
||||
return;
|
||||
// Add styled content using Run elements
|
||||
killTextBlock.Inlines.Add(new Run("Victim Name: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{deathData.VictimPilot}\n"));
|
||||
|
||||
// Measure the rendered width of the text
|
||||
FormattedText formattedText = new FormattedText(
|
||||
// Repeat for other lines
|
||||
killTextBlock.Inlines.Add(new Run("Victim Ship: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{deathData.VictimShip}\n"));
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("Victim Org: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{playerData?.OrgName}\n"));
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("Join Date: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{playerData?.JoinDate}\n"));
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("UEE Record: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
|
||||
|
||||
const string dateFormatString = "dd MMM yyyy HH:mm";
|
||||
var currentTime = DateTime.UtcNow.ToString(dateFormatString);
|
||||
|
||||
killTextBlock.Inlines.Add(new Run("Kill Time: ")
|
||||
{
|
||||
Foreground = altTextColorBrush,
|
||||
FontFamily = orbitronFontFamily,
|
||||
});
|
||||
killTextBlock.Inlines.Add(new Run($"{currentTime}"));
|
||||
|
||||
// Create a Border and apply the RoundedTextBlockWithBorder style
|
||||
var killBorder = new Border
|
||||
{
|
||||
Style = (Style)Application.Current.Resources["RoundedTextBlockWithBorder"], // Apply border style
|
||||
};
|
||||
|
||||
// Create a Grid to hold the TextBlock and the Image
|
||||
var killGrid = new Grid
|
||||
{
|
||||
Width = 400, // Adjust the width of the Grid
|
||||
Height = 130, // Adjust the height as needed
|
||||
};
|
||||
|
||||
// Define two columns in the Grid: one for the text and one for the image
|
||||
killGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(3, GridUnitType.Star) }); // Text column
|
||||
killGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) }); // Image column
|
||||
|
||||
// Add the TextBlock to the first column of the Grid
|
||||
Grid.SetColumn(killTextBlock, 0);
|
||||
killGrid.Children.Add(killTextBlock);
|
||||
|
||||
// Create the Image for the profile
|
||||
var profileImage = new Image
|
||||
{
|
||||
Source = new BitmapImage(new Uri(playerData?.PFPURL)), // Assuming the 8th part contains the profile image URL
|
||||
Width = 90,
|
||||
Height = 90,
|
||||
Stretch = Stretch.Fill, // Adjust how the image fits
|
||||
};
|
||||
|
||||
// Create a Border around the Image
|
||||
var imageBorder = new Border
|
||||
{
|
||||
BorderBrush = accentColorBrush, // Set the border color
|
||||
BorderThickness = new Thickness(2), // Set the border thickness
|
||||
Padding = new Thickness(0), // Optional padding inside the border
|
||||
CornerRadius = new CornerRadius(5),
|
||||
Margin = new Thickness(10,18,15,18),
|
||||
Child = profileImage // Set the Image as the content of the Border
|
||||
};
|
||||
|
||||
// Add the Border (with the image inside) to the Grid
|
||||
Grid.SetColumn(imageBorder, 1);
|
||||
killGrid.Children.Add(imageBorder);
|
||||
|
||||
// Set the Grid as the child of the Border
|
||||
killBorder.Child = killGrid;
|
||||
|
||||
// Add the new Border to the StackPanel inside the Border
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
KillFeedStackPanel.Children.Insert(0, killBorder);
|
||||
});
|
||||
}
|
||||
|
||||
public void StopButton_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_logHandler.Stop();
|
||||
|
||||
// Clear the text boxes
|
||||
System.Threading.Thread.Sleep(200);
|
||||
PilotNameTextBox.Text = string.Empty;
|
||||
PlayerShipTextBox.Text = string.Empty;
|
||||
GameModeTextBox.Text = string.Empty;
|
||||
KillTallyTextBox.Text = string.Empty;
|
||||
KillFeedStackPanel.Children.Clear();
|
||||
}
|
||||
|
||||
private void AdjustFontSize(TextBlock textBlock)
|
||||
{
|
||||
// Set a starting font size
|
||||
double fontSize = 14;
|
||||
double maxWidth = textBlock.Width;
|
||||
|
||||
if (string.IsNullOrEmpty(textBlock.Text) || double.IsNaN(maxWidth))
|
||||
return;
|
||||
|
||||
// Measure the rendered width of the text
|
||||
FormattedText formattedText = new FormattedText(
|
||||
textBlock.Text,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
|
||||
fontSize,
|
||||
textBlock.Foreground,
|
||||
VisualTreeHelper.GetDpi(this).PixelsPerDip
|
||||
);
|
||||
|
||||
// Reduce font size until text fits within the width
|
||||
while (formattedText.Width > maxWidth && fontSize > 6)
|
||||
{
|
||||
fontSize -= 0.5;
|
||||
formattedText = new FormattedText(
|
||||
textBlock.Text,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
|
@ -314,24 +318,9 @@ namespace AutoTrackR2
|
|||
textBlock.Foreground,
|
||||
VisualTreeHelper.GetDpi(this).PixelsPerDip
|
||||
);
|
||||
|
||||
// Reduce font size until text fits within the width
|
||||
while (formattedText.Width > maxWidth && fontSize > 6)
|
||||
{
|
||||
fontSize -= 0.5;
|
||||
formattedText = new FormattedText(
|
||||
textBlock.Text,
|
||||
CultureInfo.CurrentCulture,
|
||||
FlowDirection.LeftToRight,
|
||||
new Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch),
|
||||
fontSize,
|
||||
textBlock.Foreground,
|
||||
VisualTreeHelper.GetDpi(this).PixelsPerDip
|
||||
);
|
||||
}
|
||||
|
||||
// Apply the adjusted font size
|
||||
textBlock.FontSize = fontSize;
|
||||
}
|
||||
|
||||
// Apply the adjusted font size
|
||||
textBlock.FontSize = fontSize;
|
||||
}
|
||||
}
|
||||
|
|
17
AutoTrackR2/LocalPlayerData.cs
Normal file
17
AutoTrackR2/LocalPlayerData.cs
Normal file
|
@ -0,0 +1,17 @@
|
|||
namespace AutoTrackR2;
|
||||
|
||||
|
||||
public enum GameMode
|
||||
{
|
||||
ArenaCommander,
|
||||
PersistentUniverse
|
||||
}
|
||||
|
||||
public static class LocalPlayerData
|
||||
{
|
||||
public static string? Username;
|
||||
public static string? PlayerShip;
|
||||
public static string? GameVersion;
|
||||
public static GameMode CurrentGameMode;
|
||||
public static string? LastSeenVehicleLocation;
|
||||
}
|
59
AutoTrackR2/LogEventHandlers/ActorDeathEvent.cs
Normal file
59
AutoTrackR2/LogEventHandlers/ActorDeathEvent.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
public struct ActorDeathData
|
||||
{
|
||||
public string VictimPilot;
|
||||
public string VictimShip;
|
||||
public string Player;
|
||||
public string Weapon;
|
||||
public string Class;
|
||||
public string DamageType;
|
||||
public string Timestamp;
|
||||
}
|
||||
|
||||
public class ActorDeathEvent : ILogEventHandler
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
public ActorDeathEvent()
|
||||
{
|
||||
Pattern = new Regex(@"<Actor Death> CActor::Kill: '(?<EnemyPilot>[^']+)' \[\d+\] in zone '(?<EnemyShip>[^']+)' killed by '(?<Player>[^']+)' \[[^']+\] using '(?<Weapon>[^']+)' \[Class (?<Class>[^\]]+)\] with damage type '(?<DamageType>[^']+)");
|
||||
}
|
||||
|
||||
Regex cleanUpPattern = new Regex(@"^(.+?)_\d+$");
|
||||
|
||||
public void Handle(LogEntry entry)
|
||||
{
|
||||
if (entry.Message is null) return;
|
||||
|
||||
var match = Pattern.Match(entry.Message);
|
||||
if (!match.Success) return;
|
||||
|
||||
var data = new ActorDeathData {
|
||||
VictimPilot = match.Groups["EnemyPilot"].Value,
|
||||
VictimShip = match.Groups["EnemyShip"].Value,
|
||||
Player = match.Groups["Player"].Value,
|
||||
Weapon = match.Groups["Weapon"].Value,
|
||||
Class = match.Groups["Class"].Value,
|
||||
DamageType = match.Groups["DamageType"].Value,
|
||||
Timestamp = entry.Timestamp.ToString("yyyy-MM-dd HH:mm:ss")
|
||||
};
|
||||
|
||||
if (cleanUpPattern.IsMatch(data.VictimShip))
|
||||
{
|
||||
data.VictimShip = cleanUpPattern.Match(data.VictimShip).Groups[1].Value;
|
||||
}
|
||||
|
||||
if (cleanUpPattern.IsMatch(data.Weapon))
|
||||
{
|
||||
data.Weapon = cleanUpPattern.Match(data.Weapon).Groups[1].Value;
|
||||
}
|
||||
|
||||
|
||||
TrackREventDispatcher.OnActorDeathEvent(data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
21
AutoTrackR2/LogEventHandlers/GameVersionEvent.cs
Normal file
21
AutoTrackR2/LogEventHandlers/GameVersionEvent.cs
Normal file
|
@ -0,0 +1,21 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
public class GameVersionEvent : ILogEventHandler
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
|
||||
public GameVersionEvent()
|
||||
{
|
||||
Pattern = new Regex(@"--system-trace-env-id='pub-sc-alpha-(?<GameVersion>\d{3,4}-\d{7})'");
|
||||
}
|
||||
public void Handle(LogEntry entry)
|
||||
{
|
||||
if (entry.Message is null) return;
|
||||
var match = Pattern.Match(entry.Message);
|
||||
if (!match.Success) return;
|
||||
|
||||
TrackREventDispatcher.OnGameVersionEvent(match.Groups["GameVersion"].Value);
|
||||
}
|
||||
}
|
10
AutoTrackR2/LogEventHandlers/ILogEventHandler.cs
Normal file
10
AutoTrackR2/LogEventHandlers/ILogEventHandler.cs
Normal file
|
@ -0,0 +1,10 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
public interface ILogEventHandler
|
||||
{
|
||||
Regex Pattern { get; }
|
||||
void Handle(LogEntry entry);
|
||||
|
||||
}
|
22
AutoTrackR2/LogEventHandlers/InArenaCommanderEvent.cs
Normal file
22
AutoTrackR2/LogEventHandlers/InArenaCommanderEvent.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
public class InArenaCommanderEvent : ILogEventHandler
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
|
||||
public InArenaCommanderEvent()
|
||||
{
|
||||
Pattern = new Regex("Requesting Mode Change");
|
||||
}
|
||||
|
||||
public void Handle(LogEntry entry)
|
||||
{
|
||||
if (entry.Message is null) return;
|
||||
var match = Pattern.Match(entry.Message);
|
||||
if (!match.Success) return;
|
||||
|
||||
TrackREventDispatcher.OnPlayerChangedGameModeEvent(GameMode.ArenaCommander);
|
||||
}
|
||||
}
|
22
AutoTrackR2/LogEventHandlers/InPersistentUniverseEvent.cs
Normal file
22
AutoTrackR2/LogEventHandlers/InPersistentUniverseEvent.cs
Normal file
|
@ -0,0 +1,22 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
public class InPersistentUniverseEvent : ILogEventHandler
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
|
||||
public InPersistentUniverseEvent()
|
||||
{
|
||||
Pattern = new Regex(@"<\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z> \[Notice\] <ContextEstablisherTaskFinished> establisher=""CReplicationModel"" message=""CET completed"" taskname=""StopLoadingScreen"" state=[^\s()]+\(\d+\) status=""Finished"" runningTime=\d+\.\d+ numRuns=\d+ map=""megamap"" gamerules=""SC_Default"" sessionId=""[a-f0-9\-]+"" \[Team_Network\]\[Network\]\[Replication\]\[Loading\]\[Persistence\]");
|
||||
}
|
||||
|
||||
public void Handle(LogEntry entry)
|
||||
{
|
||||
if (entry.Message is null) return;
|
||||
var match = Pattern.Match(entry.Message);
|
||||
if (!match.Success) return;
|
||||
|
||||
TrackREventDispatcher.OnPlayerChangedGameModeEvent(GameMode.PersistentUniverse);
|
||||
}
|
||||
}
|
77
AutoTrackR2/LogEventHandlers/InstancedInteriorEvent.cs
Normal file
77
AutoTrackR2/LogEventHandlers/InstancedInteriorEvent.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
public struct InstancedInteriorData
|
||||
{
|
||||
public string Entity;
|
||||
public string OwnerGEID;
|
||||
public string ManagerGEID;
|
||||
public string InstancedInterior;
|
||||
public string? Ship;
|
||||
}
|
||||
|
||||
// A ship loadout has been changed
|
||||
public class InstancedInteriorEvent : ILogEventHandler
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
|
||||
private Regex _shipManufacturerPattern;
|
||||
private Regex _cleanUpPattern = new Regex(@"(.+?)_\d+$");
|
||||
|
||||
private List<string> _shipManufacturers = new List<string>
|
||||
{
|
||||
"ORIG",
|
||||
"CRUS",
|
||||
"RSI",
|
||||
"AEGS",
|
||||
"VNCL",
|
||||
"DRAK",
|
||||
"ANVL",
|
||||
"BANU",
|
||||
"MISC",
|
||||
"CNOU",
|
||||
"XIAN",
|
||||
"GAMA",
|
||||
"TMBL",
|
||||
"ESPR",
|
||||
"KRIG",
|
||||
"GRIN",
|
||||
"XNAA",
|
||||
"MRAI"
|
||||
};
|
||||
|
||||
public InstancedInteriorEvent()
|
||||
{
|
||||
Pattern = new Regex(@"\[InstancedInterior\] OnEntityLeaveZone - InstancedInterior \[(?<InstancedInterior>[^\]]+)\] \[\d+\] -> Entity \[(?<Entity>[^\]]+)\] \[\d+\] -- m_openDoors\[\d+\], m_managerGEID\[(?<ManagerGEID>\d+)\], m_ownerGEID\[(?<OwnerGEID>[^\[]+)\]");
|
||||
_shipManufacturerPattern = new Regex($"^({string.Join("|", _shipManufacturers)})");
|
||||
}
|
||||
|
||||
public void Handle(LogEntry entry)
|
||||
{
|
||||
if (entry.Message is null) return;
|
||||
var match = Pattern.Match(entry.Message);
|
||||
if (!match.Success) return;
|
||||
|
||||
var data = new InstancedInteriorData {
|
||||
Entity = match.Groups["Entity"].Value,
|
||||
OwnerGEID = match.Groups["OwnerGEID"].Value,
|
||||
ManagerGEID = match.Groups["ManagerGEID"].Value,
|
||||
InstancedInterior = match.Groups["InstancedInterior"].Value,
|
||||
};
|
||||
|
||||
match = _shipManufacturerPattern.Match(data.Entity);
|
||||
if (match.Success)
|
||||
{
|
||||
match = _cleanUpPattern.Match(data.Entity);
|
||||
if (match.Success)
|
||||
{
|
||||
data.Ship = match.Groups[1].Value;
|
||||
}
|
||||
}
|
||||
|
||||
TrackREventDispatcher.OnInstancedInteriorEvent(data);
|
||||
|
||||
}
|
||||
|
||||
}
|
24
AutoTrackR2/LogEventHandlers/LoginEvent.cs
Normal file
24
AutoTrackR2/LogEventHandlers/LoginEvent.cs
Normal file
|
@ -0,0 +1,24 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
// Local player has logged in
|
||||
public class LoginEvent : ILogEventHandler
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
|
||||
public LoginEvent()
|
||||
{
|
||||
Pattern = new Regex(@"\[Notice\] <Legacy login response> \[CIG-net\] User Login Success - Handle\[(?<Player>[A-Za-z0-9_-]+)\]");
|
||||
}
|
||||
|
||||
public void Handle(LogEntry entry)
|
||||
{
|
||||
if (entry.Message is null) return;
|
||||
|
||||
var match = Pattern.Match(entry.Message);
|
||||
if (!match.Success) return;
|
||||
|
||||
TrackREventDispatcher.OnPlayerLoginEvent(match.Groups["Player"].Value);
|
||||
}
|
||||
}
|
59
AutoTrackR2/LogEventHandlers/VehicleDestructionEvent.cs
Normal file
59
AutoTrackR2/LogEventHandlers/VehicleDestructionEvent.cs
Normal file
|
@ -0,0 +1,59 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace AutoTrackR2.LogEventHandlers;
|
||||
|
||||
public struct VehicleDestructionData
|
||||
{
|
||||
public string Vehicle { 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 class VehicleDestructionEvent : ILogEventHandler
|
||||
{
|
||||
public Regex Pattern { get; }
|
||||
|
||||
public VehicleDestructionEvent()
|
||||
{
|
||||
Pattern = new Regex("""
|
||||
"<(?<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>[^']+)'"
|
||||
""");
|
||||
}
|
||||
|
||||
public void Handle(LogEntry entry)
|
||||
{
|
||||
var match = Pattern.Match(entry.Message);
|
||||
if (!match.Success)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var data = new VehicleDestructionData
|
||||
{
|
||||
Vehicle = match.Groups["vehicle"].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,
|
||||
};
|
||||
|
||||
TrackREventDispatcher.OnVehicleDestructionEvent(data);
|
||||
}
|
||||
}
|
101
AutoTrackR2/LogHandler.cs
Normal file
101
AutoTrackR2/LogHandler.cs
Normal file
|
@ -0,0 +1,101 @@
|
|||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using AutoTrackR2.LogEventHandlers;
|
||||
|
||||
namespace AutoTrackR2;
|
||||
|
||||
|
||||
// Represents a single log entry
|
||||
// This is the object that will be passed to each handler, mostly for convenience
|
||||
public class LogEntry
|
||||
{
|
||||
public DateTime Timestamp { get; set; }
|
||||
public required string? Message { get; set; }
|
||||
|
||||
}
|
||||
public class LogHandler(string logPath)
|
||||
{
|
||||
private readonly string? _logPath = logPath;
|
||||
private FileStream? _fileStream;
|
||||
private StreamReader? _reader;
|
||||
|
||||
private CancellationTokenSource cancellationToken = new CancellationTokenSource();
|
||||
Thread? monitorThread;
|
||||
|
||||
// Handlers that should be run on every log entry
|
||||
// Overlap with _startupEventHandlers is fine
|
||||
private readonly List<ILogEventHandler> _eventHandlers = [
|
||||
new LoginEvent(),
|
||||
new InstancedInteriorEvent(),
|
||||
new InArenaCommanderEvent(),
|
||||
new InPersistentUniverseEvent(),
|
||||
new GameVersionEvent(),
|
||||
];
|
||||
|
||||
// Initialize the LogHandler and run all startup handlers
|
||||
public void Initialize()
|
||||
{
|
||||
if (!File.Exists(_logPath))
|
||||
{
|
||||
throw new FileNotFoundException("Log file not found", _logPath);
|
||||
}
|
||||
|
||||
_fileStream = new FileStream(_logPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
|
||||
_reader = new StreamReader(_fileStream);
|
||||
|
||||
while (_reader.ReadLine() is { } line)
|
||||
{
|
||||
HandleLogEntry(line);
|
||||
}
|
||||
|
||||
// Ensures that any deaths already in log aren't sent to the APIs until the monitor thread is running
|
||||
_eventHandlers.Add(new ActorDeathEvent());
|
||||
|
||||
monitorThread = new Thread(() => MonitorLog(cancellationToken.Token));
|
||||
monitorThread.Start();
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
// Stop the monitor thread
|
||||
cancellationToken?.Cancel();
|
||||
_reader?.Close();
|
||||
_fileStream?.Close();
|
||||
}
|
||||
|
||||
// Parse a single line of the log file and run matching handlers
|
||||
private void HandleLogEntry(string line)
|
||||
{
|
||||
foreach (var handler in _eventHandlers)
|
||||
{
|
||||
var match = handler.Pattern.Match(line);
|
||||
if (!match.Success) continue;
|
||||
|
||||
var entry = new LogEntry
|
||||
{
|
||||
Timestamp = DateTime.Now,
|
||||
Message = line
|
||||
};
|
||||
handler.Handle(entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void MonitorLog(CancellationToken token)
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
if (_reader?.ReadLine() is { } line)
|
||||
{
|
||||
HandleLogEntry(line);
|
||||
Console.WriteLine(line);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Wait for new lines to be written to the log file
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
Console.WriteLine("Monitor thread stopped");
|
||||
}
|
||||
}
|
49
AutoTrackR2/TrackREventDispatcher.cs
Normal file
49
AutoTrackR2/TrackREventDispatcher.cs
Normal file
|
@ -0,0 +1,49 @@
|
|||
using AutoTrackR2.LogEventHandlers;
|
||||
|
||||
namespace AutoTrackR2;
|
||||
|
||||
public static class TrackREventDispatcher
|
||||
{
|
||||
// Local Player Login
|
||||
public static event Action<string>? PlayerLoginEvent;
|
||||
public static void OnPlayerLoginEvent(string playerName)
|
||||
{
|
||||
PlayerLoginEvent?.Invoke(playerName);
|
||||
}
|
||||
|
||||
// An instanced interior has changed
|
||||
// Example: Player enters/leaves a ship
|
||||
public static event Action<InstancedInteriorData>? InstancedInteriorEvent;
|
||||
public static void OnInstancedInteriorEvent(InstancedInteriorData data)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ namespace AutoTrackR2
|
|||
{
|
||||
public partial class UpdatePage : UserControl
|
||||
{
|
||||
private string currentVersion = "v2.07";
|
||||
public static string currentVersion = "v2.08";
|
||||
private string latestVersion;
|
||||
|
||||
public UpdatePage()
|
||||
|
|
102
AutoTrackR2/WebHandler.cs
Normal file
102
AutoTrackR2/WebHandler.cs
Normal file
|
@ -0,0 +1,102 @@
|
|||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.RegularExpressions;
|
||||
using AutoTrackR2.LogEventHandlers;
|
||||
|
||||
namespace AutoTrackR2;
|
||||
|
||||
public static class WebHandler
|
||||
{
|
||||
class APIKillData
|
||||
{
|
||||
public string? victim_ship { get; set; }
|
||||
public string? victim{ get; set; }
|
||||
public string? enlisted{ get; set; }
|
||||
public string? rsi{ get; set; }
|
||||
public string? weapon{ get; set; }
|
||||
public string? method{ get; set; }
|
||||
public string? loadout_ship{ get; set; }
|
||||
public string? game_version{ get; set; }
|
||||
public string? gamemode{ get; set; }
|
||||
public string? trackr_version{ get; set; }
|
||||
public string? location{ get; set; }
|
||||
}
|
||||
|
||||
public static async Task<PlayerData?> GetPlayerData(string enemyPilot)
|
||||
{
|
||||
var joinDataPattern = new Regex("<span class=\"label\">Enlisted</span>\\s*<strong class=\"value\">([^<]+)</strong>");
|
||||
var ueePattern = new Regex("<p class=\"entry citizen-record\">\\s*<span class=\"label\">UEE Citizen Record<\\/span>\\s*<strong class=\"value\">#?(n\\/a|\\d+)<\\/strong>\\s*<\\/p>");
|
||||
var orgPattern = new Regex("\\/orgs\\/(?<OrgURL>[A-z0-9]+)\" .*\\>(?<OrgName>.*)<");
|
||||
var pfpPattern = new Regex("/media/(.*)\"");
|
||||
|
||||
// Make web request to check player data
|
||||
var playerData = new PlayerData();
|
||||
var httpClient = new HttpClient();
|
||||
var response = await httpClient.GetAsync($"https://robertsspaceindustries.com/en/citizens/{enemyPilot}");
|
||||
|
||||
if (response.StatusCode != HttpStatusCode.OK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var joinDataMatch = joinDataPattern.Match(content);
|
||||
if (joinDataMatch.Success)
|
||||
{
|
||||
playerData.JoinDate = joinDataMatch.Groups[1].Value;
|
||||
}
|
||||
|
||||
var ueeMatch = ueePattern.Match(content);
|
||||
if (ueeMatch.Success)
|
||||
{
|
||||
playerData.UEERecord = ueeMatch.Groups[1].Value;
|
||||
}
|
||||
|
||||
var orgMatch = orgPattern.Match(content);
|
||||
if (orgMatch.Success)
|
||||
{
|
||||
playerData.OrgName = orgMatch.Groups["OrgName"].Value;
|
||||
playerData.OrgURL = "https://robertsspaceindustries.com/en/orgs/" + orgMatch.Groups["OrgURL"].Value;
|
||||
}
|
||||
|
||||
var pfpMatch = pfpPattern.Match(content);
|
||||
if (pfpMatch.Success)
|
||||
{
|
||||
var match = pfpMatch.Groups[1].Value;
|
||||
if (match.Contains("heap_thumb"))
|
||||
{
|
||||
playerData.PFPURL = "https://cdn.robertsspaceindustries.com/static/images/account/avatar_default_big.jpg";
|
||||
}
|
||||
else
|
||||
{
|
||||
playerData.PFPURL = "https://robertsspaceindustries.com/media/" + pfpMatch.Groups[1].Value;
|
||||
}
|
||||
}
|
||||
|
||||
return playerData;
|
||||
}
|
||||
|
||||
public static async Task SubmitKill(ActorDeathData deathData, PlayerData? enemyPlayerData)
|
||||
{
|
||||
var killData = new APIKillData
|
||||
{
|
||||
victim_ship = deathData.VictimShip,
|
||||
victim = deathData.VictimPilot,
|
||||
enlisted = enemyPlayerData?.JoinDate,
|
||||
rsi = enemyPlayerData?.UEERecord,
|
||||
weapon = deathData.Weapon,
|
||||
method = deathData.DamageType,
|
||||
loadout_ship = LocalPlayerData.PlayerShip ?? "Unknown",
|
||||
game_version = LocalPlayerData.GameVersion ?? "Unknown",
|
||||
gamemode = LocalPlayerData.CurrentGameMode.ToString() ?? "Unknown",
|
||||
trackr_version = UpdatePage.currentVersion ?? "Unknown",
|
||||
location = LocalPlayerData.LastSeenVehicleLocation ?? "Unknown"
|
||||
};
|
||||
|
||||
var httpClient = new HttpClient();
|
||||
string jsonData = JsonSerializer.Serialize(killData);
|
||||
await httpClient.PostAsync(ConfigManager.ApiUrl + "/register-kill", new StringContent(jsonData, Encoding.UTF8, "application/json"));
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue