mirror of
https://github.com/MathiasLui/CSGO-Projects.git
synced 2025-05-06 22:01:18 +00:00
Make damage printer GUI features work
* Fixed a SteamHelper method that's not used anyways that threw exceptions
This commit is contained in:
parent
b5623017fc
commit
435daf6eb6
6 changed files with 664 additions and 18 deletions
|
@ -10,4 +10,8 @@
|
||||||
<SignAssembly>False</SignAssembly>
|
<SignAssembly>False</SignAssembly>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\SteamShared\SteamShared\SteamShared\SteamShared.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
13
DamagePrinter/DamagePrinterGUI/Globals.cs
Normal file
13
DamagePrinter/DamagePrinterGUI/Globals.cs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DamagePrinterGUI
|
||||||
|
{
|
||||||
|
internal static class Globals
|
||||||
|
{
|
||||||
|
public static Settings Settings { get; set; } = new Settings();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,15 +1,30 @@
|
||||||
<Window x:Class="DamagePrinterGUI.MainWindow"
|
<Window x:Name="window" x:Class="DamagePrinterGUI.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:DamagePrinterGUI"
|
xmlns:local="clr-namespace:DamagePrinterGUI"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="CS:GO Damage Printer" Height="355" Width="247"
|
Title="CS:GO Damage Printer" Height="436" Width="527"
|
||||||
ResizeMode="NoResize"
|
ResizeMode="NoResize"
|
||||||
Style="{DynamicResource CustomWindowStyle}">
|
Style="{DynamicResource CustomWindowStyle}"
|
||||||
|
Loaded="window_Loaded"
|
||||||
|
Closing="window_Closing">
|
||||||
<Grid Margin="10">
|
<Grid Margin="10">
|
||||||
<StackPanel>
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition />
|
||||||
|
<RowDefinition Height="15" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<!-- Left side of window -->
|
||||||
|
<StackPanel Margin="5">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<TextBlock Text="CS:GO folder found: " />
|
||||||
|
<TextBlock x:Name="lblCsgoFolderFound" Text="No" />
|
||||||
|
</StackPanel>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<TextBlock Text="CS:GO window found: " />
|
<TextBlock Text="CS:GO window found: " />
|
||||||
<TextBlock x:Name="lblCsgoWindowFound" Text="No" />
|
<TextBlock x:Name="lblCsgoWindowFound" Text="No" />
|
||||||
|
@ -18,7 +33,35 @@
|
||||||
<TextBlock Text="Console log found: " />
|
<TextBlock Text="Console log found: " />
|
||||||
<TextBlock x:Name="lblConsoleLogFound" Text="No" />
|
<TextBlock x:Name="lblConsoleLogFound" Text="No" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<TextBlock />
|
<!-- Only print when... -->
|
||||||
|
<GroupBox Margin="0,10,0,0" Header="Only print when..">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="the damage dealt is at least:" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Slider x:Name="sliderMinimumDealtDamage" Minimum="0" Maximum="100" Value="{Binding Settings.MinimumDealtDamage, ElementName=window}" Width="180" />
|
||||||
|
<TextBlock Margin="5,0,0,0" Text="{Binding Value, ElementName=sliderMinimumDealtDamage}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
<TextBlock Margin="0,10,0,0" Text="the damage dealt to me is at least:" />
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<Slider x:Name="sliderMinimumReceivedDamage" Minimum="0" Maximum="100" Value="{Binding Settings.MinimumReceivedDamage, ElementName=window}" Width="180" />
|
||||||
|
<TextBlock Margin="5,0,0,0" Text="{Binding Value, ElementName=sliderMinimumReceivedDamage}" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</GroupBox>
|
||||||
|
<!-- More properties -->
|
||||||
|
<CheckBox x:Name="chkPrintDeadPlayers" IsChecked="{Binding Settings.PrintDeadPlayers, ElementName=window}" Margin="0,10,0,0" Content="Print dead players" ToolTip="You can only see damage you dealt by yourself, so if someone got 70 damage by someone else and you deal 50 and kill him, the program doesn't see him as dead and prints it anyway." />
|
||||||
|
<CheckBox x:Name="chkWithholdDuplicateConsoleOutputs" IsChecked="{Binding Settings.WithholdDuplicateConsoleOutputs, ElementName=window}" Margin="0,5,0,0" Content="Withhold duplicate console outputs" ToolTip="For example when you die, and when the round ends, the damage is printed again. This option disables that." />
|
||||||
|
<CheckBox x:Name="chkPrintAmountOfShots" IsChecked="{Binding Settings.PrintAmountOfShots, ElementName=window}" Margin="0,5,0,0" Content="Print amount of shots for damage" ToolTip="Prints the amount of shots one used to deal the given damage." />
|
||||||
|
<CheckBox x:Name="chkUseSpecificTerms" IsChecked="{Binding Settings.UseSpecificTerms, ElementName=window}" Margin="0,5,0,0" Content="Use more specific terms" ToolTip="Uses 'tagged', 'lit' and 'one-shot' to distinguish more between damages." />
|
||||||
|
<CheckBox x:Name="chkPrintIngameChat" IsChecked="{Binding Settings.PrintIngameChat, ElementName=window}" Margin="0,5,0,0" Content="Print in in-game chat" ToolTip="Prints to the in-game chat. Which chat is used depends on the setting below. If off, it will only print it to the text box to the right." />
|
||||||
|
<CheckBox x:Name="chkPrintTeamChat" IsChecked="{Binding Settings.PrintTeamChat, ElementName=window}" Margin="0,5,0,0" Content="Print in team-chat" ToolTip="Prints in team-chat instead of all-chat, above setting must be on for this to matter." IsEnabled="{Binding IsChecked, ElementName=chkPrintIngameChat}" />
|
||||||
|
</StackPanel>
|
||||||
|
<!-- Right side of window -->
|
||||||
|
<Grid Grid.Column="1">
|
||||||
|
<TextBlock Text="Damage output:" />
|
||||||
|
<TextBox x:Name="txtDamageOutput" Margin="0,20,0,0" Background="#FF272727" IsReadOnly="True" />
|
||||||
|
</Grid>
|
||||||
|
<!-- Text at the bottom -->
|
||||||
|
<TextBlock Text="Made by Mathias Lui" Grid.ColumnSpan="2" Grid.Row="1" FontSize="10" HorizontalAlignment="Center" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Window>
|
</Window>
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
using System;
|
using SteamShared;
|
||||||
|
using SteamShared.SourceConfig;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
@ -12,6 +18,7 @@ using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using System.Windows.Navigation;
|
using System.Windows.Navigation;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
|
||||||
namespace DamagePrinterGUI
|
namespace DamagePrinterGUI
|
||||||
{
|
{
|
||||||
|
@ -20,9 +27,476 @@ namespace DamagePrinterGUI
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class MainWindow : Window
|
public partial class MainWindow : Window
|
||||||
{
|
{
|
||||||
|
static readonly uint WM_COPYDATA = 0x004A;
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
|
||||||
|
|
||||||
|
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||||
|
static extern int SendMessage(IntPtr windowHandle, uint message, IntPtr wParam, IntPtr lParam);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used for databinding.
|
||||||
|
/// </summary>
|
||||||
|
public Settings Settings { get; set; } = Globals.Settings;
|
||||||
|
|
||||||
|
private static readonly string myDocumentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||||
|
private static readonly string folderPath = System.IO.Path.Combine(myDocumentsPath, "CSGO Damage Printer");
|
||||||
|
private static readonly string settingsFilePath = System.IO.Path.Combine(folderPath, "settings.xml");
|
||||||
|
private static string consoleLogFileName = "console.log";
|
||||||
|
private static string? consoleLogFolderPath = null;
|
||||||
|
|
||||||
public MainWindow()
|
public MainWindow()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
|
if (!this.ensureConsoleLogAndGamePath())
|
||||||
|
{
|
||||||
|
MessageBox.Show("The console log could not be created.\n\nAs a workaround, try to create an autoexec config and adding the line 'con_logfile console.log' to it.", "Unknown setup error", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
this.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Task.Run(mainLoop);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void mainLoop()
|
||||||
|
{
|
||||||
|
string consoleLogPath = System.IO.Path.Combine(consoleLogFolderPath ?? string.Empty, consoleLogFileName);
|
||||||
|
|
||||||
|
var prevTaggedPlayers = new List<Tuple<string, int, int>>();
|
||||||
|
|
||||||
|
// here we start fresh at line 0 cause it got deleted
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
this.Dispatcher.Invoke(() => this.lblConsoleLogFound.Text = "No");
|
||||||
|
// Check for the window every now and then
|
||||||
|
bool initialScan = true;
|
||||||
|
bool consoleLogExists = false;
|
||||||
|
|
||||||
|
long oldFileSize = 0;
|
||||||
|
long nextLineOffset = 0;
|
||||||
|
if (this.findCsgoWindow())
|
||||||
|
{
|
||||||
|
this.Dispatcher.Invoke(() => this.lblCsgoWindowFound.Text = "Yes");
|
||||||
|
this.Dispatcher.Invoke(() => this.txtDamageOutput.AppendText("CS:GO Window found." + '\n'));
|
||||||
|
// We found the window so begin checking for the console
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (!findCsgoWindow())
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (!File.Exists(consoleLogPath))
|
||||||
|
// Not yet
|
||||||
|
continue;
|
||||||
|
|
||||||
|
this.Dispatcher.Invoke(() => this.lblConsoleLogFound.Text = "Yes");
|
||||||
|
|
||||||
|
if (Globals.Settings == null)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Log exists
|
||||||
|
|
||||||
|
bool update = false;
|
||||||
|
|
||||||
|
if (!consoleLogExists && initialScan)
|
||||||
|
{
|
||||||
|
consoleLogExists = true;
|
||||||
|
initialScan = false;
|
||||||
|
|
||||||
|
oldFileSize = 0;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
oldFileSize = new FileInfo(consoleLogPath).Length;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
nextLineOffset = oldFileSize; // bytes from the start of the file, by default not to read anything
|
||||||
|
}
|
||||||
|
|
||||||
|
long curFileSize = new FileInfo(consoleLogPath).Length;
|
||||||
|
if (curFileSize != oldFileSize)
|
||||||
|
{
|
||||||
|
update = true;
|
||||||
|
oldFileSize = curFileSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!update)
|
||||||
|
continue;
|
||||||
|
int damageTakenTotal = 0;
|
||||||
|
|
||||||
|
// Read in all the NEW lines of the console log
|
||||||
|
List<string> lines = new List<string>();
|
||||||
|
using (var fs = File.Open(consoleLogPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||||
|
{
|
||||||
|
fs.Position = nextLineOffset;
|
||||||
|
bool endOfFile = false;
|
||||||
|
|
||||||
|
while (!endOfFile)
|
||||||
|
{
|
||||||
|
string line = "";
|
||||||
|
bool endOfLine = false;
|
||||||
|
while (!endOfLine)
|
||||||
|
{
|
||||||
|
int nextByte = fs.ReadByte();
|
||||||
|
|
||||||
|
if (nextByte == -1 && line != "")
|
||||||
|
{
|
||||||
|
lines.Add(line);
|
||||||
|
endOfFile = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
char nextChar = (char)nextByte;
|
||||||
|
|
||||||
|
if (nextChar == '\n' && line != "")
|
||||||
|
{
|
||||||
|
lines.Add(line);
|
||||||
|
endOfLine = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (nextChar != '\r')
|
||||||
|
line += nextChar;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.ForEach(l => System.Diagnostics.Debug.WriteLine(l));
|
||||||
|
|
||||||
|
nextLineOffset = fs.Position;
|
||||||
|
}
|
||||||
|
|
||||||
|
var taggedPlayers = new List<Tuple<string, int, int>>();
|
||||||
|
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
/* -------------------------
|
||||||
|
Damage Given to "BOT Eugene" - 65 in 2 hits
|
||||||
|
-------------------------
|
||||||
|
Damage Taken from "BOT Eugene" - 117 in 4 hits*/
|
||||||
|
if (line.StartsWith("Damage Taken"))
|
||||||
|
{
|
||||||
|
Regex regexTaken = new Regex("Damage Taken from \"(.+?)\" - (\\d+) in \\d+ hits?");
|
||||||
|
Match takenMatch = regexTaken.Match(line);
|
||||||
|
|
||||||
|
if (takenMatch.Success)
|
||||||
|
{
|
||||||
|
damageTakenTotal += int.Parse(takenMatch.Groups[2].Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (line.StartsWith("Damage Given"))
|
||||||
|
{
|
||||||
|
Regex regexTaken = new Regex("Damage Given to \"(.+?)\" - (\\d+) in (\\d+) hits?");
|
||||||
|
Match givenMatch = regexTaken.Match(line);
|
||||||
|
|
||||||
|
if (givenMatch.Success)
|
||||||
|
{
|
||||||
|
string name = givenMatch.Groups[1].Value;
|
||||||
|
int damage = int.Parse(givenMatch.Groups[2].Value);
|
||||||
|
int hits = int.Parse(givenMatch.Groups[3].Value);
|
||||||
|
|
||||||
|
if ((Globals.Settings.PrintDeadPlayers || damage < 100) && damage > Globals.Settings.MinimumDealtDamage
|
||||||
|
&& taggedPlayers.FirstOrDefault(player => player.Item1 == name) == null)
|
||||||
|
{
|
||||||
|
// not in list yet so add
|
||||||
|
taggedPlayers.Add(new Tuple<string, int, int>(name, damage, hits));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (damageTakenTotal < Globals.Settings.MinimumReceivedDamage)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Globals.Settings.WithholdDuplicateConsoleOutputs && taggedPlayers.Count > 0 && areListsEqual(taggedPlayers, prevTaggedPlayers))
|
||||||
|
{
|
||||||
|
// Last is the same as previous, likely dealt damage, died and now the round ended and it was printed again
|
||||||
|
Console.WriteLine("Double console output.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
prevTaggedPlayers = taggedPlayers;
|
||||||
|
|
||||||
|
if (taggedPlayers.Count < 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string[] commands = new string[taggedPlayers.Count];
|
||||||
|
this.Dispatcher.Invoke(() => this.txtDamageOutput.AppendText("\n"));
|
||||||
|
// We had our minimum damage taken, so print the text
|
||||||
|
for (int i = 0; i < commands.Length; i++)
|
||||||
|
{
|
||||||
|
string textToAdd = string.Empty;
|
||||||
|
commands[i] += $"{(Globals.Settings.PrintTeamChat ? "say_team" : "say")} \"";
|
||||||
|
|
||||||
|
if (Globals.Settings.UseSpecificTerms)
|
||||||
|
{
|
||||||
|
if (taggedPlayers[i].Item2 >= 100)
|
||||||
|
{
|
||||||
|
// Dead
|
||||||
|
textToAdd = $"{taggedPlayers[i].Item1} is dead: {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
else if (taggedPlayers[i].Item2 > 90)
|
||||||
|
{
|
||||||
|
// One-shot
|
||||||
|
textToAdd = $"{taggedPlayers[i].Item1} is one-shot: {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
else if (taggedPlayers[i].Item2 >= 70)
|
||||||
|
{
|
||||||
|
// Lit
|
||||||
|
textToAdd = $"{taggedPlayers[i].Item1} is lit for {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Tagged
|
||||||
|
textToAdd = $"{taggedPlayers[i].Item1} is tagged for {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
textToAdd = $"{taggedPlayers[i].Item1} is hit for {taggedPlayers[i].Item2}";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Globals.Settings.PrintAmountOfShots)
|
||||||
|
textToAdd += $" in {taggedPlayers[i].Item3}";
|
||||||
|
|
||||||
|
commands[i] += textToAdd;
|
||||||
|
|
||||||
|
commands[i] += "\"";
|
||||||
|
|
||||||
|
|
||||||
|
this.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
if (this.txtDamageOutput.Text.Length > 10_000)
|
||||||
|
{
|
||||||
|
// Too much text, so delete some
|
||||||
|
this.txtDamageOutput.Text = this.txtDamageOutput.Text.Remove(0, this.txtDamageOutput.Text.IndexOf('\n', this.txtDamageOutput.Text.Length - 5_000) + 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Print to local program "console"
|
||||||
|
if (!Globals.Settings.PrintIngameChat)
|
||||||
|
textToAdd = $"({textToAdd})";
|
||||||
|
|
||||||
|
this.Dispatcher.Invoke(() =>
|
||||||
|
{
|
||||||
|
this.txtDamageOutput.AppendText(textToAdd + '\n');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Notify players in-game
|
||||||
|
if (Globals.Settings.PrintIngameChat)
|
||||||
|
ExecuteCommands(false, commands);
|
||||||
|
|
||||||
|
// End of each actual check
|
||||||
|
Thread.Sleep(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.Dispatcher.Invoke(() => this.lblCsgoWindowFound.Text = "No");
|
||||||
|
// Ensure a smaller log size
|
||||||
|
File.Delete(consoleLogPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
prevTaggedPlayers.Clear();
|
||||||
|
// End of game-alive-check, check less often
|
||||||
|
Thread.Sleep(2000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool areListsEqual(List<Tuple<string, int, int>> list1, List<Tuple<string, int, int>> list2)
|
||||||
|
{
|
||||||
|
if (list1.Count != list2.Count)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// still same length
|
||||||
|
for (int i = 0; i < list1.Count; i++)
|
||||||
|
{
|
||||||
|
if (list1[i].Item1 != list2[i].Item1)
|
||||||
|
return false;
|
||||||
|
if (list1[i].Item2 != list2[i].Item2)
|
||||||
|
return false;
|
||||||
|
if (list1[i].Item3 != list2[i].Item3)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ExecuteCommands(bool triggeredByInGameCommand, params string[] cmds)
|
||||||
|
{
|
||||||
|
if (cmds == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
IntPtr hWnd = FindWindow("Valve001", null!);
|
||||||
|
|
||||||
|
if (hWnd == IntPtr.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int chatTimeoutMs = 700;
|
||||||
|
int commandsHandled = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < cmds.Length; i++)
|
||||||
|
{
|
||||||
|
if (cmds[i] == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
cmds[i] = cmds[i].Trim();
|
||||||
|
|
||||||
|
COPYDATASTRUCT data;
|
||||||
|
data.dwData = 0;
|
||||||
|
data.cbData = (uint)cmds[i].Length + 1;
|
||||||
|
data.lpData = cmds[i];
|
||||||
|
|
||||||
|
if (triggeredByInGameCommand)
|
||||||
|
Thread.Sleep(chatTimeoutMs);
|
||||||
|
|
||||||
|
// Allocate for data
|
||||||
|
IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(data));
|
||||||
|
Marshal.StructureToPtr(data, ptr, false);
|
||||||
|
|
||||||
|
int ret = SendMessage(hWnd, WM_COPYDATA, IntPtr.Zero, ptr);
|
||||||
|
|
||||||
|
Console.WriteLine(cmds[i]);
|
||||||
|
|
||||||
|
// Free data
|
||||||
|
Marshal.FreeHGlobal(ptr);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
commandsHandled++;
|
||||||
|
|
||||||
|
if (cmds[i].StartsWith("say") || cmds[i].StartsWith("say_team"))
|
||||||
|
Thread.Sleep(chatTimeoutMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmds.Length > 0 && commandsHandled == cmds.Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool findCsgoWindow()
|
||||||
|
{
|
||||||
|
return FindWindow("Valve001", null!) != IntPtr.Zero;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveSettings()
|
||||||
|
{
|
||||||
|
if (!Directory.Exists(folderPath))
|
||||||
|
Directory.CreateDirectory(folderPath);
|
||||||
|
|
||||||
|
if (File.Exists(settingsFilePath))
|
||||||
|
File.Delete(settingsFilePath);
|
||||||
|
|
||||||
|
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
|
||||||
|
|
||||||
|
using (var fs = File.Open(settingsFilePath, FileMode.OpenOrCreate, FileAccess.ReadWrite))
|
||||||
|
{
|
||||||
|
serializer.Serialize(fs, Globals.Settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ensureConsoleLogAndGamePath()
|
||||||
|
{
|
||||||
|
// Get csgo path
|
||||||
|
var csgoPath = new SteamHelper().GetGamePathFromExactName("Counter-Strike: Global Offensive");
|
||||||
|
|
||||||
|
if (csgoPath == null)
|
||||||
|
{
|
||||||
|
this.lblCsgoFolderFound.Text = "No";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
this.lblCsgoFolderFound.Text = "Yes";
|
||||||
|
}
|
||||||
|
|
||||||
|
string gamePath = System.IO.Path.Combine(csgoPath, "csgo");
|
||||||
|
string configsPath = System.IO.Path.Combine(gamePath, "cfg");
|
||||||
|
consoleLogFolderPath = gamePath; // To use later
|
||||||
|
string autoexecPath = System.IO.Path.Combine(configsPath, "autoexec.cfg");
|
||||||
|
|
||||||
|
if (!File.Exists(autoexecPath))
|
||||||
|
{
|
||||||
|
// Create autoexec and enable console logging
|
||||||
|
File.WriteAllText(autoexecPath, "con_logfile " + consoleLogFileName);
|
||||||
|
ExecuteCommands(false, "exec autoexec");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// First create a backup in case our code has a bug that fucks up the autoexec or something
|
||||||
|
File.Delete(System.IO.Path.Combine(folderPath, "autoexec.backup"));
|
||||||
|
File.Copy(autoexecPath, System.IO.Path.Combine(folderPath, "autoexec.backup"));
|
||||||
|
|
||||||
|
// Check if autoexec has the command in it. If not, create it
|
||||||
|
var autoexec = SourceCFG.FromFile(autoexecPath);
|
||||||
|
|
||||||
|
if (autoexec == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var foundCommand = autoexec.Commands?.FirstOrDefault(line => line.CommandName?.ToLower() == "con_logfile");
|
||||||
|
if (foundCommand == null)
|
||||||
|
{
|
||||||
|
// line not found so add it.
|
||||||
|
File.AppendAllText(autoexecPath, Environment.NewLine + "con_logfile " + consoleLogFileName);
|
||||||
|
ExecuteCommands(false, "exec autoexec");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// user or we ourself added this command before, so just use the path specified here
|
||||||
|
string? newConsoleLogFileName = foundCommand.GetValuesAsOne();
|
||||||
|
|
||||||
|
if (newConsoleLogFileName != null)
|
||||||
|
{
|
||||||
|
// We now use the set one, which may differ, or may not
|
||||||
|
consoleLogFileName = newConsoleLogFileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadSettings()
|
||||||
|
{
|
||||||
|
if (File.Exists(settingsFilePath))
|
||||||
|
{
|
||||||
|
XmlSerializer serializer = new XmlSerializer(typeof(Settings));
|
||||||
|
|
||||||
|
using (var fs = File.Open(settingsFilePath, FileMode.Open, FileAccess.Read))
|
||||||
|
{
|
||||||
|
Settings? settings = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
settings = (Settings?)serializer.Deserialize(fs);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
MessageBox.Show("There was an error loading the settings in " + settingsFilePath + ".\n\nYour settings have been reset to default. If you get this more often please write me an email..Sorry for that :(", "Error loading settings", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings != null)
|
||||||
|
Globals.Settings.ApplySettingsFrom(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#region events
|
||||||
|
private void window_Loaded(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
// Load settings
|
||||||
|
this.loadSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
|
||||||
|
{
|
||||||
|
// Save settings
|
||||||
|
this.saveSettings();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
|
||||||
|
struct COPYDATASTRUCT
|
||||||
|
{
|
||||||
|
public ulong dwData;
|
||||||
|
public uint cbData;
|
||||||
|
public string lpData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
112
DamagePrinter/DamagePrinterGUI/Settings.cs
Normal file
112
DamagePrinter/DamagePrinterGUI/Settings.cs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
namespace DamagePrinterGUI
|
||||||
|
{
|
||||||
|
public class Settings : DependencyObject, ICloneable
|
||||||
|
{
|
||||||
|
public int MinimumDealtDamage
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke(() => (int)GetValue(MinimumDealtDamageProperty)); }
|
||||||
|
set { SetValue(MinimumDealtDamageProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for MinimumDealtDamage. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty MinimumDealtDamageProperty =
|
||||||
|
DependencyProperty.Register("MinimumDealtDamage", typeof(int), typeof(Settings), new PropertyMetadata(20));
|
||||||
|
|
||||||
|
|
||||||
|
public int MinimumReceivedDamage
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke( () => (int)GetValue(MinimumReceivedDamageProperty)); }
|
||||||
|
set { SetValue(MinimumReceivedDamageProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for MinimumReceivedDamage. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty MinimumReceivedDamageProperty =
|
||||||
|
DependencyProperty.Register("MinimumReceivedDamage", typeof(int), typeof(Settings), new PropertyMetadata(100));
|
||||||
|
|
||||||
|
|
||||||
|
public bool PrintDeadPlayers
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke( () => (bool)GetValue(PrintDeadPlayersProperty)); }
|
||||||
|
set { SetValue(PrintDeadPlayersProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for PrintDeadPlayers. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty PrintDeadPlayersProperty =
|
||||||
|
DependencyProperty.Register("PrintDeadPlayers", typeof(bool), typeof(Settings), new PropertyMetadata(false));
|
||||||
|
|
||||||
|
|
||||||
|
public bool WithholdDuplicateConsoleOutputs
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke( () => (bool)GetValue(WithholdDuplicateConsoleOutputsProperty)); }
|
||||||
|
set { SetValue(WithholdDuplicateConsoleOutputsProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for WithholdDuplicateConsoleOutputs. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty WithholdDuplicateConsoleOutputsProperty =
|
||||||
|
DependencyProperty.Register("WithholdDuplicateConsoleOutputs", typeof(bool), typeof(Settings), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
|
||||||
|
public bool PrintAmountOfShots
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke( () => (bool)GetValue(PrintAmountOfShotsProperty)); }
|
||||||
|
set { SetValue(PrintAmountOfShotsProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for PrintAmountOfShots. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty PrintAmountOfShotsProperty =
|
||||||
|
DependencyProperty.Register("PrintAmountOfShots", typeof(bool), typeof(Settings), new PropertyMetadata(false));
|
||||||
|
|
||||||
|
|
||||||
|
public bool UseSpecificTerms
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke( () => (bool)GetValue(UseSpecificTermsProperty)); }
|
||||||
|
set { SetValue(UseSpecificTermsProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for UseSpecificTerms. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty UseSpecificTermsProperty =
|
||||||
|
DependencyProperty.Register("UseSpecificTerms", typeof(bool), typeof(Settings), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
|
||||||
|
public bool PrintIngameChat
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke( () => (bool)GetValue(PrintIngameChatProperty)); }
|
||||||
|
set { SetValue(PrintIngameChatProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for PrintIngameChat. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty PrintIngameChatProperty =
|
||||||
|
DependencyProperty.Register("PrintIngameChat", typeof(bool), typeof(Settings), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
|
||||||
|
public bool PrintTeamChat
|
||||||
|
{
|
||||||
|
get { return this.Dispatcher.Invoke( () => (bool)GetValue(PrintTeamChatProperty)); }
|
||||||
|
set { SetValue(PrintTeamChatProperty, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Using a DependencyProperty as the backing store for PrintTeamChat. This enables animation, styling, binding, etc...
|
||||||
|
public static readonly DependencyProperty PrintTeamChatProperty =
|
||||||
|
DependencyProperty.Register("PrintTeamChat", typeof(bool), typeof(Settings), new PropertyMetadata(true));
|
||||||
|
|
||||||
|
public void ApplySettingsFrom(Settings settings)
|
||||||
|
{
|
||||||
|
foreach (System.Reflection.PropertyInfo property in typeof(Settings).GetProperties().Where(p => p.CanWrite))
|
||||||
|
{
|
||||||
|
property.SetValue(this, property.GetValue(settings, null), null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
return this.MemberwiseClone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -214,53 +214,53 @@ namespace SteamShared
|
||||||
|
|
||||||
private void populateGameInfo(SteamGame game, Element appStateVdf)
|
private void populateGameInfo(SteamGame game, Element appStateVdf)
|
||||||
{
|
{
|
||||||
game.Name = appStateVdf["name"].Value;
|
game.Name = appStateVdf["name"]?.Value;
|
||||||
|
|
||||||
game.InstallFolderName = appStateVdf["installdir"].Value;
|
game.InstallFolderName = appStateVdf["installdir"]?.Value;
|
||||||
|
|
||||||
if (int.TryParse(appStateVdf["appid"].Value, out int appId))
|
if (int.TryParse(appStateVdf["appid"]?.Value, out int appId))
|
||||||
{
|
{
|
||||||
game.AppId = appId;
|
game.AppId = appId;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (int.TryParse(appStateVdf["StateFlags"].Value, out int stateFlags))
|
if (int.TryParse(appStateVdf["StateFlags"]?.Value, out int stateFlags))
|
||||||
{
|
{
|
||||||
game.GameState = stateFlags;
|
game.GameState = stateFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long.TryParse(appStateVdf["LastUpdated"].Value, out long lastUpdated))
|
if (long.TryParse(appStateVdf["LastUpdated"]?.Value, out long lastUpdated))
|
||||||
{
|
{
|
||||||
game.LastUpdated = fromUnixFormat(lastUpdated);
|
game.LastUpdated = fromUnixFormat(lastUpdated);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long.TryParse(appStateVdf["LastOwner"].Value, out long lastOwner))
|
if (long.TryParse(appStateVdf["LastOwner"]?.Value, out long lastOwner))
|
||||||
{
|
{
|
||||||
game.LastOwnerSteam64Id = lastOwner;
|
game.LastOwnerSteam64Id = lastOwner;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long.TryParse(appStateVdf["BytesToDownload"].Value, out long bytesToDownload))
|
if (long.TryParse(appStateVdf["BytesToDownload"]?.Value, out long bytesToDownload))
|
||||||
{
|
{
|
||||||
game.BytesToDownload = bytesToDownload;
|
game.BytesToDownload = bytesToDownload;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long.TryParse(appStateVdf["BytesDownloaded"].Value, out long bytesDownloaded))
|
if (long.TryParse(appStateVdf["BytesDownloaded"]?.Value, out long bytesDownloaded))
|
||||||
{
|
{
|
||||||
game.BytesDownloaded = bytesDownloaded;
|
game.BytesDownloaded = bytesDownloaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long.TryParse(appStateVdf["BytesToStage"].Value, out long bytesToStage))
|
if (long.TryParse(appStateVdf["BytesToStage"]?.Value, out long bytesToStage))
|
||||||
{
|
{
|
||||||
game.BytesToStage = bytesToStage;
|
game.BytesToStage = bytesToStage;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long.TryParse(appStateVdf["BytesStaged"].Value, out long bytesStaged))
|
if (long.TryParse(appStateVdf["BytesStaged"]?.Value, out long bytesStaged))
|
||||||
{
|
{
|
||||||
game.BytesStaged = bytesStaged;
|
game.BytesStaged = bytesStaged;
|
||||||
}
|
}
|
||||||
|
|
||||||
game.KeepAutomaticallyUpdated = appStateVdf["AutoUpdateBehavior"].Value != "0";
|
game.KeepAutomaticallyUpdated = appStateVdf["AutoUpdateBehavior"]?.Value != "0";
|
||||||
|
|
||||||
game.AllowOtherUpdatesWhileRunning = appStateVdf["AllowOtherDownloadsWhileRunning"].Value != "0";
|
game.AllowOtherUpdatesWhileRunning = appStateVdf["AllowOtherDownloadsWhileRunning"]?.Value != "0";
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue