예제 #1
0
        private static async Task WalkFiles(string cleanFolder, string modifiedFolder, string outputFolder)
        {
            string         exeDir              = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            string         formatsDir          = Path.Combine(exeDir, "Formats");
            string         supportedBuildsPath = Path.Combine(formatsDir, "Engines.xml");
            EngineDatabase db = XMLEngineDatabaseLoader.LoadDatabase(supportedBuildsPath);

            List <string> cleanFileNames    = Directory.EnumerateFiles(cleanFolder, "*.map").Select(Path.GetFileName).ToList();
            List <string> modifiedFileNames = Directory.EnumerateFiles(modifiedFolder, "*.map").Select(Path.GetFileName).ToList();

            Console.WriteLine($"{modifiedFileNames.Count} modified cache files were found. Processing the files now.");
            List <Task> tasks = new List <Task>();

            foreach (string fileName in modifiedFileNames)
            {
                if (cleanFileNames.Contains(fileName))
                {
                    string cleanFile    = Path.Combine(cleanFolder, fileName);
                    string modifiedFile = Path.Combine(modifiedFolder, fileName);
                    string outputName   = Path.GetFileNameWithoutExtension(fileName) + "_walk.txt";
                    string outputFile   = Path.Combine(outputFolder, outputName);
                    tasks.Add(Task.Run(() => WalkFile(cleanFile, modifiedFile, outputFile, db)));
                }
                else
                {
                    Console.WriteLine($"An unmodified cache file with the name \"{fileName}\" could not be found. The operation will be skipped.");
                }
            }

            await Task.WhenAll(tasks);

            Console.WriteLine("Finished processing the files. You can close this program now.");
        }
예제 #2
0
 public ScriptDumper()
 {
     _exeDir              = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
     _formatsDir          = Path.Combine(_exeDir, "Formats");
     _supportedBuildsPath = Path.Combine(_formatsDir, "Engines.xml");
     _db = XMLEngineDatabaseLoader.LoadDatabase(_supportedBuildsPath);
 }
예제 #3
0
        public static async Task Create(Dictionary <string, string> arguments, Dictionary <string, string> options)
        {
            await Task.Delay(1);

            var cacheFilePath    = arguments["cache"];
            var projectDirectory = arguments["project"];

            // Check file exists
            if (cacheFilePath == null || !File.Exists(cacheFilePath))
            {
                throw new ComposerException("Cache doesn't exist");
            }

            // Create project directory
            // TODO: think about logic if directory already exists
            if (!Directory.Exists(projectDirectory))
            {
                Directory.CreateDirectory(projectDirectory);
            }

            // Create Project
            var project = new Models.Project
            {
                Title       = "Example Halo Project",
                Version     = "1.0.0",
                Description = "Simple project for testing the tool",
                Properties  = new ProjectProperties
                {
                    TagsFolder = "tags",
                    GitEnabled = true
                }
            };

            using (var stream = File.OpenRead(cacheFilePath))
                using (var reader = new EndianReader(stream, Endian.BigEndian))
                {
                    EngineDescription engineDescription = null;
                    EngineDatabase    engineDatabase    = XMLEngineDatabaseLoader.LoadDatabase("data/formats/engines.xml");
                    var cacheFile    = CacheFileLoader.LoadCacheFile(reader, engineDatabase, out engineDescription);
                    var stringIdTrie = new Trie();
                    if (cacheFile.StringIDs != null)
                    {
                        stringIdTrie.AddRange(cacheFile.StringIDs);
                    }

                    if (cacheFile.TagClasses.Any())
                    {
                        LoadTags(project, cacheFile, projectDirectory, stringIdTrie);
                    }
                }

            File.WriteAllText(Path.Combine(projectDirectory, "project.json"), JsonConvert.SerializeObject(project, Formatting.Indented));
        }
