/// <summary> /// Loads a cache file from a stream. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="infoLoader">The BuildInfoLoader responsible for loading build information for the cache file.</param> /// <param name="buildInfo">The variable to store build information to.</param> /// <returns>The cache file that was loaded.</returns> /// <exception cref="ArgumentException">Thrown if the cache file is invalid.</exception> /// <exception cref="NotSupportedException">Thrown if the cache file's target engine is not supported.</exception> public static ICacheFile LoadCacheFile(IReader reader, BuildInfoLoader infoLoader, out BuildInformation buildInfo) { // Set the reader's endianness based upon the file's header magic reader.SeekTo(0); byte[] headerMagic = reader.ReadBlock(4); reader.Endianness = DetermineCacheFileEndianness(headerMagic); // Load engine version info CacheFileVersionInfo version = new CacheFileVersionInfo(reader); if (version.Engine != EngineType.SecondGeneration && version.Engine != EngineType.ThirdGeneration) throw new NotSupportedException("Engine not supported"); // Load build info buildInfo = infoLoader.LoadBuild(version.BuildString); if (buildInfo == null) throw new NotSupportedException("Engine version \"" + version.BuildString + "\" not supported"); // Load the cache file depending upon the engine version switch (version.Engine) { case EngineType.SecondGeneration: return new SecondGenCacheFile(reader, buildInfo, version.BuildString); case EngineType.ThirdGeneration: return new ThirdGenCacheFile(reader, buildInfo, version.BuildString); default: throw new NotSupportedException("Engine not supported"); } }
public HaloPluginGenerator() { InitializeComponent(); DataContext = GeneratorMaps; var supportedBuilds = XDocument.Load(@"Formats\SupportedBuilds.xml"); _buildLoader = new BuildInfoLoader(supportedBuilds, @"Formats\"); }
static void Main(string[] args) { OpenFileDialog ofd = new OpenFileDialog(); ofd.Title = "Open Cache File"; ofd.Filter = "Blam Cache Files|*.map"; if (ofd.ShowDialog() != DialogResult.OK) return; SaveFileDialog sfd = new SaveFileDialog(); sfd.Title = "Save String Dump"; sfd.Filter = "Text Files|*.txt"; if (sfd.ShowDialog() != DialogResult.OK) return; string mapPath = ofd.FileName; string dumpPath = sfd.FileName; BuildInfoLoader loader = new BuildInfoLoader(@"Formats\SupportedBuilds.xml", "Formats"); ICacheFile cacheFile; LocaleTable locales; using (IReader reader = new EndianReader(File.OpenRead(mapPath), Endian.BigEndian)) { Console.WriteLine("Loading cache file..."); cacheFile = CacheFileLoader.LoadCacheFile(reader, loader); Console.WriteLine("Loading locales..."); locales = cacheFile.Languages[LocaleLanguage.English].LoadStrings(reader); } StreamWriter output = new StreamWriter(dumpPath); output.WriteLine("Input file: {0}.map", cacheFile.InternalName); output.WriteLine(); // Sort locales by stringID List<Locale> localesById = new List<Locale>(); foreach (Locale str in locales.Strings) { if (str != null) localesById.Add(str); } localesById.Sort((x, y) => x.ID.Value.CompareTo(y.ID.Value)); // Dump locales Console.WriteLine("Dumping locales..."); output.WriteLine("---------------"); output.WriteLine("English Locales"); output.WriteLine("---------------"); foreach (Locale str in localesById) { if (str != null) output.WriteLine("{0} = \"{1}\"", str.ID, str.Value); } output.WriteLine(); // Dump stringIDs Console.WriteLine("Dumping stringIDs..."); output.WriteLine("---------"); output.WriteLine("StringIDs"); output.WriteLine("---------"); int index = 0; foreach (string str in cacheFile.StringIDs) { if (str != null) output.WriteLine("0x{0:X} = \"{1}\"", index, str); else output.WriteLine("0x{0:X} = (null)", index); index++; } output.Close(); Console.WriteLine("Done!"); }
// Patch Creation private void btnCreatePatch_Click(object sender, RoutedEventArgs e) { try { // Check the user isn't completly retarded if (!CheckAllCreateMandatoryFields()) return; // Check the user isn't a skid if (!CheckAllCreateMetaFilesExists()) return; // Paths var cleanMapPath = txtCreatePatchUnModifiedMap.Text; var moddedMapPath = txtCreatePatchModifiedMap.Text; var outputPath = txtCreatePatchOutputPatch.Text; var previewImage = txtCreatePatchPreviewImage.Text; // Details var author = txtCreatePatchContentAuthor.Text; var desc = txtCreatePatchContentDescription.Text; var name = txtCreatePatchContentName.Text; // Make dat patch var patch = new Patch { Author = author, Description = desc, Name = name, Screenshot = String.IsNullOrEmpty(previewImage) ? null : File.ReadAllBytes(previewImage) }; EndianReader originalReader = null; EndianReader newReader = null; try { originalReader = new EndianReader(File.OpenRead(cleanMapPath), Endian.BigEndian); newReader = new EndianReader(File.OpenRead(moddedMapPath), Endian.BigEndian); var formatsPath = Path.Combine(VariousFunctions.GetApplicationLocation(), "Formats"); var loader = new BuildInfoLoader(Path.Combine(formatsPath, "SupportedBuilds.xml"), formatsPath); var originalFile = CacheFileLoader.LoadCacheFile(originalReader, loader); var newFile = CacheFileLoader.LoadCacheFile(originalReader, loader); if (cbCreatePatchHasCustomMeta.IsChecked != null && (bool)cbCreatePatchHasCustomMeta.IsChecked && cboxCreatePatchTargetGame.SelectedIndex < 4) { var targetGame = (TargetGame)cboxCreatePatchTargetGame.SelectedIndex; var mapInfo = File.ReadAllBytes(txtCreatePatchMapInfo.Text); var mapInfoFileInfo = new FileInfo(txtCreatePatchMapInfo.Text); FileInfo blfFileInfo; patch.CustomBlfContent = new BlfContent(mapInfoFileInfo.FullName, mapInfo, targetGame); #region Blf Data if (PatchCreationBlfOption0.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf0.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption1.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf1.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption2.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf2.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } if (PatchCreationBlfOption3.Visibility == Visibility.Visible) { blfFileInfo = new FileInfo(txtCreatePatchblf3.Text); patch.CustomBlfContent.BlfContainerEntries.Add(new BlfContainerEntry(blfFileInfo.Name, File.ReadAllBytes(blfFileInfo.FullName))); } #endregion } PatchBuilder.BuildPatch(originalFile, originalReader, newFile, newReader, patch); } finally { if (originalReader != null) originalReader.Close(); if (newReader != null) newReader.Close(); } IWriter output = new EndianWriter(File.Open(outputPath, FileMode.Create, FileAccess.Write), Endian.BigEndian); AssemblyPatchWriter.WritePatch(patch, output); output.Close(); MetroMessageBox.Show("Patch Created!", "Your patch has been created in the designated location. Happy sailing, modder!"); } catch (Exception ex) { MetroException.Show(ex); } }
// Patch Applying private void btnApplyPatch_Click(object sender, RoutedEventArgs e) { try { // Check the user isn't completly retarded if (!CheckAllApplyMandatoryFields() || currentPatch == null) return; // Paths var unmoddedMapPath = txtApplyPatchUnmodifiedMap.Text; var outputPath = txtApplyPatchOutputMap.Text; // Copy the original map to the destination path File.Copy(unmoddedMapPath, outputPath, true); // Open the destination map using (var stream = new EndianStream(File.Open(outputPath, FileMode.Open, FileAccess.ReadWrite), Endian.BigEndian)) { var formatsPath = Path.Combine(VariousFunctions.GetApplicationLocation(), "Formats"); var loader = new BuildInfoLoader(Path.Combine(formatsPath, "SupportedBuilds.xml"), formatsPath); var cacheFile = CacheFileLoader.LoadCacheFile(stream, loader); if (currentPatch.MapInternalName != null && cacheFile.InternalName != currentPatch.MapInternalName) { MetroMessageBox.Show("Unable to apply patch", "Hold on there! That patch is for " + currentPatch.MapInternalName + ".map, and the unmodified map file you selected doesn't seem to match that. Find the correct file and try again."); return; } // Apply the patch! if (currentPatch.MapInternalName == null) currentPatch.MapInternalName = cacheFile.InternalName; // Because Ascension doesn't include this, and ApplyPatch() will complain otherwise PatchApplier.ApplyPatch(currentPatch, cacheFile, stream); // Check for blf snaps if (cbApplyPatchBlfExtraction.IsChecked != null && (PatchApplicationPatchExtra.Visibility == Visibility.Visible && (bool)cbApplyPatchBlfExtraction.IsChecked)) { var extractDir = Path.GetDirectoryName(outputPath); var blfDirectory = Path.Combine(extractDir, "images"); var infDirectory = Path.Combine(extractDir, "info"); if (!Directory.Exists(blfDirectory)) Directory.CreateDirectory(blfDirectory); if (!Directory.Exists(infDirectory)) Directory.CreateDirectory(infDirectory); var infPath = Path.Combine(infDirectory, Path.GetFileName(currentPatch.CustomBlfContent.MapInfoFileName)); File.WriteAllBytes(infPath, currentPatch.CustomBlfContent.MapInfo); foreach (var blfContainerEntry in currentPatch.CustomBlfContent.BlfContainerEntries) { var blfPath = Path.Combine(blfDirectory, Path.GetFileName(blfContainerEntry.FileName)); File.WriteAllBytes(blfPath, blfContainerEntry.BlfContainer); } } } MetroMessageBox.Show("Patch Applied!", "Your patch has been applied successfully. Have fun!"); } catch (Exception ex) { MetroException.Show(ex); } }
public void InitalizeMap() { using (var fileStream = File.OpenRead(_cacheLocation)) { var reader = new EndianReader(fileStream, Endian.BigEndian); var formatsPath = Path.Combine(VariousFunctions.GetApplicationLocation(), "Formats"); var supportedBuildsPath = Path.Combine(formatsPath, "SupportedBuilds.xml"); _layoutLoader = new BuildInfoLoader(supportedBuildsPath, formatsPath); try { _cacheFile = CacheFileLoader.LoadCacheFile(reader, _layoutLoader, out _buildInfo); } catch (NotSupportedException ex) { Dispatcher.Invoke(new Action(delegate { if (!_0xabad1dea.IWff.Heman(reader)) { StatusUpdater.Update("Not a supported target engine"); MetroMessageBox.Show("Unable to open cache file", ex.Message + ".\r\nWhy not add support in the 'Formats' folder?"); } else { StatusUpdater.Update("HEYYEYAAEYAAAEYAEYAA"); } Settings.homeWindow.ExternalTabClose((TabItem)Parent); })); return; } _mapManager = new FileStreamManager(_cacheLocation, reader.Endianness); // Build SID trie _stringIDTrie = new Trie(); _stringIDTrie.AddRange(_cacheFile.StringIDs); Dispatcher.Invoke(new Action(delegate { if (Settings.startpageHideOnLaunch) Settings.homeWindow.ExternalTabClose(Home.TabGenre.StartPage); })); // Set up RTE switch (_cacheFile.Engine) { case EngineType.SecondGeneration: _rteProvider = new H2VistaRTEProvider("halo2.exe"); break; case EngineType.ThirdGeneration: _rteProvider = new XBDMRTEProvider(Settings.xbdm); break; } Dispatcher.Invoke(new Action(() => StatusUpdater.Update("Loaded Cache File"))); // Add to Recents Dispatcher.Invoke(new Action(delegate { RecentFiles.AddNewEntry(Path.GetFileName(_cacheLocation), _cacheLocation, _buildInfo.ShortName, Settings.RecentFileType.Cache); StatusUpdater.Update("Added To Recents"); })); LoadHeader(); LoadMetaData(); LoadTags(); LoadLocales(); LoadScripts(); } }
static void Main(string[] args) { if (args.Length != 2) { Console.WriteLine("Usage: mapexpand <map file> <page count>"); Console.WriteLine("Pages are multiples of 0x10000 bytes."); return; } int pageCount; if (!int.TryParse(args[1], out pageCount) || pageCount <= 0) { Console.WriteLine("The page count must be a positive integer."); return; } Console.WriteLine("Reading..."); EndianStream stream = new EndianStream(File.Open(args[0], FileMode.Open, FileAccess.ReadWrite), Endian.BigEndian); CacheFileVersionInfo version = new CacheFileVersionInfo(stream); if (version.Engine != EngineType.ThirdGeneration) { Console.WriteLine("Only third-generation map files are supported."); return; } BuildInfoLoader infoLoader = new BuildInfoLoader(XDocument.Load("Formats/SupportedBuilds.xml"), "Formats/"); BuildInformation buildInfo = infoLoader.LoadBuild(version.BuildString); ThirdGenCacheFile cacheFile = new ThirdGenCacheFile(stream, buildInfo, version.BuildString); Console.WriteLine("- Engine version: {0}", version.BuildString); Console.WriteLine("- Internal name: {0}", cacheFile.InternalName); Console.WriteLine("- Scenario name: {0}", cacheFile.ScenarioName); Console.WriteLine("- File size: 0x{0:X}", cacheFile.FileSize); Console.WriteLine("- Virtual size: 0x{0:X}", cacheFile.MetaArea.Size); for (int i = 0; i < cacheFile.Partitions.Length; i++) { var partition = cacheFile.Partitions[i]; if (partition.BasePointer != null) Console.WriteLine(" - Partition {0} at 0x{1:X}-0x{2:X} (size=0x{3:X})", i, partition.BasePointer.AsPointer(), partition.BasePointer.AsPointer() + partition.Size - 1, partition.Size); } Console.WriteLine("- Meta pointer mask: 0x{0:X}", cacheFile.MetaArea.PointerMask); Console.WriteLine("- Locale pointer mask: 0x{0:X}", (uint)-cacheFile.LocaleArea.PointerMask); Console.WriteLine("- String pointer mask: 0x{0:X}", cacheFile.StringArea.PointerMask); Console.WriteLine(); Console.WriteLine("Injecting empty pages..."); int injectSize = pageCount * 0x10000; Console.WriteLine("- Start address: 0x{0:X} (offset 0x{1:X})", cacheFile.MetaArea.BasePointer - injectSize, cacheFile.MetaArea.Offset); cacheFile.MetaArea.Resize(cacheFile.MetaArea.Size + injectSize, stream); Console.WriteLine(); Console.WriteLine("Adjusting the header..."); cacheFile.SaveChanges(stream); Console.WriteLine(); Console.WriteLine("Successfully injected 0x{0:X} bytes at 0x{1:X} (offset 0x{2:X}).", injectSize, cacheFile.MetaArea.BasePointer, cacheFile.MetaArea.Offset); stream.Close(); }
/// <summary> /// Loads a cache file from a stream. /// </summary> /// <param name="reader">The stream to read from.</param> /// <param name="infoLoader">The BuildInfoLoader responsible for loading build information for the cache file.</param> /// <returns>The cache file that was loaded.</returns> /// <exception cref="ArgumentException">Thrown if the cache file is invalid.</exception> /// <exception cref="NotSupportedException">Thrown if the cache file's target engine is not supported.</exception> public static ICacheFile LoadCacheFile(IReader reader, BuildInfoLoader infoLoader) { BuildInformation tempInfo; return LoadCacheFile(reader, infoLoader, out tempInfo); }