From 1a62ac20060a070ee4b63775a9ac796f6d11ac37 Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Sat, 24 Dec 2022 20:15:58 -0800 Subject: [PATCH] Add BSP wrapper --- .vscode/launch.json | 2 +- BurnOutSharp.Wrappers/BSP.cs | 217 +++++++++++++++++++++++++++++++++++ BurnOutSharp.Wrappers/VPK.cs | 4 +- Test/Program.cs | 30 +++++ 4 files changed, 250 insertions(+), 3 deletions(-) create mode 100644 BurnOutSharp.Wrappers/BSP.cs diff --git a/.vscode/launch.json b/.vscode/launch.json index 0c6485ae..dc6534de 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -11,7 +11,7 @@ "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. "program": "${workspaceFolder}/Test/bin/Debug/net6.0/Test.dll", - "args": [], + "args": ["--info", "R:\\BurnOutSharp Testing Files\\_HLLibTest\\as_oilrig.bsp"], "cwd": "${workspaceFolder}/Test", // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console "console": "internalConsole", diff --git a/BurnOutSharp.Wrappers/BSP.cs b/BurnOutSharp.Wrappers/BSP.cs new file mode 100644 index 00000000..931613c7 --- /dev/null +++ b/BurnOutSharp.Wrappers/BSP.cs @@ -0,0 +1,217 @@ +using System; +using System.IO; +using System.Linq; +using BurnOutSharp.Utilities; + +namespace BurnOutSharp.Wrappers +{ + public class BSP : WrapperBase + { + #region Pass-Through Properties + + #region Header + + /// + public uint Version => _file.Header.Version; + + #endregion + + #region Lumps + + /// + public Models.BSP.Lump[] Lumps => _file.Lumps; + + #endregion + + #region Texture Header + + /// + public uint TextureCount => _file.TextureHeader.TextureCount; + + /// + public uint[] Offsets => _file.TextureHeader.Offsets; + + #endregion + + #endregion + + #region Extension Properties + + // TODO: Figure out what extension oroperties are needed + + #endregion + + #region Instance Variables + + /// + /// Internal representation of the BSP + /// + private Models.BSP.File _file; + + #endregion + + #region Constructors + + /// + /// Private constructor + /// + private BSP() { } + + /// + /// Create an BSP from a byte array and offset + /// + /// Byte array representing the BSP + /// Offset within the array to parse + /// An BSP wrapper on success, null on failure + public static BSP Create(byte[] data, int offset) + { + // If the data is invalid + if (data == null) + return null; + + // If the offset is out of bounds + if (offset < 0 || offset >= data.Length) + return null; + + // Create a memory stream and use that + MemoryStream dataStream = new MemoryStream(data, offset, data.Length - offset); + return Create(dataStream); + } + + /// + /// Create anVPK from a Stream + /// + /// Stream representing the executable + /// An VPK wrapper on success, null on failure + public static BSP Create(Stream data) + { + // If the data is invalid + if (data == null || data.Length == 0 || !data.CanSeek || !data.CanRead) + return null; + + var file = Builders.BSP.ParseFile(data); + if (file == null) + return null; + + var wrapper = new BSP + { + _file = file, + _dataSource = DataSource.Stream, + _streamData = data, + }; + return wrapper; + } + + #endregion + + #region Printing + + /// + public override void Print() + { + Console.WriteLine("BSP Information:"); + Console.WriteLine("-------------------------"); + Console.WriteLine(); + + PrintHeader(); + PrintLumps(); + PrintTextureHeader(); + } + + /// + /// Print header information + /// + private void PrintHeader() + { + Console.WriteLine(" Header Information:"); + Console.WriteLine(" -------------------------"); + Console.WriteLine($" Version: {Version}"); + Console.WriteLine(); + } + + /// + /// Print lumps information + /// + private void PrintLumps() + { + Console.WriteLine(" Lumps Information:"); + Console.WriteLine(" -------------------------"); + if (Lumps == null || Lumps.Length == 0) + { + Console.WriteLine(" No lumps"); + } + else + { + for (int i = 0; i < Lumps.Length; i++) + { + var lump = Lumps[i]; + string specialLumpName = string.Empty; + switch (i) + { + case Builders.BSP.HL_BSP_LUMP_ENTITIES: + specialLumpName = " (entities)"; + break; + case Builders.BSP.HL_BSP_LUMP_TEXTUREDATA: + specialLumpName = " (texture data)"; + break; + } + + Console.WriteLine($" Lump {i}{specialLumpName}"); + Console.WriteLine($" Offset: {lump.Offset}"); + Console.WriteLine($" Length: {lump.Length}"); + } + } + Console.WriteLine(); + } + + /// + /// Print texture header information + /// + private void PrintTextureHeader() + { + Console.WriteLine(" Texture Header Information:"); + Console.WriteLine(" -------------------------"); + Console.WriteLine($" Texture count: {TextureCount}"); + Console.WriteLine($" Offsets: {string.Join(", ", Offsets)}"); + Console.WriteLine(); + } + + #endregion + + #region Extraction + + /// + /// Extract all files from the VPK to an output directory + /// + /// Output directory to write to + /// True if all files extracted, false otherwise + public bool ExtractAll(string outputDirectory) + { + return false; + } + + /// + /// Extract a lump from the VPK to an output directory by index + /// + /// Lump index to extract + /// Output directory to write to + /// True if the lump extracted, false otherwise + public bool ExtractLump(int index, string outputDirectory) + { + return false; + } + + /// + /// Extract a texture from the VPK to an output directory by index + /// + /// Lump index to extract + /// Output directory to write to + /// True if the texture extracted, false otherwise + public bool ExtractTexture(int index, string outputDirectory) + { + return false; + } + + #endregion + } +} \ No newline at end of file diff --git a/BurnOutSharp.Wrappers/VPK.cs b/BurnOutSharp.Wrappers/VPK.cs index 4719bbf1..dd484e02 100644 --- a/BurnOutSharp.Wrappers/VPK.cs +++ b/BurnOutSharp.Wrappers/VPK.cs @@ -107,7 +107,7 @@ namespace BurnOutSharp.Wrappers #region Instance Variables /// - /// Internal representation of the executable + /// Internal representation of the VPK /// private Models.VPK.File _file; @@ -128,7 +128,7 @@ namespace BurnOutSharp.Wrappers /// /// Create an VPK from a byte array and offset /// - /// Byte array representing the executable + /// Byte array representing the VPK /// Offset within the array to parse /// An VPK wrapper on success, null on failure public static VPK Create(byte[] data, int offset) diff --git a/Test/Program.cs b/Test/Program.cs index 19fcc23f..8db40c74 100644 --- a/Test/Program.cs +++ b/Test/Program.cs @@ -311,6 +311,25 @@ namespace Test bfpk.Print(); } + // BSP + else if (IsBSP(magic)) + { + // Build the BSP information + Console.WriteLine("Creating BSP deserializer"); + Console.WriteLine(); + + var bsp = BSP.Create(stream); + if (bsp == null) + { + Console.WriteLine("Something went wrong parsing BSP"); + Console.WriteLine(); + return; + } + + // Print the BSP info to screen + bsp.Print(); + } + // MoPaQ (MPQ) archive else if (IsMoPaQ(magic)) { @@ -383,6 +402,17 @@ namespace Test return magic[0] == 'B' && magic[1] == 'F' && magic[2] == 'P' && magic[3] == 'K'; } + /// + /// Determine if the magic bytes indicate an BFPK archive + /// + private static bool IsBSP(byte[] magic) + { + if (magic == null || magic.Length < 4) + return false; + + return magic[0] == 0x1e && magic[1] == 0x00 && magic[2] == 0x00 && magic[3] == 0x00; + } + /// /// Determine if the magic bytes indicate an MoPaQ archive ///