예제 #1
0
        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}");
            }
        }
예제 #2
0
 public Installer(ModList mod_list, string output_folder, Action <string> log_fn)
 {
     Outputfolder = output_folder;
     ModList      = mod_list;
     Log_Fn       = log_fn;
 }
예제 #3
0
        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;
                }
            }
        }
예제 #4
0
        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");
        }
예제 #5
0
        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");
        }
예제 #6
0
        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();
        }
예제 #7
0
 public Installer(string archive, ModList mod_list, string output_folder)
 {
     ModListArchive = archive;
     Outputfolder   = output_folder;
     ModList        = mod_list;
 }
예제 #8
0
        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}");
            }
        }
예제 #9
0
 public Installer(ModList mod_list, string output_folder)
 {
     Outputfolder = output_folder;
     ModList      = mod_list;
 }