예제 #4
0
        public static bool applyPatch(ZipArchiveEntry zippedPatchFile, string patchFileName, string unmoddedMapPath, string outputPath)
        {
            createTmpDir();
            try {
                zippedPatchFile.ExtractToFile(Config.modpack_dir + @"\tmp\" + patchFileName);
            } catch (IOException) {
                rmTmpDir();
                createTmpDir();
                zippedPatchFile.ExtractToFile(Config.modpack_dir + @"\tmp\" + patchFileName);
            }
            Patch currentPatch = LoadPatch(Config.modpack_dir + @"\tmp\" + patchFileName);

            // Copy the original map to the destination path
            IO.CopyFile(unmoddedMapPath, outputPath, true);             //if modpack has written to unmoddedmap, take from backups

            // Open the destination map
            using (var stream = new EndianStream(File.Open(outputPath, FileMode.Open, FileAccess.ReadWrite), Endian.BigEndian)) {
                EngineDatabase engineDb = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml");
                ICacheFile     cacheFile;
                try {
                    cacheFile = CacheFileLoader.LoadCacheFile(stream, engineDb);
                } catch (NotSupportedException nse) {
                    form1.showMsg("Error patching '" + patchFileName + "':" + nse.Message, "Error");
                    return(false);
                }
                if (!string.IsNullOrEmpty(currentPatch.BuildString) && cacheFile.BuildString != currentPatch.BuildString)
                {
                    form1.showMsg("Unable to patch. That patch is for a map with a build version of " + currentPatch.BuildString +
                                  ", and the unmodified map file doesn't match that.", "Error");
                    return(false);
                }

                if (currentPatch.MapInternalName == null)
                {
                    // Because Ascension doesn't include this, and ApplyPatch() will complain otherwise
                    currentPatch.MapInternalName = cacheFile.InternalName;
                }

                // Apply the patch!
                try {
                    PatchApplier.ApplyPatch(currentPatch, cacheFile, stream);
                } catch (ArgumentException ae) {
                    form1.showMsg("There was an issue applying the patch file '" + patchFileName + "': " + ae.Message, "Info");
                    return(false);
                }
            }

            rmTmpDir();
            return(true);
        }
예제 #5
0
        private static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("Usage: SharedDump <map file(s)>");
                return;
            }

            // Locate the Formats folder and SupportedBuilds.xml
            string         exeDir              = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            string         formatsDir          = Path.Combine(exeDir, "Formats");
            string         supportedBuildsPath = Path.Combine(formatsDir, "Engines.xml");
            EngineDatabase db = XMLEngineDatabaseLoader.LoadDatabase(supportedBuildsPath);

            // Dump each map file
            foreach (string arg in args)
            {
                Console.WriteLine("{0}...", arg);
                DumpSharedResources(arg, db);
            }
        }
예제 #6
0
        public BlamCacheFile(string filePath)
        {
            if (!File.Exists(filePath))
            {
                throw new FileNotFoundException("Invalid cache file path");
            }

            fileStream       = new EndianStream(File.Open(filePath, FileMode.Open, FileAccess.ReadWrite), Endian.LittleEndian);
            cacheFileVersion = new CacheFileVersionInfo(fileStream);
            EngineDatabase database = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml");

            buildInfo = database.FindEngineByVersion(cacheFileVersion.BuildString);

            switch (cacheFileVersion.Engine)
            {
            case EngineType.ThirdGeneration:
                internalCacheFile = CreateThirdGenCacheFile(fileStream, buildInfo, cacheFileVersion);
                break;

            default:
                throw new InvalidOperationException("Only third generation engine map files are supported at the moment!");
            }
        }
예제 #7
0
        // Patch Applying
        private void btnApplyPatch_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                // Check the user isn't completly retarded
                if (!CheckAllApplyMandatoryFields() || currentPatch == null)
                {
                    return;
                }

                // Check the output name
                if (cacheOutputName != "")
                {
                    if (Path.GetFileNameWithoutExtension(txtApplyPatchOutputMap.Text) != cacheOutputName)
                    {
                        if (MetroMessageBox.Show("Warning",
                                                 "This patch suggests to use the filename \"" + cacheOutputName +
                                                 ".map\" to save this map. This filename may be required in order for the map to work correctly.\r\n\r\nAre you sure you want to save this map as \"" +
                                                 Path.GetFileName(txtApplyPatchOutputMap.Text) + "\"?",
                                                 MetroMessageBox.MessageBoxButtons.OkCancel) != MetroMessageBox.MessageBoxResult.OK)
                        {
                            Close();
                            return;
                        }
                    }
                }

                // Paths
                string unmoddedMapPath = txtApplyPatchUnmodifiedMap.Text;
                string 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))
                {
                    EngineDatabase engineDb  = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml");
                    ICacheFile     cacheFile = CacheFileLoader.LoadCacheFile(stream, outputPath, engineDb);
                    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;
                    }
                    if (!string.IsNullOrEmpty(currentPatch.BuildString) && cacheFile.BuildString != currentPatch.BuildString)
                    {
                        MetroMessageBox.Show("Unable to apply patch",
                                             "Hold on there! That patch is for a map with a build version of" + currentPatch.BuildString +
                                             ", 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))
                    {
                        string extractDir   = Path.GetDirectoryName(outputPath);
                        string blfDirectory = Path.Combine(extractDir, "images");
                        string infDirectory = Path.Combine(extractDir, "info");
                        if (!Directory.Exists(blfDirectory))
                        {
                            Directory.CreateDirectory(blfDirectory);
                        }
                        if (!Directory.Exists(infDirectory))
                        {
                            Directory.CreateDirectory(infDirectory);
                        }

                        string infPath = Path.Combine(infDirectory, Path.GetFileName(currentPatch.CustomBlfContent.MapInfoFileName));
                        File.WriteAllBytes(infPath, currentPatch.CustomBlfContent.MapInfo);

                        foreach (BlfContainerEntry blfContainerEntry in currentPatch.CustomBlfContent.BlfContainerEntries)
                        {
                            string 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);
            }
        }
예제 #8
0
        static void Main(string[] args)
        {
            if (args.Length != 3)
            {
                Console.WriteLine("Usage: BlockAlignmentScanner <map dir> <in plugin dir> <out plugin dir>");
                return;
            }

            var mapDir = args[0];
            var inDir  = args[1];
            var outDir = args[2];

            Console.WriteLine("Loading plugins...");
            var pluginsByClass = new Dictionary <string, XDocument>();

            foreach (var pluginPath in Directory.EnumerateFiles(inDir, "*.xml"))
            {
                Console.WriteLine("- {0}", pluginPath);
                var document  = XDocument.Load(pluginPath);
                var className = Path.GetFileNameWithoutExtension(pluginPath);
                pluginsByClass[className] = document;
            }

            Console.WriteLine("Loading engine database...");
            var exeDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            var dbPath = Path.Combine(exeDir, "Formats", "Engines.xml");
            var db     = XMLEngineDatabaseLoader.LoadDatabase(dbPath);

            Console.WriteLine("Processing maps...");
            var alignsByElem = new Dictionary <XElement, int>();

            foreach (var mapPath in Directory.EnumerateFiles(mapDir, "*.map"))
            {
                Console.WriteLine("- {0}", Path.GetFileName(mapPath));
                using (var reader = new EndianReader(File.OpenRead(mapPath), Endian.BigEndian))
                {
                    var map = CacheFileLoader.LoadCacheFile(reader, db);
                    var visitedTagBlocks = new HashSet <uint>();
                    foreach (var tag in map.Tags)
                    {
                        if (tag == null || tag.Class == null || tag.MetaLocation == null)
                        {
                            continue;
                        }

                        // Get the plugin for the tag
                        var       className = CharConstant.ToString(tag.Class.Magic);
                        XDocument plugin;
                        if (!pluginsByClass.TryGetValue(className, out plugin))
                        {
                            continue;
                        }

                        // Process it
                        var baseOffset  = tag.MetaLocation.AsOffset();
                        var baseElement = plugin.Element("plugin");
                        DetectAlignment(map, reader, baseOffset, baseElement, alignsByElem, visitedTagBlocks);
                    }
                }
            }

            Console.WriteLine("Adjusting plugins...");
            foreach (var align in alignsByElem)
            {
                if (align.Value != 4)
                {
                    Console.WriteLine("- \"{0}\" -> align 0x{1:X}", align.Key.Attribute("name").Value, align.Value);
                    align.Key.SetAttributeValue(XName.Get("align"), "0x" + align.Value.ToString("X"));
                }
            }

            if (!Directory.Exists(outDir))
            {
                Directory.CreateDirectory(outDir);
            }

            Console.WriteLine("Saving plugins...");
            foreach (var plugin in pluginsByClass)
            {
                var outPath = Path.Combine(outDir, plugin.Key + ".xml");
                Console.WriteLine("- {0}", outPath);

                var settings = new XmlWriterSettings();
                settings.Indent      = true;
                settings.IndentChars = "\t";
                using (var writer = XmlWriter.Create(outPath, settings))
                    plugin.Value.Save(writer);
            }
        }
예제 #9
0
        private static void Main(string[] args)
        {
            var ofd = new OpenFileDialog();

            ofd.Title  = "Open Cache File";
            ofd.Filter = "Blam Cache Files|*.map";
            if (ofd.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            var 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;

            EngineDatabase engineDb = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml");
            ICacheFile     cacheFile;
            LanguagePack   locales;

            using (IReader reader = new EndianReader(File.OpenRead(mapPath), Endian.BigEndian))
            {
                Console.WriteLine("Loading cache file...");
                cacheFile = CacheFileLoader.LoadCacheFile(reader, mapPath, engineDb);

                Console.WriteLine("Loading locales...");
                locales = cacheFile.Languages.LoadLanguage(GameLanguage.English, reader);
            }

            var output = new StreamWriter(dumpPath);

            output.WriteLine("Input file: {0}.map", cacheFile.InternalName);
            output.WriteLine();

            // Sort locales by stringID
            var localesById = new List <LocalizedString>();

            localesById.AddRange(locales.StringLists.SelectMany(l => l.Strings).Where(s => s != null && s.Value != null));
            localesById.Sort((x, y) => x.Key.Value.CompareTo(y.Key.Value));

            // Dump locales
            Console.WriteLine("Dumping locales...");
            output.WriteLine("---------------");
            output.WriteLine("English Locales");
            output.WriteLine("---------------");
            foreach (LocalizedString str in localesById)
            {
                if (str != null)
                {
                    output.WriteLine("{0} = \"{1}\"", str.Key, 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!");
        }
예제 #10
0
        private static void Main(string[] args)
        {
            if (args.Length != 3)
            {
                Console.WriteLine("Usage: mapexpand <map file> <section> <page count>");
                Console.WriteLine();
                Console.WriteLine("Available sections:");
                Console.WriteLine("  stringidindex");
                Console.WriteLine("  stringiddata");
                Console.WriteLine("  tagnameindex");
                Console.WriteLine("  tagnamedata");
                Console.WriteLine("  resource");
                Console.WriteLine("  tag");
                return;
            }

            int pageCount;

            if (!int.TryParse(args[2], out pageCount) || pageCount <= 0)
            {
                Console.WriteLine("The page count must be a positive integer.");
                return;
            }

            Console.WriteLine("Reading...");

            var stream  = new EndianStream(File.Open(args[0], FileMode.Open, FileAccess.ReadWrite), Endian.BigEndian);
            var version = new CacheFileVersionInfo(stream);

            if (version.Engine != EngineType.ThirdGeneration)
            {
                Console.WriteLine("Only third-generation map files are supported.");
                return;
            }

            var database  = XMLEngineDatabaseLoader.LoadDatabase("Formats/Engines.xml");
            var buildInfo = database.FindEngineByVersion(version.BuildString);
            var cacheFile = new ThirdGenCacheFile(stream, buildInfo, version.BuildString);

            FileSegmentGroup area;
            FileSegment      section;
            int pageSize;

            switch (args[1])
            {
            case "stringidindex":
                area     = cacheFile.StringArea;
                section  = cacheFile.StringIDIndexTable;
                pageSize = 0x1000;
                break;

            case "stringiddata":
                area     = cacheFile.StringArea;
                section  = cacheFile.StringIDDataTable;
                pageSize = 0x1000;
                break;

            case "tagnameindex":
                area     = cacheFile.StringArea;
                section  = cacheFile.FileNameIndexTable;
                pageSize = 0x1000;
                break;

            case "tagnamedata":
                area     = cacheFile.StringArea;
                section  = cacheFile.FileNameDataTable;
                pageSize = 0x1000;
                break;

            case "resource":
                area     = null;
                section  = cacheFile.RawTable;
                pageSize = 0x1000;
                break;

            case "tag":
                area     = cacheFile.MetaArea;
                section  = cacheFile.MetaArea.Segments[0];
                pageSize = 0x10000;
                break;

            default:
                Console.WriteLine("Invalid section name: \"{0}\"", args[1]);
                return;
            }

            Console.WriteLine("- Engine version: {0}", version.BuildString);
            Console.WriteLine("- Internal name: {0}", cacheFile.InternalName);
            Console.WriteLine("- Scenario name: {0}", cacheFile.ScenarioName);
            Console.WriteLine();

            Console.WriteLine("Injecting empty pages...");

            var injectSize = pageCount * pageSize;

            section.Resize(section.Size + injectSize, stream);

            Console.WriteLine("Adjusting the header...");

            cacheFile.SaveChanges(stream);
            stream.Dispose();

            Console.WriteLine();

            var offset = section.Offset;

            if (section.ResizeOrigin == SegmentResizeOrigin.End)
            {
                offset += section.ActualSize - injectSize;
            }

            if (area != null)
            {
                Console.WriteLine("Successfully injected 0x{0:X} bytes at 0x{1:X} (offset 0x{2:X}).", injectSize, area.BasePointer, offset);
            }
            else
            {
                Console.WriteLine("Successfully injected 0x{0:X} bytes at offset 0x{1:X}.", injectSize, offset);
            }
        }