/// <summary> /// Validates and sets the DBAssetPools and DBAssetPoolSizes addresses of Black Ops II. /// </summary> /// <param name="instance"></param> /// <returns>True if addresses are valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); long moduleSize = instance.Reader.GetModuleMemorySize(); long[] scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x56, 0x51, 0xFF, 0xD2, 0x8B, 0xF0, 0x83, 0xC4, 0x04, 0x85, 0xF6 }, BaseAddress, BaseAddress + moduleSize, true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadInt32(scanDBAssetPools[0] - 0xB); DBAssetPoolSizes = instance.Reader.ReadInt32(scanDBAssetPools[0] + 0x3B); // In Black Ops II, defaultvehicle will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "defaultvehicle") { return(true); } } return(false); }
/// <summary> /// Validates and sets the DBAssetPools and DBAssetPoolSizes addresses of Modern Warfare 2. /// </summary> /// <param name="instance"></param> /// <returns>True if addresses are valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); long moduleSize = instance.Reader.GetModuleMemorySize(); long[] scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x56, 0x51, 0xFF, 0xD2, 0x8B, 0xF0, 0x83, 0xC4, 0x04, 0x85, 0xF6 }, BaseAddress, BaseAddress + moduleSize, true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadUInt32(scanDBAssetPools[0] - 0xB); if (instance.Reader.ActiveProcess.ProcessName == "iw4sp") { DBAssetPoolSizes = instance.Reader.ReadUInt32(scanDBAssetPools[0] + 0x30); } else if (instance.Reader.ActiveProcess.ProcessName == "iw4mp") { DBAssetPoolSizes = instance.Reader.ReadUInt32(scanDBAssetPools[0] + 0x46); } // In Modern Warfare 2, void will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "void") { return(true); } } return(false); }
/// <summary> /// Load the valid XAssets for the RawFile XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of RawFile XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { List <GameXAsset> results = new List <GameXAsset>(); DBAssetPool pool = instance.Reader.ReadStruct <DBAssetPool>(instance.Game.DBAssetPools + (Index * Marshal.SizeOf <DBAssetPool>())); Entries = pool.Entries; ElementSize = pool.ElementSize; PoolSize = pool.PoolSize; for (int i = 0; i < PoolSize; i++) { RawFileXAsset header = instance.Reader.ReadStruct <RawFileXAsset>(Entries + (i * ElementSize)); if (IsNullXAsset(header.Name)) { continue; } else if (header.Len == 0) { continue; } results.Add(new GameXAsset() { Name = instance.Reader.ReadNullTerminatedString(header.Name), Type = Name, Size = ElementSize, XAssetPool = this, HeaderAddress = Entries + (i * ElementSize), }); } return(results); }
/// <summary> /// Validates and sets the DBAssetPools and DBAssetPoolSizes addresses of WWII. /// </summary> /// <param name="instance"></param> /// <returns>True if addresses are valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); long moduleSize = instance.Reader.GetModuleMemorySize(); var scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x4A, 0x8B, 0xAC, null, null, null, null, null, 0x48, 0x85, 0xED }, BaseAddress, BaseAddress + moduleSize, true); var scanDBAssetPoolSizes = instance.Reader.FindBytes( new byte?[] { 0x83, 0xBC, null, null, null, null, null, 0x01, 0x7F, 0x48 }, BaseAddress, BaseAddress + moduleSize, true); if (scanDBAssetPools.Length > 0 && scanDBAssetPoolSizes.Length > 0) { DBAssetPools = instance.Reader.ReadInt32(scanDBAssetPools[0] + 0x4) + BaseAddress; DBAssetPoolSizes = instance.Reader.ReadInt32(scanDBAssetPoolSizes[0] + 0x3) + BaseAddress; // In WWII, empty_model will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "empty_model") { return(true); } } return(false); }
/// <summary> /// Exports the specified ScriptFile XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { ScriptFileXAsset header = instance.Reader.ReadStruct <ScriptFileXAsset>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } string addedScriptsFolder = Path.Combine(xasset.Name.Contains("scripts") ? "" : "scripts", xasset.Name); string path = Path.Combine(instance.ExportPath, addedScriptsFolder.Contains(".gsc") ? "" : addedScriptsFolder + ".gsc"); Directory.CreateDirectory(Path.GetDirectoryName(path)); MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); using (var outputStream = new FileStream(path, FileMode.Create)) { DecodedCodeStream.CopyTo(outputStream); } Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Gets the first entry in the XModel XAsset Pool of Black Ops 4. /// </summary> /// <param name="instance"></param> /// <returns>Name of the XModel.</returns> public string GetFirstXModel(JekyllInstance instance) { long address = instance.Game.DBAssetPools + (Marshal.SizeOf <DBAssetPool>() * (int)XAssetType.xmodel); DBAssetPool pool = instance.Reader.ReadStruct <DBAssetPool>(address); return(instance.Reader.ReadBytesToString(pool.Entries).ToLower()); }
/// <summary> /// Validates and sets the DBAssetPools and DBAssetPoolSizes addresses of Modern Warfare 3. /// </summary> /// <param name="instance"></param> /// <returns>True if addresses are valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); long moduleSize = instance.Reader.GetModuleMemorySize(); long[] scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0xFF, 0xD1, 0x8B, 0xF8, 0x83, 0xC4, 0x04, 0x85, 0xFF, 0x75 }, BaseAddress, BaseAddress + moduleSize, true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadUInt32(scanDBAssetPools[0] - 0xD); DBAssetPoolSizes = instance.Reader.ReadUInt32(scanDBAssetPools[0] + 0x2A); // In Modern Warfare 3, void will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "void") { return(true); } } return(false); }
/// <summary> /// Load the valid XAssets for the StringTable XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of StringTable XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { List <GameXAsset> results = new List <GameXAsset>(); Entries = instance.Reader.ReadStruct <long>(instance.Game.DBAssetPools + (Marshal.SizeOf <DBAssetPool>() * Index)); PoolSize = instance.Reader.ReadStruct <int>(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf <DBAssetPoolSize>() * Index)); for (int i = 0; i < PoolSize; i++) { StringTableXAsset header = instance.Reader.ReadStruct <StringTableXAsset>(Entries + Marshal.SizeOf <DBAssetPool>() + (i * Marshal.SizeOf <StringTableXAsset>())); if (IsNullXAsset(header.Name)) { continue; } else if (instance.Reader.ReadNullTerminatedString(header.Name).EndsWith(".csv") is false) { continue; } results.Add(new GameXAsset() { Name = instance.Reader.ReadNullTerminatedString(header.Name), Type = Name, Size = ElementSize, XAssetPool = this, HeaderAddress = Entries + Marshal.SizeOf <DBAssetPool>() + (i * Marshal.SizeOf <StringTableXAsset>()), }); } return(results); }
/// <summary> /// Validates and sets the DBAssetPools and DBAssetPoolSizes addresses of Ghosts. /// </summary> /// <param name="instance"></param> /// <returns>True if addresses are valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); long moduleSize = instance.Reader.GetModuleMemorySize(); long[] scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x48, 0x8B, 0xD8, 0x48, 0x85, 0xC0, 0x75, null, 0xF0, 0xFF, 0x0D }, BaseAddress, BaseAddress + moduleSize, true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadUInt32(scanDBAssetPools[0] - 0xB) + BaseAddress; if (instance.Reader.ActiveProcess.ProcessName == "iw6sp64_ship") { DBAssetPoolSizes = instance.Reader.ReadUInt32(scanDBAssetPools[0] + 0x26) + BaseAddress; } else if (instance.Reader.ActiveProcess.ProcessName == "iw6mp64_ship") { DBAssetPoolSizes = instance.Reader.ReadUInt32(scanDBAssetPools[0] + 0x1E) + BaseAddress; } // In Ghosts, void or empty_model will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "void" || GetFirstXModel(instance) == "empty_model") { return(true); } } return(false); }
/// <summary> /// Exports the specified RawFile XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { RawFileXAsset header = instance.Reader.ReadStruct <RawFileXAsset>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } string path = Path.Combine(instance.ExportPath, xasset.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); try { MemoryStream DecodedCodeStream = Decode(instance.Reader.ReadBytes(header.Buffer + 2, header.CompressedLen - 2)); using FileStream outputStream = new FileStream(path, FileMode.Create); DecodedCodeStream.CopyTo(outputStream); } catch { return(JekyllStatus.Exception); } Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Validates and sets the DBAssetPools and DBAssetPoolSizes addresses of Infinite Warfare. /// </summary> /// <param name="instance"></param> /// <returns>True if addresses are valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); long moduleSize = instance.Reader.GetModuleMemorySize(); long[] scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x48, 0x63, 0xC1, 0x48, 0x8D, 0x15, null, null, null, null, 0x48, 0x8B, 0x8C, 0xC2 }, BaseAddress, BaseAddress + moduleSize, true); long[] scanDBAssetPoolSizes = instance.Reader.FindBytes( new byte?[] { 0x72, null, 0x48, 0x63, 0xC1, 0x48, 0x8D, 0x0D, null, null, null, null, 0x83, 0x3C, 0x81 }, BaseAddress, BaseAddress + moduleSize, true); if (scanDBAssetPools.Length > 0 && scanDBAssetPoolSizes.Length > 0) { DBAssetPools = instance.Reader.ReadInt32(scanDBAssetPools[0] + 0xE) + BaseAddress; DBAssetPoolSizes = instance.Reader.ReadInt32(scanDBAssetPoolSizes[0] + 0x8) + (scanDBAssetPoolSizes[0] + 0xC); // In Infinite Warfare, viewmodel_default will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "viewmodel_default") { return(true); } } return(false); }
/// <summary> /// Validates and sets the DBAssetPools and DBAssetPoolSizes addresses of World at War. /// </summary> /// <param name="instance"></param> /// <returns>True if addresses are valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); long moduleSize = instance.Reader.GetModuleMemorySize(); long[] scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0xFF, 0xD2, 0x8B, 0xF0, 0x83, 0xC4, 0x04, 0x85, 0xF6, 0x75 }, BaseAddress, BaseAddress + moduleSize, true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadInt32(scanDBAssetPools[0] - 0xD); DBAssetPoolSizes = instance.Reader.ReadInt32(scanDBAssetPools[0] + 0x25); // In World at War, void, defaultactor, or defaultweapon will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "void" || GetFirstXModel(instance) == "defaultactor" || GetFirstXModel(instance) == "defaultweapon") { return(true); } } return(false); }
/// <summary> /// Exports the specified ScriptFile XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { ScriptParseTree header = instance.Reader.ReadStruct <ScriptParseTree>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } try { string path = Path.Combine(instance.ExportPath, xasset.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); File.WriteAllBytes(path, buffer); } catch { return(JekyllStatus.Exception); } Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Gets the first entry in the XModel XAsset Pool of Modern Warfare. /// </summary> /// <param name="instance"></param> /// <returns>Name of the XModel.</returns> public string GetFirstXModel(JekyllInstance instance) { long address = BaseAddress + DBAssetPools + (Marshal.SizeOf <DBAssetPool>() * (int)XAssetType.ASSET_TYPE_XMODEL); DBAssetPool pool = instance.Reader.ReadStruct <DBAssetPool>(address); long name = instance.Reader.ReadInt64(pool.Entries); return(instance.Reader.ReadNullTerminatedString(name)); }
/// <summary> /// Gets the first entry in the XModel XAsset Pool of Infinite Warfare. /// </summary> /// <param name="instance"></param> /// <returns>Name of the XModel.</returns> public string GetFirstXModel(JekyllInstance instance) { long address = DBAssetPools + (Marshal.SizeOf <DBAssetPool>() * (int)XAssetType.xmodel); long pool = instance.Reader.ReadInt64(address) + Marshal.SizeOf <DBAssetPool>(); long name = instance.Reader.ReadInt64(pool); return(instance.Reader.ReadNullTerminatedString(name)); }
/// <summary> /// Load the valid XAssets for the Key/Value Pairs XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of Key/Value Pairs XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { List <GameXAsset> results = new List <GameXAsset>(); DBAssetPool pool = instance.Reader.ReadStruct <DBAssetPool>(instance.Game.BaseAddress + instance.Game.DBAssetPools + (Index * Marshal.SizeOf <DBAssetPool>())); Entries = pool.Entries; ElementSize = pool.ElementSize; PoolSize = pool.PoolSize; if (IsValidPool(Name, ElementSize, Marshal.SizeOf <KeyValuePairsXAsset>()) == false) { return(results); } Dictionary <string, string> entries = new Dictionary <string, string>(); for (int i = 0; i < PoolSize; i++) { KeyValuePairsXAsset header = instance.Reader.ReadStruct <KeyValuePairsXAsset>(Entries + (i * ElementSize)); if (IsNullXAsset(header.Name)) { continue; } string key = instance.Reader.ReadNullTerminatedString(header.Name); if (entries.TryGetValue(key, out string _)) { continue; } KeyValuePair data = instance.Reader.ReadStruct <KeyValuePair>(header.KeyValuePairs); string value = instance.Reader.ReadNullTerminatedString(data.Value); entries.Add(key, value); Console.WriteLine($"Exported {Name} {key}"); } string path = Path.Combine(instance.ExportPath, "keyValuePairs.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); using (StreamWriter file = File.CreateText(path)) { file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); } return(results); }
/// <summary> /// Load the valid XAssets for the Localize XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of Localize XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { List <GameXAsset> results = new List <GameXAsset>(); XAssetPool pool = instance.Reader.ReadStruct <XAssetPool>(instance.Game.DBAssetPools + (Index * Marshal.SizeOf <XAssetPool>())); Entries = pool.Pool; ElementSize = pool.ItemSize; PoolSize = (uint)pool.ItemCount; if (IsValidPool(Name, ElementSize, Marshal.SizeOf <LocalizeEntry>()) == false) { return(results); } Dictionary <string, string> entries = new Dictionary <string, string>(); for (int i = 0; i < PoolSize; i++) { LocalizeEntry header = instance.Reader.ReadStruct <LocalizeEntry>(Entries + (i * ElementSize)); if (IsNullXAsset(header.Name)) { continue; } string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); if (entries.TryGetValue(key, out string _)) { continue; } string value = instance.Reader.ReadNullTerminatedString(header.Value, nullCheck: true); entries.Add(key, value); Console.WriteLine($"Exported {Name} {key}"); } string path = Path.Combine(instance.ExportPath, "localize.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); using (StreamWriter file = File.CreateText(path)) { file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); } return(results); }
/// <summary> /// Load the valid XAssets for the ScriptFile XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of ScriptFile XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { List <GameXAsset> results = new List <GameXAsset>(); DBAssetPool poolInfo = instance.Reader.ReadStruct <DBAssetPool>(instance.Game.BaseAddress + instance.Game.DBAssetPools + (Index * Marshal.SizeOf <DBAssetPool>())); Entries = poolInfo.Entries; ElementSize = poolInfo.ElementSize; PoolSize = poolInfo.PoolSize; if (IsValidPool(Name, ElementSize, Marshal.SizeOf <ScriptFileXAsset>()) == false) { return(results); } for (int i = 0; i < PoolSize; i++) { ScriptFileXAsset header = instance.Reader.ReadStruct <ScriptFileXAsset>(Entries + (i * ElementSize)); if (IsNullXAsset(header.Name)) { continue; } else if (header.CompressedLen == 0) { continue; } else if (header.Len == 0) { continue; } else if (header.BytecodeLen == 0) { continue; } results.Add(new GameXAsset() { Name = instance.Reader.ReadNullTerminatedString(header.Name), Type = Name, Size = ElementSize, XAssetPool = this, HeaderAddress = Entries + (i * ElementSize), }); } return(results); }
/// <summary> /// Exports the specified RawFile XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { RawFileXAsset header = instance.Reader.ReadStruct <RawFileXAsset>(xasset.HeaderAddress); string path = Path.Combine(instance.ExportPath, "rawfile/" + xasset.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.Len); File.WriteAllBytes(path, buffer); Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Validates and sets the DBAssetPools address of Modern Warfare. /// </summary> /// <param name="instance"></param> /// <returns>True if address is valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); var scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x48, 0x8D, 0x04, 0x40, 0x4C, 0x8D, 0x8E, null, null, null, null, 0x4D, 0x8D, 0x0C, 0xC1, 0x8D, 0x42, 0xFF }, BaseAddress, BaseAddress + instance.Reader.GetModuleMemorySize(), true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadInt32(scanDBAssetPools[0] + 0x7); // In Modern Warfare, axis_guide_createfx will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "axis_guide_createfx") { List <Dictionary <string, object> > pools = new List <Dictionary <string, object> >(); foreach (int index in Enum.GetValues(typeof(XAssetType))) { DBAssetPool pool = instance.Reader.ReadStruct <DBAssetPool>(instance.Game.BaseAddress + instance.Game.DBAssetPools + (index * Marshal.SizeOf <DBAssetPool>())); pools.Add(new Dictionary <string, object>() { { "Name", Enum.GetName(typeof(XAssetType), index) }, { "ElementSize", pool.ElementSize }, }); } string path = Path.Combine(instance.ExportPath, "DBAssetPools.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); using (StreamWriter file = File.CreateText(path)) { file.Write(JsonConvert.SerializeObject(pools, Formatting.Indented)); } return(true); } } return(false); }
/// <summary> /// Exports the specified StringTable XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { StringTableXAsset header = instance.Reader.ReadStruct <StringTableXAsset>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } string path = Path.Combine(instance.ExportPath, xasset.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); StringBuilder stringTable = new StringBuilder(); int index = 0; for (int x = 0; x < header.RowCount; x++) { for (int y = 0; y < header.ColumnCount; y++) { int cell = instance.Reader.ReadInt16(header.CellIndices + (2 * index)); string value = instance.Reader.ReadNullTerminatedString(instance.Reader.ReadInt64(header.Strings + (8 * cell))); stringTable.Append(value); if (y != (header.ColumnCount - 1)) { stringTable.Append(","); } index++; } stringTable.AppendLine(); } File.WriteAllText(path, stringTable.ToString()); Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Exports the specified ScriptFile XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { ScriptFileXAsset header = instance.Reader.ReadStruct <ScriptFileXAsset>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } string addedScriptsFolder = Path.Combine(xasset.Name.Contains("scripts") ? "" : "scripts", xasset.Name); string path = Path.Combine(instance.ExportPath, addedScriptsFolder.Contains(".gsc") ? addedScriptsFolder + "bin" : addedScriptsFolder + ".gscbin"); Directory.CreateDirectory(Path.GetDirectoryName(path)); byte[] filename = Encoding.UTF8.GetBytes(xasset.Name + char.MinValue); byte[] compressedLen = BitConverter.GetBytes(header.CompressedLen); byte[] len = BitConverter.GetBytes(header.Len); byte[] bytecodeLen = BitConverter.GetBytes(header.BytecodeLen); byte[] buffer = instance.Reader.ReadBytes(header.Buffer, header.CompressedLen); byte[] bytecode = instance.Reader.ReadBytes(header.Bytecode, header.BytecodeLen); byte[] file = new byte[filename.Length + compressedLen.Length + len.Length + bytecodeLen.Length + buffer.Length + bytecode.Length]; Buffer.BlockCopy(filename, 0, file, 0, filename.Length); Buffer.BlockCopy(compressedLen, 0, file, filename.Length, compressedLen.Length); Buffer.BlockCopy(len, 0, file, filename.Length + compressedLen.Length, len.Length); Buffer.BlockCopy(bytecodeLen, 0, file, filename.Length + compressedLen.Length + len.Length, bytecodeLen.Length); Buffer.BlockCopy(buffer, 0, file, filename.Length + compressedLen.Length + len.Length + bytecodeLen.Length, buffer.Length); Buffer.BlockCopy(bytecode, 0, file, filename.Length + compressedLen.Length + len.Length + bytecodeLen.Length + buffer.Length, bytecode.Length); try { File.WriteAllBytes(path, file); } catch { return(JekyllStatus.Exception); } Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Exports the specified MapEnts XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { MapEntsXAsset header = instance.Reader.ReadStruct <MapEntsXAsset>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } string path = Path.Combine(instance.ExportPath, xasset.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); File.WriteAllText(path, instance.Reader.ReadNullTerminatedString(header.EntityString)); Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Load the valid XAssets for the Localize XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of Localize XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { Entries = instance.Reader.ReadStruct <long>(instance.Game.DBAssetPools + (Marshal.SizeOf <DBAssetPool>() * Index)); PoolSize = instance.Reader.ReadStruct <int>(instance.Game.DBAssetPoolSizes + (Marshal.SizeOf <DBAssetPoolSize>() * Index)); Dictionary <string, string> entries = new Dictionary <string, string>(); Console.WriteLine(PoolSize); for (int i = 0; i < PoolSize; i++) { LocalizeEntry header = instance.Reader.ReadStruct <LocalizeEntry>(Entries + Marshal.SizeOf <DBAssetPool>() + (i * Marshal.SizeOf <LocalizeEntry>())); if (IsNullXAsset(header.Name)) { continue; } string key = instance.Reader.ReadNullTerminatedString(header.Name).ToUpper(); if (entries.TryGetValue(key, out string _)) { continue; } string value = instance.Reader.ReadNullTerminatedString(header.Value); entries.Add(key, value); Console.WriteLine($"Exported {Name} {key}"); } string path = Path.Combine(instance.ExportPath, "localize.json"); Directory.CreateDirectory(Path.GetDirectoryName(path)); using (StreamWriter file = File.CreateText(path)) { file.Write(JsonConvert.SerializeObject(entries, Formatting.Indented)); } return(new List <GameXAsset>()); }
/// <summary> /// Exports the specified StringTable XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { StringTableXAsset header = instance.Reader.ReadStruct <StringTableXAsset>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } string path = Path.Combine(instance.ExportPath, xasset.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); StringBuilder stringTable = new StringBuilder(); for (int x = 0; x < header.RowCount; x++) { for (int y = 0; y < header.ColumnCount; y++) { uint data = instance.Reader.ReadStruct <uint>(header.Values); string value = instance.Reader.ReadNullTerminatedString(data); stringTable.Append(value); if (y != (header.ColumnCount - 1)) { stringTable.Append(","); } header.Values += (uint)Marshal.SizeOf <uint>(); } stringTable.AppendLine(); } File.WriteAllText(path, stringTable.ToString()); Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Exports the specified TTF XAsset. /// </summary> /// <param name="xasset"></param> /// <param name="instance"></param> /// <returns>Status of the export operation.</returns> public override JekyllStatus Export(GameXAsset xasset, JekyllInstance instance) { TTFDef header = instance.Reader.ReadStruct <TTFDef>(xasset.HeaderAddress); if (xasset.Name != instance.Reader.ReadNullTerminatedString(header.Name)) { return(JekyllStatus.MemoryChanged); } string path = Path.Combine(instance.ExportPath, xasset.Name); Directory.CreateDirectory(Path.GetDirectoryName(path)); byte[] buffer = instance.Reader.ReadBytes(header.File, (int)header.FileLen); File.WriteAllBytes(path, buffer); Console.WriteLine($"Exported {xasset.Type} {xasset.Name}"); return(JekyllStatus.Success); }
/// <summary> /// Load the valid XAssets for the ScriptParseTree XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of ScriptParseTree XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { List <GameXAsset> results = new List <GameXAsset>(); XAssetPool pool = instance.Reader.ReadStruct <XAssetPool>(instance.Game.DBAssetPools + (Index * Marshal.SizeOf <XAssetPool>())); Entries = pool.Pool; ElementSize = pool.ItemSize; PoolSize = (uint)pool.ItemCount; if (IsValidPool(Name, ElementSize, Marshal.SizeOf <ScriptParseTree>()) == false) { return(results); } for (int i = 0; i < PoolSize; i++) { ScriptParseTree header = instance.Reader.ReadStruct <ScriptParseTree>(Entries + (i * ElementSize)); if (IsNullXAsset(header.Name)) { continue; } else if (header.Len == 0) { continue; } results.Add(new GameXAsset() { Name = instance.Reader.ReadNullTerminatedString(header.Name), Type = Name, Size = ElementSize, XAssetPool = this, HeaderAddress = Entries + (i * ElementSize), }); } return(results); }
/// <summary> /// Validates and sets the XAsset Pools address of Black Ops III. /// </summary> /// <param name="instance"></param> /// <returns>True if address is valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); var scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x63, 0xC1, 0x48, 0x8D, 0x05, null, null, null, null, 0x49, 0xC1, 0xE0, null, 0x4C, 0x03, 0xC0 }, BaseAddress, BaseAddress + instance.Reader.GetModuleMemorySize(), true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadInt32(scanDBAssetPools[0] + 0x5) + (scanDBAssetPools[0] + 0x9); // In Black Ops III, void will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "void") { return(true); } } return(false); }
/// <summary> /// Validates and sets the DBAssetPools address of Modern Warfare. /// </summary> /// <param name="instance"></param> /// <returns>True if address is valid, otherwise false.</returns> public bool InitializeGame(JekyllInstance instance) { BaseAddress = instance.Reader.GetBaseAddress(); var scanDBAssetPools = instance.Reader.FindBytes( new byte?[] { 0x48, 0x8D, 0x04, 0x40, 0x4C, 0x8D, 0x8E, null, null, null, null, 0x4D, 0x8D, 0x0C, 0xC1, 0x8D, 0x42, 0xFF }, BaseAddress, BaseAddress + instance.Reader.GetModuleMemorySize(), true); if (scanDBAssetPools.Length > 0) { DBAssetPools = instance.Reader.ReadInt32(scanDBAssetPools[0] + 0x7); // In Modern Warfare, axis_guide_createfx will always be the first entry in the XModel XAsset Pool. if (GetFirstXModel(instance) == "axis_guide_createfx") { return(true); } } return(false); }
/// <summary> /// Load the valid XAssets for the RawFile XAsset Pool. /// </summary> /// <param name="instance"></param> /// <returns>List of RawFile XAsset objects.</returns> public override List <GameXAsset> Load(JekyllInstance instance) { List <GameXAsset> results = new List <GameXAsset>(); DBAssetPool pool = instance.Reader.ReadStruct <DBAssetPool>(instance.Game.DBAssetPools + (Index * Marshal.SizeOf <DBAssetPool>())); Entries = pool.Entries; ElementSize = pool.ElementSize; PoolSize = pool.PoolSize; if (IsValidPool(Name, ElementSize, Marshal.SizeOf <RawFileXAsset>()) == false) { return(results); } for (int i = 0; i < PoolSize; i++) { RawFileXAsset header = instance.Reader.ReadStruct <RawFileXAsset>(Entries + (i * ElementSize)); if (header.Len == 0) { continue; } results.Add(new GameXAsset() { Name = instance.Reader.ReadBytesToString(Entries + (i * ElementSize)).ToLower(), Type = Name, Size = ElementSize, XAssetPool = this, HeaderAddress = Entries + (i * Marshal.SizeOf <RawFileXAsset>()), }); } return(results); }