├── .github └── FUNDING.yml ├── .gitignore ├── Jekyll.Library ├── Enums │ └── JekyllStatus.cs ├── Game │ ├── AdvancedWarfare │ │ ├── AdvancedWarfare.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── LuaFile.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ └── StringTable.cs │ ├── BlackOps │ │ ├── BlackOps.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ └── StringTable.cs │ ├── BlackOps2 │ │ ├── BlackOps2.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ └── StringTable.cs │ ├── BlackOps3 │ │ ├── BlackOps3.cs │ │ └── XAssets │ │ │ ├── BinaryHTML.cs │ │ │ ├── Localize.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ ├── StringTable.cs │ │ │ └── TTF.cs │ ├── BlackOps4 │ │ ├── BlackOps4.cs │ │ └── XAssets │ │ │ └── RawFile.cs │ ├── Ghosts │ │ ├── Ghosts.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── LuaFile.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ └── StringTable.cs │ ├── InfiniteWarfare │ │ ├── InfiniteWarfare.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── LuaFile.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ ├── StringTable.cs │ │ │ └── TTF.cs │ ├── ModernWarfare2 │ │ ├── ModernWarfare2.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ └── StringTable.cs │ ├── ModernWarfare2CR │ │ ├── ModernWarfare2CR.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── LuaFile.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ ├── StringTable.cs │ │ │ └── TTF.cs │ ├── ModernWarfare3 │ │ ├── ModernWarfare3.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ └── StringTable.cs │ ├── ModernWarfareRemastered │ │ ├── ModernWarfareRemastered.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── LuaFile.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ ├── StringTable.cs │ │ │ └── TTF.cs │ ├── WWII │ │ ├── WWII.cs │ │ └── XAssets │ │ │ ├── Localize.cs │ │ │ ├── LuaFile.cs │ │ │ ├── MapEnts.cs │ │ │ ├── RawFile.cs │ │ │ ├── ScriptFile.cs │ │ │ ├── StringTable.cs │ │ │ └── TTF.cs │ └── WorldatWar │ │ ├── WorldatWar.cs │ │ └── XAssets │ │ ├── Localize.cs │ │ ├── MapEnts.cs │ │ ├── RawFile.cs │ │ └── StringTable.cs ├── Interfaces │ ├── IGame.cs │ └── IXAssetPool.cs ├── Jekyll.Library.csproj ├── JekyllInstance.cs └── Utility │ └── GameXAsset.cs ├── Jekyll.UI ├── Jekyll.UI.csproj └── Program.cs ├── Jekyll.sln ├── LICENSE ├── PhilLibX ├── IO │ ├── MemoryUtility.cs │ └── ProcessReader.cs ├── NativeMethods.cs └── PhilLibX.csproj └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: mxtive 2 | -------------------------------------------------------------------------------- /Jekyll.Library/Enums/JekyllStatus.cs: -------------------------------------------------------------------------------- 1 | namespace JekyllLibrary.Library 2 | { 3 | public enum JekyllStatus 4 | { 5 | Success, 6 | UnsupportedBinary, 7 | FailedToFindGame, 8 | Exception, 9 | MemoryChanged, 10 | GameClosed, 11 | } 12 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/AdvancedWarfare/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class AdvancedWarfare 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.localize; 16 | 17 | /// 18 | /// Structure of an Advanced Warfare LocalizeEntry XAsset. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public long Value { get; set; } 23 | public long Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value)); 55 | 56 | Console.WriteLine($"Exported Localize {key}"); 57 | } 58 | 59 | string path = Path.Combine(instance.ExportPath, "localize.json"); 60 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 61 | 62 | using (StreamWriter file = File.CreateText(path)) 63 | { 64 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 65 | } 66 | 67 | return new List(); 68 | } 69 | 70 | /// 71 | /// Exports the specified Localize XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | return JekyllStatus.Success; 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/AdvancedWarfare/XAssets/LuaFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class AdvancedWarfare 9 | { 10 | public class LuaFile : IXAssetPool 11 | { 12 | public override string Name => "Lua File"; 13 | 14 | public override int Index => (int)XAssetType.luafile; 15 | 16 | /// 17 | /// Structure of an Advanced Warfare LuaFile XAsset. 18 | /// 19 | private struct LuaFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public int StrippingType { get; set; } 24 | public long Buffer { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the LuaFile XAsset Pool. 29 | /// 30 | /// 31 | /// List of LuaFile XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | LuaFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.Len == 0) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified LuaFile XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | LuaFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 84 | File.WriteAllBytes(path, buffer); 85 | 86 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 87 | 88 | return JekyllStatus.Success; 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/AdvancedWarfare/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class AdvancedWarfare 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.map_ents; 15 | 16 | /// 17 | /// Structure of an Advanced Warfare MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public long Name { get; set; } 22 | public long EntityString { get; set; } 23 | // TODO: Fill remaining unknown. 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the MapEnts XAsset Pool. 28 | /// 29 | /// 30 | /// List of MapEnts XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified MapEnts XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | string path = Path.Combine(instance.ExportPath, xasset.Name); 80 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 81 | 82 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 83 | 84 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 85 | 86 | return JekyllStatus.Success; 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/AdvancedWarfare/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class AdvancedWarfare 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.rawfile; 16 | 17 | /// 18 | /// Structure of an Advanced Warfare RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public long Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public long Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | try 82 | { 83 | string path = Path.Combine(instance.ExportPath, xasset.Name); 84 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 85 | 86 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 87 | 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class BlackOps 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_LOCALIZE_ENTRY; 16 | 17 | /// 18 | /// Structure of a Black Ops Localize XAsset. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public uint Value { get; set; } 23 | public uint Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value, nullCheck: true)); 55 | 56 | Console.WriteLine($"Exported {Name} {key}"); 57 | } 58 | 59 | string path = Path.Combine(instance.ExportPath, "localize.json"); 60 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 61 | 62 | using (StreamWriter file = File.CreateText(path)) 63 | { 64 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 65 | } 66 | 67 | return new List(); 68 | } 69 | 70 | /// 71 | /// Exports the specified Localize XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | return JekyllStatus.Success; 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_MAP_ENTS; 15 | 16 | /// 17 | /// Structure of a Black Ops MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public uint Name { get; set; } 22 | public uint EntityString { get; set; } 23 | public int NumEntityChars { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the MapEnts XAsset Pool. 28 | /// 29 | /// 30 | /// List of MapEnts XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified MapEnts XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | string path = Path.Combine(instance.ExportPath, xasset.Name); 80 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 81 | 82 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 83 | 84 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 85 | 86 | return JekyllStatus.Success; 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps 9 | { 10 | public class RawFile : IXAssetPool 11 | { 12 | public override string Name => "Raw File"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_RAWFILE; 15 | 16 | /// 17 | /// Structure of a Black Ops RawFile XAsset. 18 | /// 19 | private struct RawFileXAsset 20 | { 21 | public uint Name { get; set; } 22 | public int Len { get; set; } 23 | public uint Buffer { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the RawFile XAsset Pool. 28 | /// 29 | /// 30 | /// List of RawFile XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (header.Len == 0) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified RawFile XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | try 80 | { 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 85 | File.WriteAllBytes(path, buffer); 86 | } 87 | catch 88 | { 89 | return JekyllStatus.Exception; 90 | } 91 | 92 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 93 | 94 | return JekyllStatus.Success; 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps2/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class BlackOps2 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_LOCALIZE_ENTRY; 16 | 17 | /// 18 | /// Structure of a Black Ops II LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public uint Value { get; set; } 23 | public uint Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value, nullCheck: true)); 55 | 56 | Console.WriteLine($"Exported {Name} {key}"); 57 | } 58 | 59 | string path = Path.Combine(instance.ExportPath, "localize.json"); 60 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 61 | 62 | using (StreamWriter file = File.CreateText(path)) 63 | { 64 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 65 | } 66 | 67 | return new List(); 68 | } 69 | 70 | /// 71 | /// Exports the specified Localize XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | return JekyllStatus.Success; 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps2/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps2 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_MAP_ENTS; 15 | 16 | /// 17 | /// Structure of a Black Ops II MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public uint Name { get; set; } 22 | public uint EntityString { get; set; } 23 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 28)] 24 | public byte[] Unused; 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the MapEnts XAsset Pool. 29 | /// 30 | /// 31 | /// List of MapEnts XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified MapEnts XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 84 | 85 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 86 | 87 | return JekyllStatus.Success; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps2/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps2 9 | { 10 | public class RawFile : IXAssetPool 11 | { 12 | public override string Name => "Raw File"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_RAWFILE; 15 | 16 | /// 17 | /// Structure of a Black Ops II RawFile XAsset. 18 | /// 19 | private struct RawFileXAsset 20 | { 21 | public uint Name { get; set; } 22 | public int Len { get; set; } 23 | public uint Buffer { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the RawFile XAsset Pool. 28 | /// 29 | /// 30 | /// List of RawFile XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (header.Len == 0) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified RawFile XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | string path = Path.Combine(instance.ExportPath, xasset.Name); 80 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 81 | 82 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 83 | File.WriteAllBytes(path, buffer); 84 | 85 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 86 | 87 | return JekyllStatus.Success; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps2/XAssets/ScriptFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps2 9 | { 10 | public class ScriptFile : IXAssetPool 11 | { 12 | public override string Name => "Script File"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_SCRIPTPARSETREE; 15 | 16 | /// 17 | /// Structure of a Black Ops II ScriptParseTree. 18 | /// 19 | private struct ScriptParseTree 20 | { 21 | public uint Name { get; set; } 22 | public int Len { get; set; } 23 | public uint Buffer { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the ScriptFile XAsset Pool. 28 | /// 29 | /// 30 | /// List of ScriptFile XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | ScriptParseTree header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (header.Len == 0) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified ScriptFile XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | ScriptParseTree header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | try 80 | { 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 85 | File.WriteAllBytes(path, buffer); 86 | } 87 | catch 88 | { 89 | return JekyllStatus.Exception; 90 | } 91 | 92 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 93 | 94 | return JekyllStatus.Success; 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps3/XAssets/BinaryHTML.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps3 9 | { 10 | public class BinaryHTML : IXAssetPool 11 | { 12 | public override string Name => "Binary HTML"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_BINARYHTML; 15 | 16 | /// 17 | /// Structure of a Black Ops III BinaryHTML. 18 | /// 19 | private struct BinaryHTMLXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public long Buffer { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the BinaryHTML XAsset Pool. 28 | /// 29 | /// 30 | /// List of BinaryHTML XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | XAssetPool pool = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Index * Marshal.SizeOf())); 36 | 37 | Entries = pool.Pool; 38 | ElementSize = pool.ItemSize; 39 | PoolSize = (uint)pool.ItemCount; 40 | 41 | if (IsValidPool(Name, ElementSize, Marshal.SizeOf()) == false) 42 | { 43 | return results; 44 | } 45 | 46 | for (int i = 0; i < PoolSize; i++) 47 | { 48 | BinaryHTMLXAsset header = instance.Reader.ReadStruct(Entries + (i * ElementSize)); 49 | 50 | if (IsNullXAsset(header.Name)) 51 | { 52 | continue; 53 | } 54 | else if (header.Len == 0) 55 | { 56 | continue; 57 | } 58 | 59 | results.Add(new GameXAsset() 60 | { 61 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 62 | Type = Name, 63 | Size = ElementSize, 64 | XAssetPool = this, 65 | HeaderAddress = Entries + (i * ElementSize), 66 | }); 67 | } 68 | 69 | return results; 70 | } 71 | 72 | /// 73 | /// Exports the specified BinaryHTML XAsset. 74 | /// 75 | /// 76 | /// 77 | /// Status of the export operation. 78 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 79 | { 80 | BinaryHTMLXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 81 | 82 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 83 | { 84 | return JekyllStatus.MemoryChanged; 85 | } 86 | 87 | string path = Path.Combine(instance.ExportPath, xasset.Name); 88 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 89 | 90 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 91 | 92 | File.WriteAllBytes(path, buffer); 93 | 94 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 95 | 96 | return JekyllStatus.Success; 97 | } 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps3/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class BlackOps3 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_LOCALIZE_ENTRY; 16 | 17 | /// 18 | /// Structure of a Black Ops III LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public long Value { get; set; } 23 | public long Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | XAssetPool pool = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Index * Marshal.SizeOf())); 36 | 37 | Entries = pool.Pool; 38 | ElementSize = pool.ItemSize; 39 | PoolSize = (uint)pool.ItemCount; 40 | 41 | if (IsValidPool(Name, ElementSize, Marshal.SizeOf()) == false) 42 | { 43 | return results; 44 | } 45 | 46 | Dictionary entries = new Dictionary(); 47 | 48 | for (int i = 0; i < PoolSize; i++) 49 | { 50 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + (i * ElementSize)); 51 | 52 | if (IsNullXAsset(header.Name)) 53 | { 54 | continue; 55 | } 56 | 57 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 58 | 59 | if (entries.TryGetValue(key, out string _)) 60 | { 61 | continue; 62 | } 63 | 64 | string value = instance.Reader.ReadNullTerminatedString(header.Value, nullCheck:true); 65 | entries.Add(key, value); 66 | 67 | Console.WriteLine($"Exported {Name} {key}"); 68 | } 69 | 70 | string path = Path.Combine(instance.ExportPath, "localize.json"); 71 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 72 | 73 | using (StreamWriter file = File.CreateText(path)) 74 | { 75 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 76 | } 77 | 78 | return results; 79 | } 80 | 81 | /// 82 | /// Exports the specified Localize XAsset. 83 | /// 84 | /// 85 | /// 86 | /// Status of the export operation. 87 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 88 | { 89 | return JekyllStatus.Success; 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps3/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps3 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_MAP_ENTS; 15 | 16 | /// 17 | /// Structure of a Black Ops III MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public long Name { get; set; } 22 | public long EntityString { get; set; } 23 | public int NumEntityChars { get; set; } 24 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 48)] 25 | public byte[] Trigger; 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the MapEnts XAsset Pool. 30 | /// 31 | /// 32 | /// List of MapEnts XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | XAssetPool pool = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Index * Marshal.SizeOf())); 38 | 39 | Entries = pool.Pool; 40 | ElementSize = pool.ItemSize; 41 | PoolSize = (uint)pool.ItemCount; 42 | 43 | if (IsValidPool(Name, ElementSize, Marshal.SizeOf()) == false) 44 | { 45 | return results; 46 | } 47 | 48 | for (int i = 0; i < PoolSize; i++) 49 | { 50 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + (i * ElementSize)); 51 | 52 | if (IsNullXAsset(header.Name)) 53 | { 54 | continue; 55 | } 56 | 57 | results.Add(new GameXAsset() 58 | { 59 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 60 | Type = Name, 61 | Size = ElementSize, 62 | XAssetPool = this, 63 | HeaderAddress = Entries + (i * ElementSize), 64 | }); 65 | } 66 | 67 | return results; 68 | } 69 | 70 | /// 71 | /// Exports the specified MapEnts XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 79 | 80 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 81 | { 82 | return JekyllStatus.MemoryChanged; 83 | } 84 | 85 | string path = Path.Combine(instance.ExportPath, xasset.Name); 86 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 87 | 88 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 89 | 90 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 91 | 92 | return JekyllStatus.Success; 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps3/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps3 9 | { 10 | public class RawFile : IXAssetPool 11 | { 12 | public override string Name => "Raw File"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_RAWFILE; 15 | 16 | /// 17 | /// Structure of a Black Ops III RawFile XAsset. 18 | /// 19 | private struct RawFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public long Buffer { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the RawFile XAsset Pool. 28 | /// 29 | /// 30 | /// List of RawFile XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | XAssetPool pool = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Index * Marshal.SizeOf())); 36 | 37 | Entries = pool.Pool; 38 | ElementSize = pool.ItemSize; 39 | PoolSize = (uint)pool.ItemCount; 40 | 41 | if (IsValidPool(Name, ElementSize, Marshal.SizeOf()) == false) 42 | { 43 | return results; 44 | } 45 | 46 | for (int i = 0; i < PoolSize; i++) 47 | { 48 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + (i * ElementSize)); 49 | 50 | if (IsNullXAsset(header.Name)) 51 | { 52 | continue; 53 | } 54 | else if (header.Len == 0) 55 | { 56 | continue; 57 | } 58 | 59 | results.Add(new GameXAsset() 60 | { 61 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 62 | Type = Name, 63 | Size = ElementSize, 64 | XAssetPool = this, 65 | HeaderAddress = Entries + (i * ElementSize), 66 | }); 67 | } 68 | 69 | return results; 70 | } 71 | 72 | /// 73 | /// Exports the specified RawFile XAsset. 74 | /// 75 | /// 76 | /// 77 | /// Status of the export operation. 78 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 79 | { 80 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 81 | 82 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 83 | { 84 | return JekyllStatus.MemoryChanged; 85 | } 86 | 87 | string path = Path.Combine(instance.ExportPath, xasset.Name); 88 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 89 | 90 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 91 | 92 | File.WriteAllBytes(path, buffer); 93 | 94 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 95 | 96 | return JekyllStatus.Success; 97 | } 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps3/XAssets/ScriptFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps3 9 | { 10 | public class ScriptFile : IXAssetPool 11 | { 12 | public override string Name => "Script File"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_SCRIPTPARSETREE; 15 | 16 | /// 17 | /// Structure of a Black Ops III ScriptParseTree. 18 | /// 19 | private struct ScriptParseTree 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public long Buffer { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the ScriptParseTree XAsset Pool. 28 | /// 29 | /// 30 | /// List of ScriptParseTree XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | XAssetPool pool = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Index * Marshal.SizeOf())); 36 | 37 | Entries = pool.Pool; 38 | ElementSize = pool.ItemSize; 39 | PoolSize = (uint)pool.ItemCount; 40 | 41 | if (IsValidPool(Name, ElementSize, Marshal.SizeOf()) == false) 42 | { 43 | return results; 44 | } 45 | 46 | for (int i = 0; i < PoolSize; i++) 47 | { 48 | ScriptParseTree header = instance.Reader.ReadStruct(Entries + (i * ElementSize)); 49 | 50 | if (IsNullXAsset(header.Name)) 51 | { 52 | continue; 53 | } 54 | else if (header.Len == 0) 55 | { 56 | continue; 57 | } 58 | 59 | results.Add(new GameXAsset() 60 | { 61 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 62 | Type = Name, 63 | Size = ElementSize, 64 | XAssetPool = this, 65 | HeaderAddress = Entries + (i * ElementSize), 66 | }); 67 | } 68 | 69 | return results; 70 | } 71 | 72 | /// 73 | /// Exports the specified ScriptParseTree XAsset. 74 | /// 75 | /// 76 | /// 77 | /// Status of the export operation. 78 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 79 | { 80 | ScriptParseTree header = instance.Reader.ReadStruct(xasset.HeaderAddress); 81 | 82 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 83 | { 84 | return JekyllStatus.MemoryChanged; 85 | } 86 | 87 | string path = Path.Combine(instance.ExportPath, xasset.Name); 88 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 89 | 90 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 91 | 92 | File.WriteAllBytes(path, buffer); 93 | 94 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 95 | 96 | return JekyllStatus.Success; 97 | } 98 | } 99 | } 100 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps3/XAssets/TTF.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps3 9 | { 10 | public class TTF : IXAssetPool 11 | { 12 | public override string Name => "TrueType Font"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_TTF; 15 | 16 | /// 17 | /// Structure of a Black Ops III TTFDef. 18 | /// 19 | private struct TTFDef 20 | { 21 | public long Name { get; set; } 22 | public int FileLen { get; set; } 23 | public long File { get; set; } 24 | public long FtFace { get; set; } 25 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 131072)] 26 | public byte[] KerningCache; 27 | } 28 | 29 | /// 30 | /// Load the valid XAssets for the TTF XAsset Pool. 31 | /// 32 | /// 33 | /// List of TTF XAsset objects. 34 | public override List Load(JekyllInstance instance) 35 | { 36 | List results = new List(); 37 | 38 | XAssetPool pool = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Index * Marshal.SizeOf())); 39 | 40 | Entries = pool.Pool; 41 | ElementSize = pool.ItemSize; 42 | PoolSize = (uint)pool.ItemCount; 43 | 44 | if (IsValidPool(Name, ElementSize, Marshal.SizeOf()) == false) 45 | { 46 | return results; 47 | } 48 | 49 | for (int i = 0; i < PoolSize; i++) 50 | { 51 | TTFDef header = instance.Reader.ReadStruct(Entries + (i * ElementSize)); 52 | 53 | if (IsNullXAsset(header.Name)) 54 | { 55 | continue; 56 | } 57 | else if (header.FileLen == 0) 58 | { 59 | continue; 60 | } 61 | 62 | results.Add(new GameXAsset() 63 | { 64 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 65 | Type = Name, 66 | Size = ElementSize, 67 | XAssetPool = this, 68 | HeaderAddress = Entries + (i * ElementSize), 69 | }); 70 | } 71 | 72 | return results; 73 | } 74 | 75 | /// 76 | /// Exports the specified TTF XAsset. 77 | /// 78 | /// 79 | /// 80 | /// Status of the export operation. 81 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 82 | { 83 | TTFDef header = instance.Reader.ReadStruct(xasset.HeaderAddress); 84 | 85 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 86 | { 87 | return JekyllStatus.MemoryChanged; 88 | } 89 | 90 | string path = Path.Combine(instance.ExportPath, xasset.Name); 91 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 92 | 93 | byte[] buffer = instance.Reader.ReadBytes(header.File, header.FileLen); 94 | 95 | File.WriteAllBytes(path, buffer); 96 | 97 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 98 | 99 | return JekyllStatus.Success; 100 | } 101 | } 102 | } 103 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/BlackOps4/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class BlackOps4 9 | { 10 | public class RawFile : IXAssetPool 11 | { 12 | public override string Name => "Raw File"; 13 | 14 | public override int Index => (int)XAssetType.rawfile; 15 | 16 | /// 17 | /// Structure of a Black Ops 4 RawFile XAsset. 18 | /// 19 | private struct RawFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public long NullPadding1 { get; set; } 23 | public int Len { get; set; } 24 | public int CompressedLen { get; set; } 25 | public long Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | DBAssetPool pool = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Index * Marshal.SizeOf())); 38 | 39 | Entries = pool.Entries; 40 | ElementSize = pool.ElementSize; 41 | PoolSize = pool.PoolSize; 42 | 43 | if (IsValidPool(Name, ElementSize, Marshal.SizeOf()) == false) 44 | { 45 | return results; 46 | } 47 | 48 | for (int i = 0; i < PoolSize; i++) 49 | { 50 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + (i * ElementSize)); 51 | 52 | if (header.Len == 0) 53 | { 54 | continue; 55 | } 56 | 57 | results.Add(new GameXAsset() 58 | { 59 | Name = instance.Reader.ReadBytesToString(Entries + (i * ElementSize)).ToLower(), 60 | Type = Name, 61 | Size = ElementSize, 62 | XAssetPool = this, 63 | HeaderAddress = Entries + (i * Marshal.SizeOf()), 64 | }); 65 | } 66 | 67 | return results; 68 | } 69 | 70 | /// 71 | /// Exports the specified RawFile XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 79 | 80 | string path = Path.Combine(instance.ExportPath, "rawfile/" + xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 84 | 85 | File.WriteAllBytes(path, buffer); 86 | 87 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 88 | 89 | return JekyllStatus.Success; 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/Ghosts/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class Ghosts 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_LOCALIZE_ENTRY; 16 | 17 | /// 18 | /// Structure of a Ghosts LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public long Value { get; set; } 23 | public long Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | Dictionary entries = new Dictionary(); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | 49 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 50 | 51 | if (entries.TryGetValue(key, out string _)) 52 | { 53 | continue; 54 | } 55 | 56 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value, nullCheck: true)); 57 | 58 | Console.WriteLine($"Exported {Name} {key}"); 59 | } 60 | 61 | string path = Path.Combine(instance.ExportPath, "localize.json"); 62 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 63 | 64 | using (StreamWriter file = File.CreateText(path)) 65 | { 66 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 67 | } 68 | 69 | return results; 70 | } 71 | 72 | /// 73 | /// Exports the specified Localize XAsset. 74 | /// 75 | /// 76 | /// 77 | /// Status of the export operation. 78 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 79 | { 80 | return JekyllStatus.Success; 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/Ghosts/XAssets/LuaFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class Ghosts 9 | { 10 | public class LuaFile : IXAssetPool 11 | { 12 | public override string Name => "Lua File"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_LUA_FILE; 15 | 16 | /// 17 | /// Structure of a Ghosts LuaFile XAsset. 18 | /// 19 | private struct LuaFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public byte StrippingType { get; set; } 24 | public long Buffer { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the LuaFile XAsset Pool. 29 | /// 30 | /// 31 | /// List of LuaFile XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | LuaFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.Len == 0) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified LuaFile XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | LuaFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 84 | File.WriteAllBytes(path, buffer); 85 | 86 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 87 | 88 | return JekyllStatus.Success; 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/Ghosts/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class Ghosts 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_MAP_ENTS; 15 | 16 | /// 17 | /// Structure of a Ghosts MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public long Name { get; set; } 22 | public long EntityString { get; set; } 23 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 236)] 24 | public byte[] Unused; 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the MapEnts XAsset Pool. 29 | /// 30 | /// 31 | /// List of MapEnts XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified MapEnts XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 84 | 85 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 86 | 87 | return JekyllStatus.Success; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/Ghosts/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class Ghosts 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_RAWFILE; 16 | 17 | /// 18 | /// Structure of a Ghosts RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public long Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public long Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | try 82 | { 83 | string path = Path.Combine(instance.ExportPath, xasset.Name); 84 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 85 | 86 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 87 | 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/InfiniteWarfare/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class InfiniteWarfare 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.localize; 16 | 17 | /// 18 | /// Structure of an Infinite Warfare LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public long Value { get; set; } 23 | public long Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value)); 55 | 56 | Console.WriteLine($"Exported Localize {key}"); 57 | } 58 | 59 | string path = Path.Combine(instance.ExportPath, "localize.json"); 60 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 61 | 62 | using (StreamWriter file = File.CreateText(path)) 63 | { 64 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 65 | } 66 | 67 | return new List(); 68 | } 69 | 70 | /// 71 | /// Exports the specified Localize XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | return JekyllStatus.Success; 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/InfiniteWarfare/XAssets/LuaFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class InfiniteWarfare 9 | { 10 | public class LuaFile : IXAssetPool 11 | { 12 | public override string Name => "Lua File"; 13 | 14 | public override int Index => (int)XAssetType.luafile; 15 | 16 | /// 17 | /// Structure of an Infinite Warfare LuaFile XAsset. 18 | /// 19 | private struct LuaFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public int StrippingType { get; set; } 24 | public long Buffer { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the LuaFile XAsset Pool. 29 | /// 30 | /// 31 | /// List of LuaFile XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | LuaFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.Len == 0) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified LuaFile XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | LuaFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 84 | File.WriteAllBytes(path, buffer); 85 | 86 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 87 | 88 | return JekyllStatus.Success; 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/InfiniteWarfare/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class InfiniteWarfare 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.map_ents; 15 | 16 | /// 17 | /// Structure of an Infinite Warfare MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public long Name { get; set; } 22 | public long EntityString { get; set; } 23 | // TODO: Fill remaining unknown. 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the MapEnts XAsset Pool. 28 | /// 29 | /// 30 | /// List of MapEnts XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified MapEnts XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | string path = Path.Combine(instance.ExportPath, xasset.Name); 80 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 81 | 82 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 83 | 84 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 85 | 86 | return JekyllStatus.Success; 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/InfiniteWarfare/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class InfiniteWarfare 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.rawfile; 16 | 17 | /// 18 | /// Structure of an Infinite Warfare RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public long Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public long Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | try 82 | { 83 | string path = Path.Combine(instance.ExportPath, xasset.Name); 84 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 85 | 86 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 87 | 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/InfiniteWarfare/XAssets/TTF.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class InfiniteWarfare 9 | { 10 | public class TTF : IXAssetPool 11 | { 12 | public override string Name => "TrueType Font"; 13 | 14 | public override int Index => (int)XAssetType.ttf; 15 | 16 | /// 17 | /// Structure of an Infinite Warfare TTFDef. 18 | /// 19 | private struct TTFDef 20 | { 21 | public long Name { get; set; } 22 | public int FileLen { get; set; } 23 | public long File { get; set; } 24 | public int FtFace { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the TTF XAsset Pool. 29 | /// 30 | /// 31 | /// List of TTF XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | TTFDef header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.FileLen == 1) 48 | { 49 | continue; 50 | } 51 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".ttf") is false) 52 | { 53 | continue; 54 | } 55 | 56 | results.Add(new GameXAsset() 57 | { 58 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 59 | Type = Name, 60 | Size = ElementSize, 61 | XAssetPool = this, 62 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 63 | }); 64 | } 65 | 66 | return results; 67 | } 68 | 69 | /// 70 | /// Exports the specified TTF XAsset. 71 | /// 72 | /// 73 | /// 74 | /// Status of the export operation. 75 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 76 | { 77 | TTFDef header = instance.Reader.ReadStruct(xasset.HeaderAddress); 78 | 79 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 80 | { 81 | return JekyllStatus.MemoryChanged; 82 | } 83 | 84 | string path = Path.Combine(instance.ExportPath, xasset.Name); 85 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 86 | 87 | byte[] buffer = instance.Reader.ReadBytes(header.File, header.FileLen); 88 | File.WriteAllBytes(path, buffer); 89 | 90 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 91 | 92 | return JekyllStatus.Success; 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfare2 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_LOCALIZE_ENTRY; 16 | 17 | /// 18 | /// Structure of a Modern Warfare 2 LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public uint Value { get; set; } 23 | public uint Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | Dictionary entries = new Dictionary(); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | 49 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 50 | 51 | if (entries.TryGetValue(key, out string _)) 52 | { 53 | continue; 54 | } 55 | 56 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value, nullCheck: true)); 57 | 58 | Console.WriteLine($"Exported {Name} {key}"); 59 | } 60 | 61 | string path = Path.Combine(instance.ExportPath, "localize.json"); 62 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 63 | 64 | using (StreamWriter file = File.CreateText(path)) 65 | { 66 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 67 | } 68 | 69 | return results; 70 | } 71 | 72 | /// 73 | /// Exports the specified Localize XAsset. 74 | /// 75 | /// 76 | /// 77 | /// Status of the export operation. 78 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 79 | { 80 | return JekyllStatus.Success; 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfare2 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_MAP_ENTS; 15 | 16 | /// 17 | /// Structure of a Modern Warfare 2 MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public uint Name { get; set; } 22 | public uint EntityString { get; set; } 23 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 36)] 24 | public byte[] Unused; 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the MapEnts XAsset Pool. 29 | /// 30 | /// 31 | /// List of MapEnts XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified MapEnts XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 84 | 85 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 86 | 87 | return JekyllStatus.Success; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfare2 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_RAWFILE; 16 | 17 | /// 18 | /// Structure of a Modern Warfare 2 RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public uint Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public uint Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | try 82 | { 83 | string path = Path.Combine(instance.ExportPath, xasset.Name); 84 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 85 | 86 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 87 | 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2CR/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfare2CR 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.localize; 16 | 17 | /// 18 | /// Structure of a Modern Warfare 2 Campaign Remastered LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public long Value { get; set; } 23 | public long Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value)); 55 | 56 | Console.WriteLine($"Exported {Name} {key}"); 57 | } 58 | 59 | string path = Path.Combine(instance.ExportPath, "localize.json"); 60 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 61 | 62 | using (StreamWriter file = File.CreateText(path)) 63 | { 64 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 65 | } 66 | 67 | return new List(); 68 | } 69 | 70 | /// 71 | /// Exports the specified Localize XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | return JekyllStatus.Success; 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2CR/XAssets/LuaFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfare2CR 9 | { 10 | public class LuaFile : IXAssetPool 11 | { 12 | public override string Name => "Lua File"; 13 | 14 | public override int Index => (int)XAssetType.luafile; 15 | 16 | /// 17 | /// Structure of a Modern Warfare 2 Campaign Remastered LuaFile XAsset. 18 | /// 19 | private struct LuaFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public int StrippingType { get; set; } 24 | public long Buffer { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the LuaFile XAsset Pool. 29 | /// 30 | /// 31 | /// List of LuaFile XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | LuaFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.Len == 0) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | 66 | /// 67 | /// Exports the specified LuaFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | LuaFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 85 | File.WriteAllBytes(path, buffer); 86 | 87 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 88 | 89 | return JekyllStatus.Success; 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2CR/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfare2CR 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.map_ents; 15 | 16 | /// 17 | /// Structure of a Modern Warfare 2 Campaign Remastered MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public long Name { get; set; } 22 | public long EntityString { get; set; } 23 | } 24 | 25 | /// 26 | /// Load the valid XAssets for the MapEnts XAsset Pool. 27 | /// 28 | /// 29 | /// List of MapEnts XAsset objects. 30 | public override List Load(JekyllInstance instance) 31 | { 32 | List results = new List(); 33 | 34 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 35 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 36 | 37 | for (int i = 0; i < PoolSize; i++) 38 | { 39 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 40 | 41 | if (IsNullXAsset(header.Name)) 42 | { 43 | continue; 44 | } 45 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 46 | { 47 | continue; 48 | } 49 | 50 | results.Add(new GameXAsset() 51 | { 52 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 53 | Type = Name, 54 | Size = ElementSize, 55 | XAssetPool = this, 56 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 57 | }); 58 | } 59 | 60 | return results; 61 | } 62 | 63 | /// 64 | /// Exports the specified MapEnts XAsset. 65 | /// 66 | /// 67 | /// 68 | /// Status of the export operation. 69 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 70 | { 71 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 72 | 73 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 74 | { 75 | return JekyllStatus.MemoryChanged; 76 | } 77 | 78 | string path = Path.Combine(instance.ExportPath, xasset.Name); 79 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 80 | 81 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 82 | 83 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 84 | 85 | return JekyllStatus.Success; 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2CR/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfare2CR 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.rawfile; 16 | 17 | /// 18 | /// Structure of a Modern Warfare 2 Campaign Remastered RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public long Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public long Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 85 | 86 | try 87 | { 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare2CR/XAssets/TTF.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfare2CR 9 | { 10 | public class TTF : IXAssetPool 11 | { 12 | public override string Name => "TrueType Font"; 13 | 14 | public override int Index => (int)XAssetType.ttf; 15 | 16 | /// 17 | /// Structure of a Modern Warfare 2 Campaign Remastered TTFDef. 18 | /// 19 | private struct TTFDef 20 | { 21 | public long Name { get; set; } 22 | public int FileLen { get; set; } 23 | public long File { get; set; } 24 | public int FtFace { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the TTF XAsset Pool. 29 | /// 30 | /// 31 | /// List of TTF XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | TTFDef header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".ttf") is false) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified TTF XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | TTFDef header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | byte[] buffer = instance.Reader.ReadBytes(header.File, header.FileLen); 84 | 85 | File.WriteAllBytes(path, buffer); 86 | 87 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 88 | 89 | return JekyllStatus.Success; 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare3/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfare3 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_LOCALIZE_ENTRY; 16 | 17 | /// 18 | /// Structure of a Modern Warfare 3 LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public uint Value { get; set; } 23 | public uint Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | Dictionary entries = new Dictionary(); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | 49 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 50 | 51 | if (entries.TryGetValue(key, out string _)) 52 | { 53 | continue; 54 | } 55 | 56 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value, nullCheck: true)); 57 | 58 | Console.WriteLine($"Exported {Name} {key}"); 59 | } 60 | 61 | string path = Path.Combine(instance.ExportPath, "localize.json"); 62 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 63 | 64 | using (StreamWriter file = File.CreateText(path)) 65 | { 66 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 67 | } 68 | 69 | return results; 70 | } 71 | 72 | /// 73 | /// Exports the specified Localize XAsset. 74 | /// 75 | /// 76 | /// 77 | /// Status of the export operation. 78 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 79 | { 80 | return JekyllStatus.Success; 81 | } 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare3/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfare3 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_MAP_ENTS; 15 | 16 | /// 17 | /// Structure of a Modern Warfare 3 MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public uint Name { get; set; } 22 | public uint EntityString { get; set; } 23 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 88)] 24 | public byte[] Unused; 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the MapEnts XAsset Pool. 29 | /// 30 | /// 31 | /// List of MapEnts XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified MapEnts XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 84 | 85 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 86 | 87 | return JekyllStatus.Success; 88 | } 89 | } 90 | } 91 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfare3/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfare3 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_RAWFILE; 16 | 17 | /// 18 | /// Structure of a Modern Warfare 3 RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public uint Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public uint Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | try 82 | { 83 | string path = Path.Combine(instance.ExportPath, xasset.Name); 84 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 85 | 86 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 87 | 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfareRemastered/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfareRemastered 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.localize; 16 | 17 | /// 18 | /// Structure of a Modern Warfare Remastered LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public long Value { get; set; } 23 | public long Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value)); 55 | 56 | Console.WriteLine($"Exported {Name} {key}"); 57 | } 58 | 59 | string path = Path.Combine(instance.ExportPath, "localize.json"); 60 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 61 | 62 | using (StreamWriter file = File.CreateText(path)) 63 | { 64 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 65 | } 66 | 67 | return new List(); 68 | } 69 | 70 | /// 71 | /// Exports the specified Localize XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | return JekyllStatus.Success; 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfareRemastered/XAssets/LuaFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfareRemastered 9 | { 10 | public class LuaFile : IXAssetPool 11 | { 12 | public override string Name => "Lua File"; 13 | 14 | public override int Index => (int)XAssetType.luafile; 15 | 16 | /// 17 | /// Structure of a Modern Warfare Remastered LuaFile XAsset. 18 | /// 19 | private struct LuaFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public int StrippingType { get; set; } 24 | public long Buffer { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the LuaFile XAsset Pool. 29 | /// 30 | /// 31 | /// List of LuaFile XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | LuaFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.Len == 0) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | 66 | /// 67 | /// Exports the specified LuaFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | LuaFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 85 | File.WriteAllBytes(path, buffer); 86 | 87 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 88 | 89 | return JekyllStatus.Success; 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfareRemastered/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfareRemastered 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.map_ents; 15 | 16 | /// 17 | /// Structure of a Modern Warfare Remastered MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public long Name { get; set; } 22 | public long EntityString { get; set; } 23 | } 24 | 25 | /// 26 | /// Load the valid XAssets for the MapEnts XAsset Pool. 27 | /// 28 | /// 29 | /// List of MapEnts XAsset objects. 30 | public override List Load(JekyllInstance instance) 31 | { 32 | List results = new List(); 33 | 34 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 35 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 36 | 37 | for (int i = 0; i < PoolSize; i++) 38 | { 39 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 40 | 41 | if (IsNullXAsset(header.Name)) 42 | { 43 | continue; 44 | } 45 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 46 | { 47 | continue; 48 | } 49 | 50 | results.Add(new GameXAsset() 51 | { 52 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 53 | Type = Name, 54 | Size = ElementSize, 55 | XAssetPool = this, 56 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 57 | }); 58 | } 59 | 60 | return results; 61 | } 62 | 63 | /// 64 | /// Exports the specified MapEnts XAsset. 65 | /// 66 | /// 67 | /// 68 | /// Status of the export operation. 69 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 70 | { 71 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 72 | 73 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 74 | { 75 | return JekyllStatus.MemoryChanged; 76 | } 77 | 78 | string path = Path.Combine(instance.ExportPath, xasset.Name); 79 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 80 | 81 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 82 | 83 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 84 | 85 | return JekyllStatus.Success; 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfareRemastered/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class ModernWarfareRemastered 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.rawfile; 16 | 17 | /// 18 | /// Structure of a Modern Warfare Remastered RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public long Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public long Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 85 | 86 | try 87 | { 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/ModernWarfareRemastered/XAssets/TTF.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class ModernWarfareRemastered 9 | { 10 | public class TTF : IXAssetPool 11 | { 12 | public override string Name => "TrueType Font"; 13 | 14 | public override int Index => (int)XAssetType.ttf; 15 | 16 | /// 17 | /// Structure of a Modern Warfare Remastered TTFDef. 18 | /// 19 | private struct TTFDef 20 | { 21 | public long Name { get; set; } 22 | public int FileLen { get; set; } 23 | public long File { get; set; } 24 | public int FtFace { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the TTF XAsset Pool. 29 | /// 30 | /// 31 | /// List of TTF XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | TTFDef header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".ttf") is false) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified TTF XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | TTFDef header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | byte[] buffer = instance.Reader.ReadBytes(header.File, header.FileLen); 84 | 85 | File.WriteAllBytes(path, buffer); 86 | 87 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 88 | 89 | return JekyllStatus.Success; 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WWII/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class WWII 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.localize; 16 | 17 | /// 18 | /// Structure of a WWII LocalizeEntry. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public long Value { get; set; } 23 | public long Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | string value = instance.Reader.ReadNullTerminatedString(header.Value); 55 | entries.Add(key, value); 56 | 57 | Console.WriteLine($"Exported {Name} {key}"); 58 | } 59 | 60 | string path = Path.Combine(instance.ExportPath, "localize.json"); 61 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 62 | 63 | using (StreamWriter file = File.CreateText(path)) 64 | { 65 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 66 | } 67 | 68 | return new List(); 69 | } 70 | 71 | /// 72 | /// Exports the specified Localize XAsset. 73 | /// 74 | /// 75 | /// 76 | /// Status of the export operation. 77 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 78 | { 79 | return JekyllStatus.Success; 80 | } 81 | } 82 | } 83 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WWII/XAssets/LuaFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class WWII 9 | { 10 | public class LuaFile : IXAssetPool 11 | { 12 | public override string Name => "Lua File"; 13 | 14 | public override int Index => (int)XAssetType.luafile; 15 | 16 | /// 17 | /// Structure of a WWII LuaFile XAsset. 18 | /// 19 | private struct LuaFileXAsset 20 | { 21 | public long Name { get; set; } 22 | public int Len { get; set; } 23 | public int StrippingType { get; set; } 24 | public long Buffer { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the LuaFile XAsset Pool. 29 | /// 30 | /// 31 | /// List of LuaFile XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | LuaFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.Len == 0) 48 | { 49 | continue; 50 | } 51 | 52 | results.Add(new GameXAsset() 53 | { 54 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 55 | Type = Name, 56 | Size = ElementSize, 57 | XAssetPool = this, 58 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 59 | }); 60 | } 61 | 62 | return results; 63 | } 64 | 65 | /// 66 | /// Exports the specified LuaFile XAsset. 67 | /// 68 | /// 69 | /// 70 | /// Status of the export operation. 71 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 72 | { 73 | LuaFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 74 | 75 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 76 | { 77 | return JekyllStatus.MemoryChanged; 78 | } 79 | 80 | string path = Path.Combine(instance.ExportPath, xasset.Name); 81 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 82 | 83 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 84 | File.WriteAllBytes(path, buffer); 85 | 86 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 87 | 88 | return JekyllStatus.Success; 89 | } 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WWII/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class WWII 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.map_ents; 15 | 16 | /// 17 | /// Structure of a WWII MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public long Name { get; set; } 22 | public long EntityString { get; set; } 23 | } 24 | 25 | /// 26 | /// Load the valid XAssets for the MapEnts XAsset Pool. 27 | /// 28 | /// 29 | /// List of MapEnts XAsset objects. 30 | public override List Load(JekyllInstance instance) 31 | { 32 | List results = new List(); 33 | 34 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 35 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 36 | 37 | for (int i = 0; i < PoolSize; i++) 38 | { 39 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 40 | 41 | if (IsNullXAsset(header.Name)) 42 | { 43 | continue; 44 | } 45 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 46 | { 47 | continue; 48 | } 49 | 50 | results.Add(new GameXAsset() 51 | { 52 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 53 | Type = Name, 54 | Size = ElementSize, 55 | XAssetPool = this, 56 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 57 | }); 58 | } 59 | 60 | return results; 61 | } 62 | 63 | /// 64 | /// Exports the specified MapEnts XAsset. 65 | /// 66 | /// 67 | /// 68 | /// Status of the export operation. 69 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 70 | { 71 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 72 | 73 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 74 | { 75 | return JekyllStatus.MemoryChanged; 76 | } 77 | 78 | string path = Path.Combine(instance.ExportPath, xasset.Name); 79 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 80 | 81 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 82 | 83 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 84 | 85 | return JekyllStatus.Success; 86 | } 87 | } 88 | } 89 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WWII/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.IO.Compression; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class WWII 10 | { 11 | public class RawFile : IXAssetPool 12 | { 13 | public override string Name => "Raw File"; 14 | 15 | public override int Index => (int)XAssetType.rawfile; 16 | 17 | /// 18 | /// Structure of a WWII RawFile XAsset. 19 | /// 20 | private struct RawFileXAsset 21 | { 22 | public long Name { get; set; } 23 | public int CompressedLen { get; set; } 24 | public int Len { get; set; } 25 | public long Buffer { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the RawFile XAsset Pool. 30 | /// 31 | /// 32 | /// List of RawFile XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (header.Len == 0) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified RawFile XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | try 82 | { 83 | string path = Path.Combine(instance.ExportPath, xasset.Name); 84 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 85 | 86 | MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); 87 | 88 | using FileStream outputStream = new FileStream(path, FileMode.Create); 89 | DecodedCodeStream.CopyTo(outputStream); 90 | } 91 | catch 92 | { 93 | return JekyllStatus.Exception; 94 | } 95 | 96 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 97 | 98 | return JekyllStatus.Success; 99 | } 100 | 101 | /// 102 | /// Decompress the specified array of bytes. 103 | /// 104 | /// 105 | /// 106 | public static MemoryStream Decode(byte[] data) 107 | { 108 | MemoryStream output = new MemoryStream(); 109 | MemoryStream input = new MemoryStream(data); 110 | 111 | using (DeflateStream deflateStream = new DeflateStream(input, CompressionMode.Decompress)) 112 | { 113 | deflateStream.CopyTo(output); 114 | } 115 | 116 | output.Flush(); 117 | output.Position = 0; 118 | 119 | return output; 120 | } 121 | } 122 | } 123 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WWII/XAssets/StringTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class WWII 10 | { 11 | public class StringTable : IXAssetPool 12 | { 13 | public override string Name => "String Table"; 14 | 15 | public override int Index => (int)XAssetType.stringtable; 16 | 17 | /// 18 | /// Structure of a WWII StringTable XAsset. 19 | /// 20 | private struct StringTableXAsset 21 | { 22 | public long Name { get; set; } 23 | public int ColumnCount { get; set; } 24 | public int RowCount { get; set; } 25 | public long Strings { get; set; } 26 | } 27 | 28 | /// 29 | /// Structure of a WWII StringTable String. 30 | /// 31 | private struct StringTableString 32 | { 33 | public long Value { get; set; } 34 | public int Hash { get; set; } 35 | public int NullPadding { get; set; } 36 | } 37 | 38 | /// 39 | /// Load the valid XAssets for the StringTable XAsset Pool. 40 | /// 41 | /// 42 | /// List of StringTable XAsset objects. 43 | public override List Load(JekyllInstance instance) 44 | { 45 | List results = new List(); 46 | 47 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 48 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 49 | 50 | for (int i = 0; i < PoolSize; i++) 51 | { 52 | StringTableXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 53 | 54 | if (IsNullXAsset(header.Name)) 55 | { 56 | continue; 57 | } 58 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".csv") is false) 59 | { 60 | continue; 61 | } 62 | 63 | results.Add(new GameXAsset() 64 | { 65 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 66 | Type = Name, 67 | Size = ElementSize, 68 | XAssetPool = this, 69 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 70 | }); 71 | } 72 | 73 | return results; 74 | } 75 | 76 | /// 77 | /// Exports the specified StringTable XAsset. 78 | /// 79 | /// 80 | /// 81 | /// Status of the export operation. 82 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 83 | { 84 | StringTableXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 85 | 86 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 87 | { 88 | return JekyllStatus.MemoryChanged; 89 | } 90 | 91 | string path = Path.Combine(instance.ExportPath, xasset.Name); 92 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 93 | 94 | StringBuilder stringTable = new StringBuilder(); 95 | 96 | for (int y = 0; y < header.RowCount; y++) 97 | { 98 | for (int x = 0; x < header.ColumnCount; x++) 99 | { 100 | StringTableString data = instance.Reader.ReadStruct(header.Strings); 101 | string cell = instance.Reader.ReadNullTerminatedString(data.Value); 102 | 103 | stringTable.Append($"{cell},"); 104 | 105 | header.Strings += Marshal.SizeOf(); 106 | } 107 | 108 | stringTable.AppendLine(); 109 | } 110 | 111 | File.WriteAllText(path, stringTable.ToString()); 112 | 113 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 114 | 115 | return JekyllStatus.Success; 116 | } 117 | } 118 | } 119 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WWII/XAssets/TTF.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class WWII 9 | { 10 | public class TTF : IXAssetPool 11 | { 12 | public override string Name => "TrueType Font"; 13 | 14 | public override int Index => (int)XAssetType.ttf; 15 | 16 | /// 17 | /// Structure of a WWII TTFDef. 18 | /// 19 | private struct TTFDef 20 | { 21 | public long Name { get; set; } 22 | public int FileLen { get; set; } 23 | public long File { get; set; } 24 | public int FtFace { get; set; } 25 | } 26 | 27 | /// 28 | /// Load the valid XAssets for the TTF XAsset Pool. 29 | /// 30 | /// 31 | /// List of TTF XAsset objects. 32 | public override List Load(JekyllInstance instance) 33 | { 34 | List results = new List(); 35 | 36 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 37 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 38 | 39 | for (int i = 0; i < PoolSize; i++) 40 | { 41 | TTFDef header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 42 | 43 | if (IsNullXAsset(header.Name)) 44 | { 45 | continue; 46 | } 47 | else if (header.FileLen == 0) 48 | { 49 | continue; 50 | } 51 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".ttf") is false) 52 | { 53 | continue; 54 | } 55 | 56 | results.Add(new GameXAsset() 57 | { 58 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 59 | Type = Name, 60 | Size = ElementSize, 61 | XAssetPool = this, 62 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 63 | }); 64 | } 65 | 66 | return results; 67 | } 68 | 69 | /// 70 | /// Exports the specified TTF XAsset. 71 | /// 72 | /// 73 | /// 74 | /// Status of the export operation. 75 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 76 | { 77 | TTFDef header = instance.Reader.ReadStruct(xasset.HeaderAddress); 78 | 79 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 80 | { 81 | return JekyllStatus.MemoryChanged; 82 | } 83 | 84 | string path = Path.Combine(instance.ExportPath, xasset.Name); 85 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 86 | 87 | byte[] buffer = instance.Reader.ReadBytes(header.File, header.FileLen); 88 | File.WriteAllBytes(path, buffer); 89 | 90 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 91 | 92 | return JekyllStatus.Success; 93 | } 94 | } 95 | } 96 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WorldatWar/XAssets/Localize.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Runtime.InteropServices; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class WorldatWar 10 | { 11 | public class Localize : IXAssetPool 12 | { 13 | public override string Name => "Localize Entry"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_LOCALIZE_ENTRY; 16 | 17 | /// 18 | /// Structure of a World at War Localize XAsset. 19 | /// 20 | private struct LocalizeEntry 21 | { 22 | public uint Value { get; set; } 23 | public uint Name { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the Localize XAsset Pool. 28 | /// 29 | /// 30 | /// List of Localize XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 34 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 35 | 36 | Dictionary entries = new Dictionary(); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | LocalizeEntry header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | 47 | string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); 48 | 49 | if (entries.TryGetValue(key, out string _)) 50 | { 51 | continue; 52 | } 53 | 54 | entries.Add(key, instance.Reader.ReadNullTerminatedString(header.Value, nullCheck: true)); 55 | 56 | Console.WriteLine($"Exported {Name} {key}"); 57 | } 58 | 59 | string path = Path.Combine(instance.ExportPath, "localize.json"); 60 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 61 | 62 | using (StreamWriter file = File.CreateText(path)) 63 | { 64 | file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); 65 | } 66 | 67 | return new List(); 68 | } 69 | 70 | /// 71 | /// Exports the specified Localize XAsset. 72 | /// 73 | /// 74 | /// 75 | /// Status of the export operation. 76 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 77 | { 78 | return JekyllStatus.Success; 79 | } 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WorldatWar/XAssets/MapEnts.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class WorldatWar 9 | { 10 | public class MapEnts : IXAssetPool 11 | { 12 | public override string Name => "Map Entities"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_MAP_ENTS; 15 | 16 | /// 17 | /// Structure of a World at War MapEnts XAsset. 18 | /// 19 | private struct MapEntsXAsset 20 | { 21 | public uint Name { get; set; } 22 | public uint EntityString { get; set; } 23 | public int NumEntityChars { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the MapEnts XAsset Pool. 28 | /// 29 | /// 30 | /// List of MapEnts XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | MapEntsXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".d3dbsp") is false) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified MapEnts XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | MapEntsXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | string path = Path.Combine(instance.ExportPath, xasset.Name); 80 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 81 | 82 | File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); 83 | 84 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 85 | 86 | return JekyllStatus.Success; 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WorldatWar/XAssets/RawFile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | 6 | namespace JekyllLibrary.Library 7 | { 8 | public partial class WorldatWar 9 | { 10 | public class RawFile : IXAssetPool 11 | { 12 | public override string Name => "Raw File"; 13 | 14 | public override int Index => (int)XAssetType.ASSET_TYPE_RAWFILE; 15 | 16 | /// 17 | /// Structure of a World at War RawFile XAsset. 18 | /// 19 | private struct RawFileXAsset 20 | { 21 | public uint Name { get; set; } 22 | public int Len { get; set; } 23 | public uint Buffer { get; set; } 24 | } 25 | 26 | /// 27 | /// Load the valid XAssets for the RawFile XAsset Pool. 28 | /// 29 | /// 30 | /// List of RawFile XAsset objects. 31 | public override List Load(JekyllInstance instance) 32 | { 33 | List results = new List(); 34 | 35 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 36 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 37 | 38 | for (int i = 0; i < PoolSize; i++) 39 | { 40 | RawFileXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 41 | 42 | if (IsNullXAsset(header.Name)) 43 | { 44 | continue; 45 | } 46 | else if (header.Len == 0) 47 | { 48 | continue; 49 | } 50 | 51 | results.Add(new GameXAsset() 52 | { 53 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 54 | Type = Name, 55 | Size = ElementSize, 56 | XAssetPool = this, 57 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 58 | }); 59 | } 60 | 61 | return results; 62 | } 63 | 64 | /// 65 | /// Exports the specified RawFile XAsset. 66 | /// 67 | /// 68 | /// 69 | /// Status of the export operation. 70 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 71 | { 72 | RawFileXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 73 | 74 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 75 | { 76 | return JekyllStatus.MemoryChanged; 77 | } 78 | 79 | try 80 | { 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); 85 | File.WriteAllBytes(path, buffer); 86 | } 87 | catch 88 | { 89 | return JekyllStatus.Exception; 90 | } 91 | 92 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 93 | 94 | return JekyllStatus.Success; 95 | } 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Jekyll.Library/Game/WorldatWar/XAssets/StringTable.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Runtime.InteropServices; 5 | using System.Text; 6 | 7 | namespace JekyllLibrary.Library 8 | { 9 | public partial class WorldatWar 10 | { 11 | public class StringTable : IXAssetPool 12 | { 13 | public override string Name => "String Table"; 14 | 15 | public override int Index => (int)XAssetType.ASSET_TYPE_STRINGTABLE; 16 | 17 | /// 18 | /// Structure of a World at War StringTable XAsset. 19 | /// 20 | private struct StringTableXAsset 21 | { 22 | public uint Name { get; set; } 23 | public int ColumnCount { get; set; } 24 | public int RowCount { get; set; } 25 | public uint Values { get; set; } 26 | } 27 | 28 | /// 29 | /// Load the valid XAssets for the StringTable XAsset Pool. 30 | /// 31 | /// 32 | /// List of StringTable XAsset objects. 33 | public override List Load(JekyllInstance instance) 34 | { 35 | List results = new List(); 36 | 37 | Entries = instance.Reader.ReadStruct(instance.Game.DBAssetPools + (Marshal.SizeOf() * Index)); 38 | PoolSize = instance.Reader.ReadStruct(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf() * Index)); 39 | 40 | for (int i = 0; i < PoolSize; i++) 41 | { 42 | StringTableXAsset header = instance.Reader.ReadStruct(Entries + Marshal.SizeOf() + (i * Marshal.SizeOf())); 43 | 44 | if (IsNullXAsset(header.Name)) 45 | { 46 | continue; 47 | } 48 | else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".csv") is false) 49 | { 50 | continue; 51 | } 52 | 53 | results.Add(new GameXAsset() 54 | { 55 | Name = instance.Reader.ReadNullTerminatedString(header.Name), 56 | Type = Name, 57 | Size = ElementSize, 58 | XAssetPool = this, 59 | HeaderAddress = Entries + Marshal.SizeOf() + (i * Marshal.SizeOf()), 60 | }); 61 | } 62 | 63 | return results; 64 | } 65 | 66 | /// 67 | /// Exports the specified StringTable XAsset. 68 | /// 69 | /// 70 | /// 71 | /// Status of the export operation. 72 | public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) 73 | { 74 | StringTableXAsset header = instance.Reader.ReadStruct(xasset.HeaderAddress); 75 | 76 | if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) 77 | { 78 | return JekyllStatus.MemoryChanged; 79 | } 80 | 81 | string path = Path.Combine(instance.ExportPath, xasset.Name); 82 | Directory.CreateDirectory(Path.GetDirectoryName(path)); 83 | 84 | StringBuilder stringTable = new StringBuilder(); 85 | 86 | for (int x = 0; x < header.RowCount; x++) 87 | { 88 | for (int y = 0; y < header.ColumnCount; y++) 89 | { 90 | uint data = instance.Reader.ReadStruct(header.Values); 91 | string value = instance.Reader.ReadNullTerminatedString(data); 92 | 93 | stringTable.Append(value); 94 | 95 | if (y != (header.ColumnCount - 1)) 96 | { 97 | stringTable.Append(","); 98 | } 99 | 100 | header.Values += (uint)Marshal.SizeOf(); 101 | } 102 | 103 | stringTable.AppendLine(); 104 | } 105 | 106 | File.WriteAllText(path, stringTable.ToString()); 107 | 108 | Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); 109 | 110 | return JekyllStatus.Success; 111 | } 112 | } 113 | } 114 | } -------------------------------------------------------------------------------- /Jekyll.Library/Interfaces/IGame.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace JekyllLibrary.Library 4 | { 5 | public interface IGame 6 | { 7 | /// 8 | /// Gets the name of the game. 9 | /// 10 | string Name { get; } 11 | 12 | /// 13 | /// Gets the process names of the game. 14 | /// 15 | string[] ProcessNames { get; } 16 | 17 | /// 18 | /// Gets or sets the process index for the game. 19 | /// 20 | int ProcessIndex { get; set; } 21 | 22 | /// 23 | /// Gets or sets the base address for the game. 24 | /// 25 | long BaseAddress { get; set; } 26 | 27 | /// 28 | /// Gets or sets the memory address for the DBAssetPools of the game. 29 | /// 30 | long DBAssetPools { get; set; } 31 | 32 | /// 33 | /// Gets or sets the memory address for the DBAssetPoolSizes of the game (optional). 34 | /// 35 | long DBAssetPoolSizes { get; set; } 36 | 37 | /// 38 | /// Gets or sets the list of XAsset Pools for the game. 39 | /// 40 | List XAssetPools { get; set; } 41 | 42 | /// 43 | /// Initializes the game and validates its associated addresses. 44 | /// 45 | /// True if valid addresses are found, otherwise false. 46 | bool InitializeGame(JekyllInstance instance); 47 | 48 | /// 49 | /// Gets the first entry in the XModel XAsset Pool of the game. 50 | /// 51 | /// True if valid addresses are found, otherwise false. 52 | string GetFirstXModel(JekyllInstance instance); 53 | 54 | /// 55 | /// Creates a shallow copy of the IGame object. 56 | /// 57 | /// Shallow copy of the IGame object. 58 | object Clone(); 59 | } 60 | } -------------------------------------------------------------------------------- /Jekyll.Library/Interfaces/IXAssetPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace JekyllLibrary.Library 5 | { 6 | public abstract class IXAssetPool 7 | { 8 | /// 9 | /// Gets the name of the XAsset Pool. 10 | /// 11 | public abstract string Name { get; } 12 | 13 | /// 14 | /// Gets the index of the XAsset Pool. 15 | /// 16 | public abstract int Index { get; } 17 | 18 | /// 19 | /// Gets or sets the start address of the XAsset Pool. 20 | /// 21 | public long Entries { get; set; } 22 | 23 | /// 24 | /// Gets or sets the header size of XAssets in the XAsset Pool. 25 | /// 26 | public uint ElementSize { get; set; } 27 | 28 | /// 29 | /// Gets or sets the number of slots in the XAsset Pool. 30 | /// 31 | public uint PoolSize { get; set; } 32 | 33 | /// 34 | /// Loads XAssets from the specified XAsset Pool. 35 | /// 36 | public abstract List Load(JekyllInstance instance); 37 | 38 | /// 39 | /// Exports the given XAsset from the current game. 40 | /// 41 | public abstract JekyllStatus Export(GameXAsset xasset, JekyllInstance instance); 42 | 43 | /// 44 | /// Determines if the specified XAsset is a null slot. 45 | /// 46 | public bool IsNullXAsset(long nameAddress) 47 | { 48 | return nameAddress >= Entries && nameAddress <= PoolSize * ElementSize + Entries || nameAddress == 0; 49 | } 50 | 51 | /// 52 | /// Determines if the structure of the XAsset Pool is valid. 53 | /// 54 | public bool IsValidPool(string type, uint elementSize, int structSize) 55 | { 56 | if (elementSize == structSize) 57 | { 58 | return true; 59 | } 60 | else 61 | { 62 | Console.ForegroundColor = ConsoleColor.Red; 63 | Console.WriteLine($"Failed to export {type} XAsset Type, Element Size ({ElementSize}) is not equal to Struct Size ({structSize})"); 64 | Console.ResetColor(); 65 | 66 | return false; 67 | } 68 | } 69 | } 70 | } -------------------------------------------------------------------------------- /Jekyll.Library/Jekyll.Library.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Jekyll.Library/Utility/GameXAsset.cs: -------------------------------------------------------------------------------- 1 | namespace JekyllLibrary.Library 2 | { 3 | /// 4 | /// Generic class that represents a Call of Duty XAsset. 5 | /// 6 | public class GameXAsset 7 | { 8 | /// 9 | /// Gets or sets the name of the XAsset. 10 | /// 11 | public string Name { get; set; } 12 | 13 | /// 14 | /// Gets or sets the type of the XAsset. 15 | /// 16 | public string Type { get; set; } 17 | 18 | /// 19 | /// Gets or sets the size of the XAsset. 20 | /// 21 | public uint Size { get; set; } 22 | 23 | /// 24 | /// Gets or sets the XAsset Pool of the XAsset. 25 | /// 26 | public IXAssetPool XAssetPool { get; set; } 27 | 28 | /// 29 | /// Gets or sets the header address of the XAsset. 30 | /// 31 | public long HeaderAddress { get; set; } 32 | } 33 | } -------------------------------------------------------------------------------- /Jekyll.UI/Jekyll.UI.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | netcoreapp3.0 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /Jekyll.UI/Program.cs: -------------------------------------------------------------------------------- 1 | using JekyllLibrary.Library; 2 | using System; 3 | 4 | namespace Jekyll.UI 5 | { 6 | class Program 7 | { 8 | private static readonly JekyllInstance Instance = new JekyllInstance(); 9 | 10 | static void Main() 11 | { 12 | Console.WriteLine("Jekyll: Call of Duty XAsset Exporter"); 13 | Console.ForegroundColor = ConsoleColor.DarkGray; 14 | Console.WriteLine("https://github.com/EthanC/Jekyll\n"); 15 | Console.ResetColor(); 16 | 17 | JekyllStatus status = Instance.LoadGame(); 18 | 19 | if (status == JekyllStatus.Success) 20 | { 21 | foreach (GameXAsset xasset in Instance.XAssets) 22 | { 23 | xasset.XAssetPool.Export(xasset, Instance); 24 | } 25 | } 26 | else 27 | { 28 | Console.ForegroundColor = ConsoleColor.Red; 29 | Console.WriteLine("Failed to find a supported game"); 30 | Console.ResetColor(); 31 | } 32 | 33 | Console.WriteLine("\nPress any key to exit..."); 34 | Console.ReadKey(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Jekyll.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29709.97 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PhilLibX", "PhilLibX\PhilLibX.csproj", "{7101247D-6ABE-448F-8E5C-ABE066155C3F}" 7 | EndProject 8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jekyll.UI", "Jekyll.UI\Jekyll.UI.csproj", "{551502A8-A10E-40F7-8BFD-B82B479C69CE}" 9 | EndProject 10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Jekyll.Library", "Jekyll.Library\Jekyll.Library.csproj", "{A10C2B74-848F-41BD-964C-B0689C147413}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {7101247D-6ABE-448F-8E5C-ABE066155C3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {7101247D-6ABE-448F-8E5C-ABE066155C3F}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {7101247D-6ABE-448F-8E5C-ABE066155C3F}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {7101247D-6ABE-448F-8E5C-ABE066155C3F}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {551502A8-A10E-40F7-8BFD-B82B479C69CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {551502A8-A10E-40F7-8BFD-B82B479C69CE}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {551502A8-A10E-40F7-8BFD-B82B479C69CE}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {551502A8-A10E-40F7-8BFD-B82B479C69CE}.Release|Any CPU.Build.0 = Release|Any CPU 26 | {A10C2B74-848F-41BD-964C-B0689C147413}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 27 | {A10C2B74-848F-41BD-964C-B0689C147413}.Debug|Any CPU.Build.0 = Debug|Any CPU 28 | {A10C2B74-848F-41BD-964C-B0689C147413}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {A10C2B74-848F-41BD-964C-B0689C147413}.Release|Any CPU.Build.0 = Release|Any CPU 30 | EndGlobalSection 31 | GlobalSection(SolutionProperties) = preSolution 32 | HideSolutionNode = FALSE 33 | EndGlobalSection 34 | GlobalSection(ExtensibilityGlobals) = postSolution 35 | SolutionGuid = {5EC4FE2A-52A2-4EC3-940A-F6B1838D5C05} 36 | EndGlobalSection 37 | EndGlobal 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Ethan 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PhilLibX/PhilLibX.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | netstandard2.1 5 | true 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jekyll 2 | 3 | Jekyll is a Call of Duty XAsset exporter that dumps raw assets from a game's memory. 4 | 5 | ## Requirements 6 | 7 | - [.NET Core 3.0](https://dotnet.microsoft.com/download/dotnet-core/3.0) 8 | 9 | ## Usage 10 | 11 | You will need to build the Jekyll solution from the source. 12 | 13 | Run a supported Call of Duty title, then run `Jekyll.UI.exe` and allow the program to finish. 14 | 15 | ## Supported Titles 16 | 17 | ### Call of Duty: Vanguard 18 | 19 | Currently not available for public release. 20 | 21 | ### Call of Duty: Black Ops Cold War 22 | 23 | Currently not available for public release. 24 | 25 | ### Call of Duty: Modern Warfare 2 Campaign Remastered 26 | 27 | - Localize 28 | - Lua Files\* 29 | - Map Entities 30 | - Raw Files 31 | - Script Files\* 32 | - String Tables 33 | - TrueType Fonts 34 | 35 | ### Call of Duty: Modern Warfare 36 | 37 | Currently not available for public release. 38 | 39 | ### Call of Duty: Black Ops 4 40 | 41 | - Raw Files 42 | 43 | ### Call of Duty: WWII 44 | 45 | - Localize 46 | - Lua Files\* 47 | - Map Entities 48 | - Raw Files 49 | - Script Files\* 50 | - String Tables 51 | - TrueType Fonts 52 | 53 | ### Call of Duty: Infinite Warfare 54 | 55 | - Localize 56 | - Lua Files\* 57 | - Map Entities 58 | - Raw Files 59 | - Script Files\* 60 | - String Tables 61 | - TrueType Fonts 62 | 63 | ### Call of Duty: Modern Warfare Remastered 64 | 65 | - Localize 66 | - Lua Files\* 67 | - Map Entities 68 | - Raw Files 69 | - Script Files\* 70 | - String Tables 71 | - TrueType Fonts 72 | 73 | ### Call of Duty: Black Ops III 74 | 75 | - Binary HTML 76 | - Localize 77 | - Map Entities 78 | - Raw Files 79 | - Script Files\* 80 | - String Tables 81 | - TrueType Fonts 82 | 83 | ### Call of Duty: Advanced Warfare 84 | 85 | - Localize 86 | - Lua Files\* 87 | - Map Entities 88 | - Raw Files 89 | - Script Files\* 90 | - String Tables 91 | 92 | ### Call of Duty: Ghosts 93 | 94 | - Localize 95 | - Lua Files\* 96 | - Map Entities 97 | - Raw Files 98 | - Script Files\* 99 | - String Tables 100 | 101 | ### Call of Duty: Black Ops II 102 | 103 | - Localize 104 | - Map Entities 105 | - Raw Files 106 | - Script Files\* 107 | - String Tables 108 | 109 | ### Call of Duty: Modern Warfare 3 110 | 111 | - Localize 112 | - Map Entities 113 | - Raw Files 114 | - Script Files\* 115 | - String Tables 116 | 117 | ### Call of Duty: Black Ops 118 | 119 | - Localize 120 | - Map Entities 121 | - Raw Files 122 | - String Tables 123 | 124 | ### Call of Duty: Modern Warfare 2 125 | 126 | - Localize 127 | - Map Entities 128 | - Raw Files 129 | - String Tables 130 | 131 | ### Call of Duty: World at War 132 | 133 | - Localize 134 | - Map Entities 135 | - Raw Files 136 | - String Tables 137 | 138 | ## Credits 139 | 140 | - [Scobalula](https://github.com/Scobalula) - [PhilLibX](https://github.com/Scobalula/PhilLibX) 141 | 142 | ## Disclaimer 143 | 144 | Jekyll is developed to allow users obtain to assets for use in the official Call of Duty SDKs, such as the [Call of Duty: Black Ops III Mod Tools](https://steamdb.info/app/455130/). It's also used for informational purposes, such as the [COD Tracker Database](https://tracker.gg/warzone/db), when paired with [Hyde](https://github.com/EthanC/Hyde) - a Call of Duty XAsset compiler. 145 | 146 | All assets extracted by Jekyll are property of their respective owners. Jekyll is in no way, shape, or form associated with or endorsed by Activision or its subsidiary studios. 147 | --------------------------------------------------------------------------------