public void Build(ModList lst) { Text($"### {lst.Name} - Installation Summary"); Text( $"#### Download Summary ({lst.Archives.Count} archives - {lst.Archives.Sum(a => a.Size).ToFileSizeString()})"); foreach (var archive in SortArchives(lst.Archives)) { var hash = archive.Hash.FromBase64().ToHEX(); switch (archive) { case NexusMod m: var profile = m.UploaderProfile.Replace("/games/", "/" + NexusApiUtils.ConvertGameName(m.GameName).ToLower() + "/"); NoWrapText( $"* [{m.Name}](http://nexusmods.com/{NexusApiUtils.ConvertGameName(m.GameName)}/mods/{m.ModID})"); NoWrapText($" * Author : [{m.UploadedBy}]({profile})"); NoWrapText($" * Version : {m.Version}"); break; case MODDBArchive m: NoWrapText($"* MODDB - [{m.Name}]({m.URL})"); break; case MEGAArchive m: NoWrapText($"* MEGA - [{m.Name}]({m.URL})"); break; case GoogleDriveMod m: NoWrapText( $"* GoogleDrive - [{m.Name}](https://drive.google.com/uc?id={m.Id}&export=download)"); break; case DirectURLArchive m: NoWrapText($"* URL - [{m.Name} - {m.URL}]({m.URL})"); break; } NoWrapText($" * Size : {archive.Size.ToFileSizeString()}"); NoWrapText($" * SHA256 : [{hash}](https://www.virustotal.com/gui/file/{hash})"); } Text("\n\n"); var patched = lst.Directives.OfType <PatchedFromArchive>().OrderBy(p => p.To).ToList(); Text($"#### Summary of ({patched.Count}) patches"); foreach (var directive in patched) { NoWrapText( $"* Applying {directive.Patch.Length} byte patch `{directive.FullPath}` to create `{directive.To}`"); } var files = lst.Directives.OrderBy(d => d.To).ToList(); Text($"\n\n### Install Plan of ({files.Count}) files"); Text("(ignoring files that are directly copied from archives or listed in the patches section above)"); foreach (var directive in files.OrderBy(f => f.GetType().Name).ThenByDescending(f => f.To)) { switch (directive) { case FromArchive f: //NoWrapText($"* `{f.To}` from `{f.FullPath}`"); break; case CleanedESM i: NoWrapText($"* `{i.To}` by applying a patch to a game ESM ({i.SourceESMHash})"); break; case RemappedInlineFile i: NoWrapText($"* `{i.To}` by remapping the contents of an inline file"); break; case InlineFile i: NoWrapText($"* `{i.To}` from `{i.SourceData.Length.ToFileSizeString()}` file included in modlist"); break; case CreateBSA i: NoWrapText( $"* `{i.To}` by creating a BSA of files found in `{Consts.BSACreationDir}\\{i.TempID}`"); break; } } var inlined = lst.Directives.OfType <InlineFile>() .Select(f => (f.To, "inlined", f.SourceData.Length)) .Concat(lst.Directives .OfType <PatchedFromArchive>() .Select(f => (f.To, "patched", f.Patch.Length))) .ToHashSet() .OrderByDescending(f => f.Length); NoWrapText("\n\n### Summary of inlined files in this installer"); foreach (var inline in inlined) { NoWrapText($"* {inline.Length.ToFileSizeString()} for {inline.Item2} file {inline.To}"); } }
public Installer(ModList mod_list, string output_folder, Action <string> log_fn) { Outputfolder = output_folder; ModList = mod_list; Log_Fn = log_fn; }
public void Build(ModList lst) { Text($"### {lst.Name} - Installation Summary"); Text($"#### Download Summary ({lst.Archives.Count} archives)"); foreach (var archive in SortArchives(lst.Archives)) { switch (archive) { case NexusMod m: var profile = m.UploaderProfile.Replace("/games/", "/" + NexusAPI.ConvertGameName(m.GameName).ToLower() + "/"); NoWrapText($"* [{m.UploadedBy}]({profile}) - [{m.Name}](http://nexusmods.com/{NexusAPI.ConvertGameName(m.GameName)}/mods/{m.ModID})"); break; case MODDBArchive m: NoWrapText($"* MODDB - [{m.Name}]({m.URL})"); break; case MEGAArchive m: NoWrapText($"* MEGA - [{m.Name}]({m.URL})"); break; case GoogleDriveMod m: NoWrapText($"* GoogleDrive - [{m.Name}](https://drive.google.com/uc?id={m.Id}&export=download)"); break; case DirectURLArchive m: NoWrapText($"* URL - [{m.Name} - {m.URL}]({m.URL})"); break; } } Text($"\n\n"); var patched = lst.Directives.OfType <PatchedFromArchive>().OrderBy(p => p.To).ToList(); Text($"#### Summary of ({patched.Count}) patches"); foreach (var directive in patched) { NoWrapText($"* Applying {directive.Patch.Length} byte patch `{directive.FullPath}` to create `{directive.To}`"); } var files = lst.Directives.OrderBy(d => d.To).ToList(); Text($"\n\n### Install Plan of ({files.Count}) files"); Text($"(ignoring files that are directly copied from archives or listed in the patches section above)"); foreach (var directive in files) { switch (directive) { case FromArchive f: //NoWrapText($"* `{f.To}` from `{f.FullPath}`"); break; case CleanedESM i: NoWrapText($"* `{i.To}` by applying a patch to a game ESM ({i.SourceESMHash})"); break; case RemappedInlineFile i: NoWrapText($"* `{i.To}` by remapping the contents of a inline file"); break; case InlineFile i: NoWrapText($"* `{i.To}` from `{i.SourceData.Length}` byte file included in modlist"); break; case CreateBSA i: NoWrapText($"* `{i.To}` by creating a BSA of files found in `{Consts.BSACreationDir}\\{i.TempID}`"); break; } } }
public void Compile() { var mo2_files = Directory.EnumerateFiles(MO2Folder, "*", SearchOption.AllDirectories) .Where(p => p.FileExists()) .Select(p => new RawSourceFile() { Path = p.RelativeTo(MO2Folder), AbsolutePath = p }); var game_files = Directory.EnumerateFiles(GamePath, "*", SearchOption.AllDirectories) .Where(p => p.FileExists()) .Select(p => new RawSourceFile() { Path = Path.Combine(Consts.GameFolderFilesDir, p.RelativeTo(GamePath)), AbsolutePath = p }); Info("Searching for mod files"); AllFiles = mo2_files.Concat(game_files).ToList(); Info("Found {0} files to build into mod list", AllFiles.Count); ExtraFiles = new ConcurrentBag <Directive>(); var stack = MakeStack(); Info("Running Compilation Stack"); var results = AllFiles.PMap(f => RunStack(stack, f)).ToList(); // Add the extra files that were generated by the stack Info($"Adding {ExtraFiles.Count} that were generated by the stack"); results = results.Concat(ExtraFiles).ToList(); var nomatch = results.OfType <NoMatch>(); Info("No match for {0} files", nomatch.Count()); foreach (var file in nomatch) { Info(" {0}", file.To); } if (nomatch.Count() > 0) { Info("Exiting due to no way to compile these files"); return; } InstallDirectives = results.Where(i => !(i is IgnoredDirectly)).ToList(); GatherArchives(); BuildPatches(); ModList = new ModList() { Archives = SelectedArchives, Directives = InstallDirectives, Name = MO2Profile }; PatchExecutable(); ResetMembers(); Info("Done Building Modpack"); }
public void Compile() { Info($"Indexing {MO2Folder}"); VFS.AddRoot(MO2Folder); Info($"Indexing {GamePath}"); VFS.AddRoot(GamePath); var mo2_files = Directory.EnumerateFiles(MO2Folder, "*", SearchOption.AllDirectories) .Where(p => p.FileExists()) .Select(p => new RawSourceFile(VFS.Lookup(p)) { Path = p.RelativeTo(MO2Folder) }); var game_files = Directory.EnumerateFiles(GamePath, "*", SearchOption.AllDirectories) .Where(p => p.FileExists()) .Select(p => new RawSourceFile(VFS.Lookup(p)) { Path = Path.Combine(Consts.GameFolderFilesDir, p.RelativeTo(GamePath)) }); var loot_path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "LOOT"); Info($"Indexing {loot_path}"); VFS.AddRoot(loot_path); var loot_files = Directory.EnumerateFiles(loot_path, "userlist.yaml", SearchOption.AllDirectories) .Where(p => p.FileExists()) .Select(p => new RawSourceFile(VFS.Lookup(p)) { Path = Path.Combine(Consts.LOOTFolderFilesDir, p.RelativeTo(loot_path)) }); Info($"Indexing Archives"); IndexedArchives = Directory.EnumerateFiles(MO2DownloadsFolder) .Where(f => Consts.SupportedArchives.Contains(Path.GetExtension(f))) .Where(f => File.Exists(f + ".meta")) .Select(f => new IndexedArchive() { File = VFS.Lookup(f), Name = Path.GetFileName(f), IniData = (f + ".meta").LoadIniFile(), Meta = File.ReadAllText(f + ".meta") }) .ToList(); Info($"Indexing Files"); IndexedFiles = IndexedArchives.PMap(f => { Status($"Finding files in {Path.GetFileName(f.File.FullPath)}"); return(VFS.FilesInArchive(f.File)); }) .SelectMany(fs => fs) .OrderByDescending(f => f.TopLevelArchive.LastModified) .GroupBy(f => f.Hash) .ToDictionary(f => f.Key, f => f.AsEnumerable()); Info("Searching for mod files"); AllFiles = mo2_files.Concat(game_files) .Concat(loot_files) .ToList(); Info("Found {0} files to build into mod list", AllFiles.Count); ExtraFiles = new ConcurrentBag <Directive>(); ModInis = Directory.EnumerateDirectories(Path.Combine(MO2Folder, "mods")) .Select(f => { var mod_name = Path.GetFileName(f); var meta_path = Path.Combine(f, "meta.ini"); if (File.Exists(meta_path)) { return(mod_name, meta_path.LoadIniFile()); } return(null, null); }) .Where(f => f.Item2 != null) .ToDictionary(f => f.Item1, f => f.Item2); var stack = MakeStack(); Info("Running Compilation Stack"); var results = AllFiles.PMap(f => RunStack(stack, f)).ToList(); // Add the extra files that were generated by the stack Info($"Adding {ExtraFiles.Count} that were generated by the stack"); results = results.Concat(ExtraFiles).ToList(); var nomatch = results.OfType <NoMatch>(); Info("No match for {0} files", nomatch.Count()); foreach (var file in nomatch) { Info(" {0}", file.To); } if (nomatch.Count() > 0) { if (IgnoreMissingFiles) { Info("Continuing even though files were missing at the request of the user."); } else { Info("Exiting due to no way to compile these files"); return; } } InstallDirectives = results.Where(i => !(i is IgnoredDirectly)).ToList(); Info("Getting nexus api_key please click authorize if a browser window appears"); NexusKey = NexusAPI.GetNexusAPIKey(); User = NexusAPI.GetUserStatus(NexusKey); if (!User.is_premium) { Info($"User {User.name} is not a premium Nexus user, cannot continue"); } GatherArchives(); BuildPatches(); ModList = new ModList() { Archives = SelectedArchives, Directives = InstallDirectives, Name = MO2Profile }; GenerateReport(); PatchExecutable(); ResetMembers(); ShowReport(); Info("Done Building Modpack"); }
public ModListVM(ModList sourceModList, string modListPath) { this.ModListPath = modListPath; this.SourceModList = sourceModList; this.ImageObservable = Observable.Return(this.ImageURL) .ObserveOn(RxApp.TaskpoolScheduler) .Select(url => { try { if (!File.Exists(url)) { return(default(MemoryStream)); } if (string.IsNullOrWhiteSpace(sourceModList.Image)) { return(default(MemoryStream)); } if (sourceModList.Image.Length != 36) { return(default(MemoryStream)); } using (var fs = new FileStream(this.ModListPath, FileMode.Open, FileAccess.Read, FileShare.Read)) using (var ar = new ZipArchive(fs, ZipArchiveMode.Read)) { var ms = new MemoryStream(); var entry = ar.GetEntry(sourceModList.Image); using (var e = entry.Open()) { e.CopyTo(ms); } return(ms); } } catch (Exception ex) { Utils.LogToFile($"Exception while caching Mod List image {this.Name}\n{ex.ExceptionToString()}"); return(default(MemoryStream)); } }) .ObserveOn(RxApp.MainThreadScheduler) .Select(memStream => { try { var image = new BitmapImage(); image.BeginInit(); image.CacheOption = BitmapCacheOption.OnLoad; image.StreamSource = memStream; image.EndInit(); image.Freeze(); return(image); } catch (Exception ex) { Utils.LogToFile($"Exception while caching Mod List image {this.Name}\n{ex.ExceptionToString()}"); return(default(BitmapImage)); } }) .Replay(1) .RefCount(); }
public Installer(string archive, ModList mod_list, string output_folder) { ModListArchive = archive; Outputfolder = output_folder; ModList = mod_list; }
public void Build(Compiler c, ModList lst) { Text($"### {lst.Name} by {lst.Author} - Installation Summary"); Text(lst.Description); Text($"#### Website:"); NoWrapText($"[{lst.Website}]({lst.Website})"); var readme_file = Path.Combine(c.MO2ProfileDir, "readme.md"); if (File.Exists(readme_file)) { File.ReadAllLines(readme_file) .Do(NoWrapText); } Text( $"#### Download Summary ({lst.Archives.Count} archives - {lst.Archives.Sum(a => a.Size).ToFileSizeString()})"); foreach (var archive in SortArchives(lst.Archives)) { var hash = archive.Hash.FromBase64().ToHEX(); NoWrapText(archive.State.GetReportEntry(archive)); NoWrapText($" * Size : {archive.Size.ToFileSizeString()}"); NoWrapText($" * SHA256 : [{hash}](https://www.virustotal.com/gui/file/{hash})"); } Text("\n\n"); var patched = lst.Directives.OfType <PatchedFromArchive>().OrderBy(p => p.To).ToList(); Text($"#### Summary of ({patched.Count}) patches"); foreach (var directive in patched) { NoWrapText( $"* Applying {SizeForID(directive.PatchID)} byte patch `{directive.FullPath}` to create `{directive.To}`"); } var files = lst.Directives.OrderBy(d => d.To).ToList(); Text($"\n\n### Install Plan of ({files.Count}) files"); Text("(ignoring files that are directly copied from archives or listed in the patches section above)"); foreach (var directive in files.OrderBy(f => f.GetType().Name).ThenByDescending(f => f.To)) { switch (directive) { case PropertyFile i: NoWrapText($"* `{i.SourceDataID}` as a `{Enum.GetName(typeof(PropertyType),i.Type)}`"); break; case FromArchive f: //NoWrapText($"* `{f.To}` from `{f.FullPath}`"); break; case CleanedESM i: NoWrapText($"* `{i.To}` by applying a patch to a game ESM ({i.SourceESMHash})"); break; case RemappedInlineFile i: NoWrapText($"* `{i.To}` by remapping the contents of an inline file"); break; case InlineFile i: NoWrapText($"* `{i.To}` from `{SizeForID(i.SourceDataID).ToFileSizeString()}` file included in modlist"); break; case CreateBSA i: NoWrapText( $"* `{i.To}` by creating a BSA of files found in `{Consts.BSACreationDir}\\{i.TempID}`"); break; } } var inlined = lst.Directives.OfType <InlineFile>() .Select(f => (f.To, "inlined", SizeForID(f.SourceDataID))) .Concat(lst.Directives .OfType <PatchedFromArchive>() .Select(f => (f.To, "patched", SizeForID(f.PatchID)))) .ToHashSet() .OrderByDescending(f => f.Item3); NoWrapText("\n\n### Summary of inlined files in this installer"); foreach (var inline in inlined) { NoWrapText($"* {inline.Item3.ToFileSizeString()} for {inline.Item2} file {inline.To}"); } }
public Installer(ModList mod_list, string output_folder) { Outputfolder = output_folder; ModList = mod_list; }