public void TestFileStreamRebuildWad() { WadBuilder wadBuilder = new WadBuilder(); // Build entries foreach (WadEntry entry in this._originalWad.Entries.Values) { WadEntryBuilder entryBuilder = new WadEntryBuilder(entry.ChecksumType); Stream entryDecompressedStream = entry.GetDataHandle().GetDecompressedStream(); string entryFileName = "temp/" + entry.XXHash + "." + Utilities.GetExtension(Utilities.GetExtensionType(entryDecompressedStream)); // Extract entry data to temporary file using (FileStream writeEntryFileStream = File.OpenWrite(entryFileName)) { entry.GetDataHandle().GetDecompressedStream().CopyTo(writeEntryFileStream); } entryBuilder .WithPathXXHash(entry.XXHash) .WithFileDataStream(entryFileName); wadBuilder.WithEntry(entryBuilder); } MemoryStream rebuiltWadStream = new MemoryStream(); Assert.DoesNotThrow(delegate { wadBuilder.Build(rebuiltWadStream, true); }, "Failed to build WAD using files"); rebuiltWadStream.Seek(0, SeekOrigin.Begin); this._fileStreamWad = Wad.Mount(rebuiltWadStream, true); }
public static WadBuilder Merge(WadBuilder wadBase, WadBuilder wadToMerge) { WadBuilder wadBuilder = new WadBuilder(); // First add new files and then modify changed ones foreach (var entryToMerge in wadToMerge.Entries) { // Add new entry if (wadBase.Entries.ContainsKey(entryToMerge.Key) is false) { wadBuilder.WithEntry(entryToMerge.Value); } // Modify existing entry else if (!entryToMerge.Value.Sha256Checksum.SequenceEqual(wadBase.Entries[entryToMerge.Key].Sha256Checksum)) { wadBuilder.WithEntry(entryToMerge.Value); } } // Copy over the rest foreach (var entry in wadBase.Entries.Where(x => wadToMerge.Entries.ContainsKey(x.Key) is false)) { wadBuilder.WithEntry(entry.Value); } return(wadBuilder); }
private void PackWadFolder(string wadFolderLocation) { string[] wadFolderFiles = Directory.GetFiles(wadFolderLocation, "*", SearchOption.AllDirectories); if (wadFolderFiles.Length > 0) { char separator = Pathing.GetPathSeparator(wadFolderLocation); string wadName = wadFolderLocation.Split(separator).Last(); WadBuilder wad = new WadBuilder(); //Add each file to the WAD foreach (string wadFolderFile in Directory.EnumerateFiles(wadFolderLocation, "*", SearchOption.AllDirectories)) { string path = wadFolderFile.Replace(wadFolderLocation + separator, "").Replace('\\', '/'); ulong hash = XXHash.XXH64(Encoding.ASCII.GetBytes(path.ToLower())); WadEntryBuilder entryBuilder = new(); entryBuilder .WithPathXXHash(hash) .WithFileDataStream(File.OpenRead(wadFolderFile)); wad.WithEntry(entryBuilder); } //After WAD creation is finished we can write the WAD to the ZIP ZipArchiveEntry archiveEntry = this.Content.CreateEntry(string.Format("WAD/{0}", wadName)); wad.Build(archiveEntry.Open(), false); } }
public override void OnInspectorGUI() { DrawDefaultInspector(); WadBuilder wadBuilder = (WadBuilder)target; if (GUILayout.Button("Load and Build Wad Map")) { wadBuilder.LoadAndBuildMap(); } }
public void TestDataStreamRebuildWad() { WadBuilder wadBuilder = new WadBuilder(); // Build entries foreach (WadEntry entry in this._originalWad.Entries.Values) { WadEntryBuilder entryBuilder = new WadEntryBuilder(entry.ChecksumType); entryBuilder .WithPathXXHash(entry.XXHash); if (entry.Type == WadEntryType.GZipCompressed) { entryBuilder.WithGZipDataStream(entry.GetDataHandle().GetCompressedStream(), entry.CompressedSize, entry.UncompressedSize); } else if (entry.Type == WadEntryType.ZStandardCompressed) { entryBuilder.WithZstdDataStream(entry.GetDataHandle().GetCompressedStream(), entry.CompressedSize, entry.UncompressedSize); } else if (entry.Type == WadEntryType.Uncompressed) { entryBuilder.WithUncompressedDataStream(entry.GetDataHandle().GetDecompressedStream()); } else if (entry.Type == WadEntryType.FileRedirection) { entryBuilder.WithFileRedirection(entry.FileRedirection); } wadBuilder.WithEntry(entryBuilder); } MemoryStream rebuiltWadStream = new MemoryStream(); Assert.DoesNotThrow(delegate { wadBuilder.Build(rebuiltWadStream, true); }, "Failed to build WAD using data streams"); rebuiltWadStream.Seek(0, SeekOrigin.Begin); this._dataStreamWad = Wad.Mount(rebuiltWadStream, true); }
public void UninstallMod(ModFile mod) { Log.Information("Uninstalling Mod: " + mod.GetID()); List <ulong> moddedEntries = new List <ulong>(); if (this.Index.ModEntryMap.TryGetValue(mod.GetID(), out List <ulong> _moddedEntries)) { moddedEntries = new List <ulong>(_moddedEntries); } Dictionary <string, WadBuilder> moddedWads = new Dictionary <string, WadBuilder>(); this.Index.StartEdit(); //In this loop we remove the installed WAD entries foreach (ulong moddedEntry in moddedEntries) { List <string> moddedEntryWadFiles = this.Index.Mod[moddedEntry]; //Initialize WAD files for entry deletion foreach (string moddedEntryWadFile in moddedEntryWadFiles) { if (!moddedWads.ContainsKey(moddedEntryWadFile)) { using Wad moddedWad = Wad.Mount(string.Format(@"{0}\{1}", OVERLAY_FOLDER, moddedEntryWadFile), false); moddedWads.Add(moddedEntryWadFile, new WadBuilder(moddedWad)); } moddedWads[moddedEntryWadFile].RemoveEntry(moddedEntry); } this.Index.RemoveModdedEntry(moddedEntry, mod.GetID()); } //Now we need to either delete empty WAD files or fill the ones from which we removed the entries with original files //if the modified ones are the same as original then we need to delete those too foreach (KeyValuePair <string, WadBuilder> moddedWad in moddedWads) { //If the WAD isn't being used by any other mod or is empty we can delete it if (this.Index.WadModMap[moddedWad.Key].All(x => x == mod.GetID()) || moddedWad.Value.Entries.Count == 0) { File.Delete(string.Format(@"{0}\{1}", OVERLAY_FOLDER, moddedWad.Key)); } //If it's used by some other mods we need to merge it into the original WAD else { string gameWadPath = string.Format(@"{0}\{1}", this.LeagueFolder, moddedWad.Key); string overlayWadPath = string.Format(@"{0}\{1}", OVERLAY_FOLDER, moddedWad.Key); using Wad originalWad = Wad.Mount(gameWadPath, false); WadBuilder mergedWad = WadMerger.Merge(new WadBuilder(originalWad), moddedWad.Value); mergedWad.Build(overlayWadPath + ".temp"); File.Delete(overlayWadPath); File.Move(overlayWadPath + ".temp", overlayWadPath); } } this.Database.ChangeModState(mod.GetID(), false); this.Index.RemoveMod(mod.GetID()); this.Index.EndEdit(); }
private void WriteModWADFiles(ModFile mod) { Action <KeyValuePair <string, WadBuilder> > writeWadFileDelegate = new (WriteWadFile); if (Config.Get <bool>("ParallelWadInstallation")) { ParallelOptions parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = Environment.ProcessorCount }; Parallel.ForEach(mod.GetWadFiles(this.Index), parallelOptions, (modWadFile) => { writeWadFileDelegate.Invoke(modWadFile); }); } else { var modWadFiles = mod.GetWadFiles(this.Index); foreach (var modWadFile in modWadFiles) { writeWadFileDelegate.Invoke(modWadFile); } foreach (var modWadFile in modWadFiles) { modWadFile.Value.Dispose(); } } void WriteWadFile(KeyValuePair <string, WadBuilder> modWadFile) { string wadPath = this.Index.FindWADPath(modWadFile.Key); string overlayModWadPath = string.Format(@"{0}\{1}", OVERLAY_FOLDER, wadPath); string gameModWadPath = string.Format(@"{0}\{1}", this.LeagueFolder, wadPath); //Check if the WAD already exists, if it does, we need to merge the 2 WADs //if it doesnt, then we need to copy it from the game directory if (!File.Exists(overlayModWadPath)) { Directory.CreateDirectory(Path.GetDirectoryName(overlayModWadPath)); using (Wad baseWad = Wad.Mount(gameModWadPath, false)) { WadBuilder mergedWad = WadMerger.Merge(new WadBuilder(baseWad), modWadFile.Value); mergedWad.Build(overlayModWadPath); } } else { File.Move(overlayModWadPath, overlayModWadPath + ".temp"); using (Wad mergedWad = Wad.Mount(overlayModWadPath + ".temp", false)) { WadBuilder mergedWadBuilder = WadMerger.Merge(new WadBuilder(mergedWad), modWadFile.Value); mergedWadBuilder.Build(overlayModWadPath); } //Delete temp wad file File.Delete(overlayModWadPath + ".temp"); } } }