diff --git a/SteamShared/SteamShared/SteamShared/CsgoHelper.cs b/SteamShared/SteamShared/SteamShared/CsgoHelper.cs index 67206d7..37406c6 100644 --- a/SteamShared/SteamShared/SteamShared/CsgoHelper.cs +++ b/SteamShared/SteamShared/SteamShared/CsgoHelper.cs @@ -7,55 +7,22 @@ using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; -using System.Text; using System.Text.RegularExpressions; -using System.Threading.Tasks; using System.Management; using Pfim; using System.Drawing; namespace SteamShared { + /// + /// A class that aids in getting information about CS:GO. + /// public class CsgoHelper { - public string? CsgoPath { get; set; } - - public static readonly float DuckModifier = 0.34f; - - public static readonly float WalkModifier = 0.52f; - - public static readonly int GameID = 730; - /// - /// Gets the prefixes allowed for maps when using . + /// Empty constructor. + /// Make sure the other constructor is called before using the object. /// - /// - /// If adjusted, should also be adjusted to set the type. - /// - private readonly string[] validMapPrefixes = new[] - { - "de", - "cs", - "dz", - "ar" - }; - - /// - /// Gets the files relative to the CS:GO install path that are checked when validating. - /// - private readonly string[] filesToValidate = new[] - { - "csgo\\scripts\\items\\items_game.txt" // Item info (weapon stats etc.) - }; - - /// - /// Gets the directories relative to the CS:GO install path that are checked when validating. - /// - private readonly string[] directoriesToValidate = new[] - { - "csgo\\resource\\overviews" // Map overviews - }; - public CsgoHelper() { // Nothing to do, don't use this ctor, aside from before the program initialises. @@ -70,37 +37,18 @@ namespace SteamShared this.CsgoPath = csgoPath; } + /// + /// The absolute path to the CS:GO root directory. + /// + public string? CsgoPath { get; set; } + /// /// Validates files and directories for CS:GO installed in the path. /// /// whether the files and directories exist. public bool Validate() { - return this.Validate(this.CsgoPath!); - } - - /// - /// Gets a handle to the currently running CS:GO instance. - /// - /// a tuple containing the process handle, as well as the arguments it was started with, either can be null. - public (Process?,string?) GetRunningCsgo() - { - // This is used as the normal process handle - Process? csgoProcess = Process.GetProcessesByName("csgo").FirstOrDefault(p => Globals.ComparePaths(p.MainModule?.FileName!, this.CsgoPath!)); - - // And this is used for grabbing the command line arguments the process was started with - string? cmdLine = string.Empty; - - var mgmtClass = new ManagementClass("Win32_Process"); - foreach (ManagementObject o in mgmtClass.GetInstances()) - { - if (o["Name"].Equals("csgo.exe")) - { - cmdLine = o["CommandLine"].ToString(); - } - } - - return (csgoProcess, cmdLine); + return this.Validate(this.CsgoPath); } /// @@ -112,8 +60,11 @@ namespace SteamShared /// /// The path to the CS:GO install directory, in which the executable resides. /// whether the files and directories exist. - public bool Validate(string csgoPath) + public bool Validate(string? csgoPath) { + if (csgoPath is null) + return false; + foreach (string file in this.filesToValidate) { if (!File.Exists(Path.Combine(csgoPath, file))) @@ -129,6 +80,30 @@ namespace SteamShared return true; } + /// + /// Gets a handle to the currently running CS:GO instance. + /// + /// a tuple containing the process handle, as well as the arguments it was started with, either can be null. + public (Process? processHandle, string? startArguments) GetRunningCsgo() + { + // This is used as the normal process handle + Process? csgoProcess = Process.GetProcessesByName("csgo").FirstOrDefault(p => Globals.ComparePaths(p.MainModule?.FileName!, this.CsgoPath!)); + + // And this is used for grabbing the command line arguments the process was started with + string? cmdLine = string.Empty; + + var mgmtClass = new ManagementClass("Win32_Process"); + foreach (ManagementObject o in mgmtClass.GetInstances()) + { + if (o["Name"].Equals("csgo.exe")) + { + cmdLine = o["CommandLine"].ToString(); + } + } + + return (csgoProcess, cmdLine); + } + /// /// Gets all maps and tries to fill all the information it can find about it. /// @@ -391,6 +366,97 @@ namespace SteamShared return weapons; } + /// + /// Reads entity list from uncompressed BSP file. + /// + /// The absolute path to the BSP file. + /// the entity list, null if actual length differed from length specified in file, or a general error occurred. + public string? ReadEntityListFromBsp(string bspFilePath) + { + using (var bspFile = File.OpenRead(bspFilePath)) + { + using (var reader = new BinaryReader(bspFile)) + { + reader.BaseStream.Position = 8; // Skip magic bytes and file version + int offset = reader.ReadInt32(); // Lump data offset from beginning of file + int length = reader.ReadInt32(); // Length of lump data + + reader.BaseStream.Position = offset; + char[] chars = new char[length]; + int charsRead = reader.Read(chars, 0, length); + + if (charsRead == length) + { + // Everything was read + return new string(chars); + } + } + } + return null; + } + + /// + /// Reads packed files from a BSP and checks for NAV and AIN files. + /// + /// The absolute path to the BSP file. + /// a tuple containing whether NAV or AIN files were found, as well as the parsed NAV mesh. + public (bool navFilesFound, bool ainFilesFound, NavMesh? navMesh) ReadIfPackedNavFilesInBsp(string bspFilePath) + { + bool navFound = false; + bool ainFound = false; + byte[]? readZipBytes = null; + + using (var bspFile = File.OpenRead(bspFilePath)) + { + using (var reader = new BinaryReader(bspFile)) + { + // Skip stuff before (lumps + (pakfile index * lump array item length)) + reader.BaseStream.Position = 8 + (40 * 16); + + // Get lump pos and size + int offset = reader.ReadInt32(); + int length = reader.ReadInt32(); + + // Read zip file + reader.BaseStream.Position = offset; + readZipBytes = reader.ReadBytes(length); + } + } + + if (readZipBytes == null) + return (false, false, null); + + using var stream = new MemoryStream(readZipBytes); + + // Packed files are contained in a ZIP file within the BSP file + using var zip = new ZipArchive(stream, ZipArchiveMode.Read); + + NavMesh? nav = null; + foreach (var entry in zip.Entries) + { + if (entry.FullName.ToLower().EndsWith(".nav")) + { + // Found a packed NAV file + navFound = true; + nav = NavFile.Parse(entry.Open()); + } + if (entry.FullName.ToLower().EndsWith(".ain")) + // Found a packed AIN file + ainFound = true; + + if (navFound && ainFound) + { + // If both are already found, return prematurely, + // as we don't care how many there are + return (navFound, ainFound, nav); + } + } + + // We get here, if either no NAV or no AIN file has been found + // If navFound is null, nav will be null as well + return (navFound, ainFound, nav); + } + /// /// Gets whether a given weapon can be fired (Hint: You can't shoot knives, at least not in the usual sense). /// @@ -404,7 +470,7 @@ namespace SteamShared if (prefabTrace != null) { // Stuff involving prefab trace here - if(prefabTrace.FirstOrDefault(pr => pr == "primary" || pr == "secondary") != null) + if (prefabTrace.FirstOrDefault(pr => pr == "primary" || pr == "secondary") != null) // Allow any weapon in the primary or secondary slot isWhitelisted = true; } @@ -470,7 +536,7 @@ namespace SteamShared // =========================== ATTRIBUTES =========================== // // Base damage - if (weapon.BaseDamage == -1) + if (weapon.BaseDamage == -1) { string damage = attributes["damage"]?.Value!; if (damage != null) @@ -608,7 +674,7 @@ namespace SteamShared { string fileName = Path.GetFileName(mapPath.ToLower()); - foreach(string prefix in this.validMapPrefixes) + foreach (string prefix in this.validMapPrefixes) { if (fileName.StartsWith(prefix.ToLower())) return true; @@ -617,97 +683,6 @@ namespace SteamShared return false; } - /// - /// Reads entity list from uncompressed BSP file. - /// - /// The absolute path to the BSP file. - /// the entity list, null if actual length differed from length specified in file, or a general error occurred. - public string? ReadEntityListFromBsp(string bspFilePath) - { - using(var bspFile = File.OpenRead(bspFilePath)) - { - using(var reader = new BinaryReader(bspFile)) - { - reader.BaseStream.Position = 8; // Skip magic bytes and file version - int offset = reader.ReadInt32(); // Lump data offset from beginning of file - int length = reader.ReadInt32(); // Length of lump data - - reader.BaseStream.Position = offset; - char[] chars = new char[length]; - int charsRead = reader.Read(chars, 0, length); - - if(charsRead == length) - { - // Everything was read - return new string(chars); - } - } - } - return null; - } - - /// - /// Reads packed files from a BSP and checks for NAV and AIN files. - /// - /// The absolute path to the BSP file. - /// a tuple containing whether NAV or AIN files were found, as well as the parsed NAV mesh. - public (bool NavFilesFound, bool AinFilesFound, NavMesh? NavMesh) ReadIfPackedNavFilesInBsp(string bspFilePath) - { - bool navFound = false; - bool ainFound = false; - byte[]? readZipBytes = null; - - using (var bspFile = File.OpenRead(bspFilePath)) - { - using (var reader = new BinaryReader(bspFile)) - { - // Skip stuff before (lumps + (pakfile index * lump array item length)) - reader.BaseStream.Position = 8 + (40 * 16); - - // Get lump pos and size - int offset = reader.ReadInt32(); - int length = reader.ReadInt32(); - - // Read zip file - reader.BaseStream.Position = offset; - readZipBytes = reader.ReadBytes(length); - } - } - - if (readZipBytes == null) - return (false, false, null); - - using var stream = new MemoryStream(readZipBytes); - - // Packed files are contained in a ZIP file within the BSP file - using var zip = new ZipArchive(stream, ZipArchiveMode.Read); - - NavMesh? nav = null; - foreach (var entry in zip.Entries) - { - if (entry.FullName.ToLower().EndsWith(".nav")) - { - // Found a packed NAV file - navFound = true; - nav = NavFile.Parse(entry.Open()); - } - if (entry.FullName.ToLower().EndsWith(".ain")) - // Found a packed AIN file - ainFound = true; - - if (navFound && ainFound) - { - // If both are already found, return prematurely, - // as we don't care how many there are - return (navFound, ainFound, nav); - } - } - - // We get here, if either no NAV or no AIN file has been found - // If navFound is null, nav will be null as well - return (navFound, ainFound, nav); - } - /// /// Checks whether a lump is unused (all zeroes). /// @@ -715,7 +690,7 @@ namespace SteamShared /// a bool indicating if the lump is unused. private bool isLumpUnused(byte[] lump) { - for(int i = 0; i < lump.Length; i++) + for (int i = 0; i < lump.Length; i++) { if (lump[i] != 0) return false; @@ -723,5 +698,50 @@ namespace SteamShared return true; } + + /// + /// The multiplier for player movement speed while ducking. + /// + public static readonly float DuckModifier = 0.34f; + + /// + /// The multiplier for player movement speed while shifting. + /// + public static readonly float WalkModifier = 0.52f; + + /// + /// The Steam game ID of CS:GO. + /// + public static readonly int GameID = 730; + + /// + /// Gets the prefixes allowed for maps when using . + /// + /// + /// If adjusted, should also be adjusted to set the type. + /// + private readonly string[] validMapPrefixes = new[] + { + "de", + "cs", + "dz", + "ar" + }; + + /// + /// Gets the files relative to the CS:GO install path that are checked when validating. + /// + private readonly string[] filesToValidate = new[] + { + "csgo\\scripts\\items\\items_game.txt" // Item info (weapon stats etc.) + }; + + /// + /// Gets the directories relative to the CS:GO install path that are checked when validating. + /// + private readonly string[] directoriesToValidate = new[] + { + "csgo\\resource\\overviews" // Map overviews + }; } }