コード例 #1
0
        //this should be private but no way to test it private for now...

        /// <summary>
        /// Inspects and loads compressed mods from an archive.
        /// </summary>
        /// <param name="filepath">Path of the archive</param>
        /// <param name="addCompressedModCallback">Callback indicating that the mod should be added to the collection of found mods</param>
        /// <param name="currentOperationTextCallback">Callback to tell caller what's going on'</param>
        /// <param name="forcedOverrideData">Override data about archive. Used for testing only</param>
        public static void InspectArchive(string filepath, Action <Mod> addCompressedModCallback = null, Action <Mod> failedToLoadModeCallback = null, Action <string> currentOperationTextCallback = null, string forcedMD5 = null, int forcedSize = -1)
        {
            string     relayVersionResponse = @"-1";
            List <Mod> internalModList      = new List <Mod>(); //internal mod list is for this function only so we don't need a callback to get our list since results are returned immediately
            var        isExe       = filepath.EndsWith(@".exe");
            var        archiveFile = isExe ? new SevenZipExtractor(filepath, InArchiveFormat.Nsis) : new SevenZipExtractor(filepath);

            using (archiveFile)
            {
#if DEBUG
                foreach (var v in archiveFile.ArchiveFileData)
                {
                    Debug.WriteLine($@"{v.FileName} | Index {v.Index} | Size {v.Size}");
                }
#endif
                var moddesciniEntries = new List <ArchiveFileInfo>();
                var sfarEntries       = new List <ArchiveFileInfo>(); //ME3 DLC
                var bioengineEntries  = new List <ArchiveFileInfo>(); //ME2 DLC
                var me2mods           = new List <ArchiveFileInfo>(); //ME2 RCW Mods
                foreach (var entry in archiveFile.ArchiveFileData)
                {
                    string fname = Path.GetFileName(entry.FileName);
                    if (!entry.IsDirectory && fname.Equals(@"moddesc.ini", StringComparison.InvariantCultureIgnoreCase))
                    {
                        moddesciniEntries.Add(entry);
                    }
                    else if (!entry.IsDirectory && fname.Equals(@"Default.sfar", StringComparison.InvariantCultureIgnoreCase))
                    {
                        //for unofficial lookups
                        sfarEntries.Add(entry);
                    }
                    else if (!entry.IsDirectory && fname.Equals(@"BIOEngine.ini", StringComparison.InvariantCultureIgnoreCase))
                    {
                        //for unofficial lookups
                        bioengineEntries.Add(entry);
                    }
                    else if (!entry.IsDirectory && Path.GetExtension(fname) == @".me2mod")
                    {
                        //for unofficial lookups
                        me2mods.Add(entry);
                    }
                }

                if (moddesciniEntries.Count > 0)
                {
                    foreach (var entry in moddesciniEntries)
                    {
                        currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_interp_readingX, entry.FileName));
                        Mod m = new Mod(entry, archiveFile);
                        if (m.ValidMod)
                        {
                            addCompressedModCallback?.Invoke(m);
                            internalModList.Add(m);
                        }
                        else
                        {
                            failedToLoadModeCallback?.Invoke(m);
                        }
                    }
                }
                else if (me2mods.Count > 0)
                {
                    //found some .me2mod files.
                    foreach (var entry in me2mods)
                    {
                        currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_interp_readingX, entry.FileName));
                        MemoryStream ms = new MemoryStream();
                        archiveFile.ExtractFile(entry.Index, ms);
                        ms.Position = 0;
                        StreamReader reader         = new StreamReader(ms);
                        string       text           = reader.ReadToEnd();
                        var          rcwModsForFile = RCWMod.ParseRCWMods(Path.GetFileNameWithoutExtension(entry.FileName), text);
                        foreach (var rcw in rcwModsForFile)
                        {
                            Mod m = new Mod(rcw);
                            addCompressedModCallback?.Invoke(m);
                            internalModList.Add(m);
                        }
                    }
                }
                else
                {
                    Log.Information(@"Querying third party importing service for information about this file");
                    currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_queryingThirdPartyImportingService));
                    var  md5  = forcedMD5 ?? Utilities.CalculateMD5(filepath);
                    long size = forcedSize > 0 ? forcedSize : new FileInfo(filepath).Length;
                    var  potentialImportinInfos = ThirdPartyServices.GetImportingInfosBySize(size);
                    var  importingInfo          = potentialImportinInfos.FirstOrDefault(x => x.md5 == md5);

                    if (importingInfo == null && isExe)
                    {
                        Log.Error(@"EXE-based mods must be validated by ME3Tweaks before they can be imported into M3. This is to prevent breaking third party mods.");
                        return;
                    }

                    if (importingInfo?.servermoddescname != null)
                    {
                        //Partially supported unofficial third party mod
                        //Mod has a custom written moddesc.ini stored on ME3Tweaks
                        Log.Information(@"Fetching premade moddesc.ini from ME3Tweaks for this mod archive");
                        string custommoddesc    = OnlineContent.FetchThirdPartyModdesc(importingInfo.servermoddescname);
                        Mod    virutalCustomMod = new Mod(custommoddesc, "", archiveFile); //Load virutal mod
                        if (virutalCustomMod.ValidMod)
                        {
                            addCompressedModCallback?.Invoke(virutalCustomMod);
                            internalModList.Add(virutalCustomMod);
                            return; //Don't do further parsing as this is custom written
                        }
                        else
                        {
                            Log.Error(@"Server moddesc was not valid for this mod. This shouldn't occur. Please report to Mgamerz.");
                            return;
                        }
                    }

                    ExeTransform transform = null;
                    if (importingInfo?.exetransform != null)
                    {
                        Log.Information(@"TPIS lists exe transform for this mod: " + importingInfo.exetransform);
                        transform = new ExeTransform(OnlineContent.FetchExeTransform(importingInfo.exetransform));
                    }

                    //Fully unofficial third party mod.

                    //ME3
                    foreach (var sfarEntry in sfarEntries)
                    {
                        var vMod = AttemptLoadVirtualMod(sfarEntry, archiveFile, Mod.MEGame.ME3, md5);
                        if (vMod.ValidMod)
                        {
                            addCompressedModCallback?.Invoke(vMod);
                            internalModList.Add(vMod);
                            vMod.ExeExtractionTransform = transform;
                        }
                    }

                    //TODO: ME2
                    //foreach (var entry in bioengineEntries)
                    //{
                    //    var vMod = AttemptLoadVirtualMod(entry, archiveFile, Mod.MEGame.ME2, md5);
                    //    if (vMod.ValidMod)
                    //    {
                    //        addCompressedModCallback?.Invoke(vMod);
                    //        internalModList.Add(vMod);
                    //    }
                    //}

                    //TODO: ME1

                    if (importingInfo?.version != null)
                    {
                        foreach (Mod compressedMod in internalModList)
                        {
                            compressedMod.ModVersionString = importingInfo.version;
                            Version.TryParse(importingInfo.version, out var parsedValue);
                            compressedMod.ParsedModVersion = parsedValue;
                        }
                    }
                    else if (relayVersionResponse == @"-1")
                    {
                        //If no version information, check ME3Tweaks to see if it's been added recently
                        //see if server has information on version number
                        currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_gettingAdditionalInformationAboutFileFromME3Tweaks));
                        Log.Information(@"Querying ME3Tweaks for additional information");
                        var modInfo = OnlineContent.QueryModRelay(md5, size);
                        //todo: make this work offline.
                        if (modInfo != null && modInfo.TryGetValue(@"version", out string value))
                        {
                            Log.Information(@"ME3Tweaks reports version number for this file is: " + value);
                            foreach (Mod compressedMod in internalModList)
                            {
                                compressedMod.ModVersionString = value;
                                Version.TryParse(value, out var parsedValue);
                                compressedMod.ParsedModVersion = parsedValue;
                            }
                            relayVersionResponse = value;
                        }
                        else
                        {
                            Log.Information(@"ME3Tweaks does not have additional version information for this file");
                            Analytics.TrackEvent("Non Mod Manager Mod Dropped", new Dictionary <string, string>()
                            {
                                { "Filename", Path.GetFileName(filepath) },
                                { "MD5", md5 }
                            });
                        }
                    }

                    else
                    {
                        //Try straight up TPMI import?
                        Log.Warning($@"No importing information is available for file with hash {md5}. No mods could be found.");
                        Analytics.TrackEvent("Non Mod Manager Mod Dropped", new Dictionary <string, string>()
                        {
                            { "Filename", Path.GetFileName(filepath) },
                            { "MD5", md5 }
                        });
                    }
                }
            }
        }
コード例 #2
0
        //this should be private but no way to test it private for now...

        /// <summary>
        /// Inspects and loads compressed mods from an archive.
        /// </summary>
        /// <param name="filepath">Path of the archive</param>
        /// <param name="addCompressedModCallback">Callback indicating that the mod should be added to the collection of found mods</param>
        /// <param name="currentOperationTextCallback">Callback to tell caller what's going on'</param>
        /// <param name="forcedOverrideData">Override data about archive. Used for testing only</param>
        public static void InspectArchive(string filepath, Action <Mod> addCompressedModCallback = null, Action <Mod> failedToLoadModeCallback = null, Action <string> currentOperationTextCallback = null,
                                          Action showALOTLauncher = null, string forcedMD5 = null, int forcedSize = -1)
        {
            string     relayVersionResponse = @"-1";
            List <Mod> internalModList      = new List <Mod>(); //internal mod list is for this function only so we don't need a callback to get our list since results are returned immediately
            var        isExe       = filepath.EndsWith(@".exe");
            var        archiveFile = isExe ? new SevenZipExtractor(filepath, InArchiveFormat.Nsis) : new SevenZipExtractor(filepath);

            using (archiveFile)
            {
#if DEBUG
                foreach (var v in archiveFile.ArchiveFileData)
                {
                    Debug.WriteLine($@"{v.FileName} | Index {v.Index} | Size {v.Size} | Last Modified {v.LastWriteTime}");
                }
#endif
                var  moddesciniEntries = new List <ArchiveFileInfo>();
                var  sfarEntries       = new List <ArchiveFileInfo>(); //ME3 DLC
                var  bioengineEntries  = new List <ArchiveFileInfo>(); //ME2 DLC
                var  me2mods           = new List <ArchiveFileInfo>(); //ME2 RCW Mods
                var  textureModEntries = new List <ArchiveFileInfo>(); //TPF MEM MOD files
                bool isAlotFile        = false;
                try
                {
                    foreach (var entry in archiveFile.ArchiveFileData)
                    {
                        if (!entry.IsDirectory)
                        {
                            string fname = Path.GetFileName(entry.FileName);
                            if (fname.Equals(@"ALOTInstaller.exe", StringComparison.InvariantCultureIgnoreCase))
                            {
                                isAlotFile = true;
                            }
                            else if (fname.Equals(@"moddesc.ini", StringComparison.InvariantCultureIgnoreCase))
                            {
                                moddesciniEntries.Add(entry);
                            }
                            else if (fname.Equals(@"Default.sfar", StringComparison.InvariantCultureIgnoreCase))
                            {
                                //for unofficial lookups
                                sfarEntries.Add(entry);
                            }
                            else if (fname.Equals(@"BIOEngine.ini", StringComparison.InvariantCultureIgnoreCase))
                            {
                                //for unofficial lookups
                                bioengineEntries.Add(entry);
                            }
                            else if (Path.GetExtension(fname) == @".me2mod")
                            {
                                me2mods.Add(entry);
                            }
                            else if (Path.GetExtension(fname) == @".mem" || Path.GetExtension(fname) == @".tpf" || Path.GetExtension(fname) == @".mod")
                            {
                                //for forwarding to ALOT Installer
                                textureModEntries.Add(entry);
                            }
                        }
                    }
                }
                catch (SevenZipArchiveException svae)
                {
                    //error reading archive!
                    Mod failed = new Mod(false);
                    failed.ModName          = M3L.GetString(M3L.string_archiveError);
                    failed.LoadFailedReason = M3L.GetString(M3L.string_couldNotInspectArchive7zException);
                    Log.Error($@"Unable to inspect archive {filepath}: SevenZipException occurred! It may be corrupt. The specific error was: {svae.Message}");
                    failedToLoadModeCallback?.Invoke(failed);
                    addCompressedModCallback?.Invoke(failed);
                    return;
                }

                // Used for TPIS information lookup
                long archiveSize = forcedSize > 0 ? forcedSize : new FileInfo(filepath).Length;

                if (moddesciniEntries.Count > 0)
                {
                    foreach (var entry in moddesciniEntries)
                    {
                        currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_interp_readingX, entry.FileName));
                        Mod m = new Mod(entry, archiveFile);
                        if (!m.ValidMod)
                        {
                            failedToLoadModeCallback?.Invoke(m);
                            m.SelectedForImport = false;
                        }

                        addCompressedModCallback?.Invoke(m);
                        internalModList.Add(m);
                    }
                }
                else if (me2mods.Count > 0)
                {
                    //found some .me2mod files.
                    foreach (var entry in me2mods)
                    {
                        currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_interp_readingX, entry.FileName));
                        MemoryStream ms = new MemoryStream();
                        archiveFile.ExtractFile(entry.Index, ms);
                        ms.Position = 0;
                        StreamReader reader         = new StreamReader(ms);
                        string       text           = reader.ReadToEnd();
                        var          rcwModsForFile = RCWMod.ParseRCWMods(Path.GetFileNameWithoutExtension(entry.FileName), text);
                        foreach (var rcw in rcwModsForFile)
                        {
                            Mod m = new Mod(rcw);
                            addCompressedModCallback?.Invoke(m);
                            internalModList.Add(m);
                        }
                    }
                }
                else if (textureModEntries.Any() && isAlotFile)
                {
                    if (isAlotFile)
                    {
                        //is alot installer
                        Log.Information(@"This file contains texture files and ALOTInstaller.exe - this is an ALOT main file");
                        var textureLibraryPath = Utilities.GetALOTInstallerTextureLibraryDirectory();
                        if (textureLibraryPath != null)
                        {
                            //we have destination
                            var destPath = Path.Combine(textureLibraryPath, Path.GetFileName(filepath));
                            if (!File.Exists(destPath))
                            {
                                Log.Information(M3L.GetString(M3L.string_thisFileIsNotInTheTextureLibraryMovingItToTheTextureLibrary));
                                currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_movingALOTFileToTextureLibraryPleaseWait));
                                archiveFile.Dispose();
                                File.Move(filepath, destPath, true);
                                showALOTLauncher?.Invoke();
                            }
                        }
                    }
                    //todo: Parse
                    //else
                    //{
                    //    //found some texture-mod only files
                    //    foreach (var entry in textureModEntries)
                    //    {
                    //        currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_interp_readingX, entry.FileName));
                    //        MemoryStream ms = new MemoryStream();
                    //        archiveFile.ExtractFile(entry.Index, ms);
                    //        ms.Position = 0;
                    //        StreamReader reader = new StreamReader(ms);
                    //        string text = reader.ReadToEnd();
                    //        var rcwModsForFile = RCWMod.ParseRCWMods(Path.GetFileNameWithoutExtension(entry.FileName), text);
                    //        foreach (var rcw in rcwModsForFile)
                    //        {
                    //            Mod m = new Mod(rcw);
                    //            addCompressedModCallback?.Invoke(m);
                    //            internalModList.Add(m);
                    //        }
                    //    }
                    //}
                }
                else
                {
                    Log.Information(@"Querying third party importing service for information about this file: " + filepath);
                    currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_queryingThirdPartyImportingService));
                    var md5 = forcedMD5 ?? Utilities.CalculateMD5(filepath);
                    var potentialImportinInfos = ThirdPartyServices.GetImportingInfosBySize(archiveSize);
                    var importingInfo          = potentialImportinInfos.FirstOrDefault(x => x.md5 == md5);

                    if (importingInfo == null && isExe)
                    {
                        Log.Error(@"EXE-based mods must be validated by ME3Tweaks before they can be imported into M3. This is to prevent breaking third party mods.");
                        return;
                    }

                    if (importingInfo?.servermoddescname != null)
                    {
                        //Partially supported unofficial third party mod
                        //Mod has a custom written moddesc.ini stored on ME3Tweaks
                        Log.Information(@"Fetching premade moddesc.ini from ME3Tweaks for this mod archive");
                        string custommoddesc    = null;
                        string loadFailedReason = null;
                        try
                        {
                            custommoddesc = OnlineContent.FetchThirdPartyModdesc(importingInfo.servermoddescname);
                        }
                        catch (Exception e)
                        {
                            loadFailedReason = e.Message;
                            Log.Error(@"Error fetching moddesc from server: " + e.Message);
                        }

                        Mod virutalCustomMod = new Mod(custommoddesc, "", archiveFile); //Load virutal mod
                        if (virutalCustomMod.ValidMod)
                        {
                            Log.Information(@"Mod loaded from server moddesc.");
                            addCompressedModCallback?.Invoke(virutalCustomMod);
                            internalModList.Add(virutalCustomMod);
                            return; //Don't do further parsing as this is custom written
                        }
                        else
                        {
                            if (loadFailedReason != null)
                            {
                                virutalCustomMod.LoadFailedReason = M3L.GetString(M3L.string_interp_failedToFetchModdesciniFileFromServerReasonLoadFailedReason, loadFailedReason);
                            }
                            else
                            {
                                Log.Error(@"Server moddesc was not valid for this mod. This shouldn't occur. Please report to Mgamerz.");
                            }
                            return;
                        }
                    }

                    ExeTransform transform = null;
                    if (importingInfo?.exetransform != null)
                    {
                        Log.Information(@"TPIS lists exe transform for this mod: " + importingInfo.exetransform);
                        transform = new ExeTransform(OnlineContent.FetchExeTransform(importingInfo.exetransform));
                    }

                    //Fully unofficial third party mod.

                    //ME3
                    foreach (var sfarEntry in sfarEntries)
                    {
                        var vMod = AttemptLoadVirtualMod(sfarEntry, archiveFile, Mod.MEGame.ME3, md5);
                        if (vMod != null)
                        {
                            addCompressedModCallback?.Invoke(vMod);
                            internalModList.Add(vMod);
                            vMod.ExeExtractionTransform = transform;
                        }
                    }

                    //TODO: ME2 ?
                    //foreach (var entry in bioengineEntries)
                    //{
                    //    var vMod = AttemptLoadVirtualMod(entry, archiveFile, Mod.MEGame.ME2, md5);
                    //    if (vMod.ValidMod)
                    //    {
                    //        addCompressedModCallback?.Invoke(vMod);
                    //        internalModList.Add(vMod);
                    //    }
                    //}

                    //TODO: ME1 ?

                    if (importingInfo?.version != null)
                    {
                        foreach (Mod compressedMod in internalModList)
                        {
                            compressedMod.ModVersionString = importingInfo.version;
                            Version.TryParse(importingInfo.version, out var parsedValue);
                            compressedMod.ParsedModVersion = parsedValue;
                        }
                    }
                    else if (relayVersionResponse == @"-1")
                    {
                        //If no version information, check ME3Tweaks to see if it's been added recently
                        //see if server has information on version number
                        currentOperationTextCallback?.Invoke(M3L.GetString(M3L.string_gettingAdditionalInformationAboutFileFromME3Tweaks));
                        Log.Information(@"Querying ME3Tweaks for additional information for this file...");
                        var modInfo = OnlineContent.QueryModRelay(md5, archiveSize);
                        //todo: make this work offline.
                        if (modInfo != null && modInfo.TryGetValue(@"version", out string value))
                        {
                            Log.Information(@"ME3Tweaks reports version number for this file is: " + value);
                            foreach (Mod compressedMod in internalModList)
                            {
                                compressedMod.ModVersionString = value;
                                Version.TryParse(value, out var parsedValue);
                                compressedMod.ParsedModVersion = parsedValue;
                            }
                            relayVersionResponse = value;
                        }
                        else
                        {
                            Log.Information(@"ME3Tweaks does not have additional version information for this file.");
                            Analytics.TrackEvent(@"Non Mod Manager Mod Dropped", new Dictionary <string, string>()
                            {
                                { @"Filename", Path.GetFileName(filepath) },
                                { @"MD5", md5 }
                            });
                            foreach (Mod compressedMod in internalModList)
                            {
                                compressedMod.ModVersionString = M3L.GetString(M3L.string_unknown);
                            }
                        }
                    }

                    else
                    {
                        //Try straight up TPMI import?
                        Log.Warning($@"No importing information is available for file with hash {md5}. No mods could be found.");
                        Analytics.TrackEvent(@"Non Mod Manager Mod Dropped", new Dictionary <string, string>()
                        {
                            { @"Filename", Path.GetFileName(filepath) },
                            { @"MD5", md5 }
                        });
                    }
                }
            }
        }
コード例 #3
0
        private void InspectArchiveBackgroundThread(object sender, DoWorkEventArgs e)
        {
            TaskRunning = true;
            ActionText  = M3L.GetString(M3L.string_interp_openingX, ScanningFile);

            var archive = e.Argument as string;

            void AddCompressedModCallback(Mod m)
            {
                Application.Current.Dispatcher.Invoke(delegate
                {
                    CompressedMods.Add(m);
                    if (CompressedMods.Count > 1 && !openedMultipanel)
                    {
                        Storyboard sb = FindResource(@"OpenWebsitePanel") as Storyboard;
                        if (sb.IsSealed)
                        {
                            sb = sb.Clone();
                        }
                        Storyboard.SetTarget(sb, MultipleModsPopupPanel);
                        sb.Begin();
                        openedMultipanel = true;
                    }
                    CompressedMods.Sort(x => x.ModName);
                });
            }

            void CompressedModFailedCallback(Mod m)
            {
                Application.Current.Dispatcher.Invoke(delegate { NoModSelectedText += M3L.GetString(M3L.string_interp_XfailedToLoadY, m.ModName, m.LoadFailedReason); });
            }

            if (Path.GetExtension(archive) == @".me2mod")
            {
                //RCW
                var RCWMods = RCWMod.ParseRCWMods(Path.GetFileNameWithoutExtension(archive), File.ReadAllText(archive));
                foreach (var rcw in RCWMods)
                {
                    AddCompressedModCallback(new Mod(rcw));
                }
                return;
            }
            //Embedded executables.
            var    archiveSize         = new FileInfo(archive).Length;
            var    knownModsOfThisSize = ThirdPartyServices.GetImportingInfosBySize(archiveSize);
            string pathOverride        = null;

            if (knownModsOfThisSize.Count > 0 && knownModsOfThisSize.Any(x => x.zippedexepath != null))
            {
                //might have embedded exe
                if (archive.RepresentsFileArchive())
                {
                    SevenZipExtractor sve             = new SevenZipExtractor(archive);
                    string            embeddedExePath = null;
                    Log.Information(@"This file may contain a known exe-based mod.");
                    foreach (var importingInfo in knownModsOfThisSize)
                    {
                        if (importingInfo.zippedexepath == null)
                        {
                            continue;
                        }
                        if (sve.ArchiveFileNames.Contains(importingInfo.zippedexepath))
                        {
                            embeddedExePath = importingInfo.zippedexepath;
                            //Ensure embedded exe is supported at least by decompressed size
                            var exedata = sve.ArchiveFileData.FirstOrDefault(x => x.FileName == embeddedExePath);
                            if (exedata.FileName != null)
                            {
                                var importingInfo2 = ThirdPartyServices.GetImportingInfosBySize((long)exedata.Size);
                                if (importingInfo2.Count == 0)
                                {
                                    Log.Warning(@"zip wrapper for this file has importing information but the embedded exe does not!");
                                    break; //no importing info
                                }

                                Log.Information(@"Reading embedded executable file in archive: " + embeddedExePath);
                                ActionText          = M3L.GetString(M3L.string_readingZippedExecutable);
                                pathOverride        = Path.Combine(Utilities.GetTempPath(), Path.GetFileName(embeddedExePath));
                                using var outstream = new FileStream(pathOverride, FileMode.Create);
                                sve.Extracting     += (o, pea) => { ActionText = $@"{M3L.GetString(M3L.string_readingZippedExecutable)} {pea.PercentDone}%"; };
                                sve.ExtractFile(embeddedExePath, outstream);
                                ArchiveFilePath = pathOverride; //set new path so further extraction calls use correct archive path.
                                break;
                            }
                        }
                    }
                }
            }


            void ActionTextUpdateCallback(string newText)
            {
                ActionText = newText;
            }

            InspectArchive(pathOverride ?? archive, AddCompressedModCallback, CompressedModFailedCallback, ActionTextUpdateCallback);
        }
コード例 #4
0
        private ModInstallCompletedStatus InstallAttachedRCWMod()
        {
            CLog.Information(@"Installing attached RCW mod. Checking Coalesced.ini first to make sure this mod can be safely applied", Settings.LogModInstallation);
            ME2Coalesced me2c = new ME2Coalesced(ME2Directory.CoalescedPath(gameTarget));
            RCWMod       rcw  = ModBeingInstalled.GetJob(ModJob.JobHeader.ME2_RCWMOD).RCW;

            foreach (var rcwF in rcw.Files)
            {
                var me2cF = me2c.Inis.FirstOrDefault(x => x.Key == rcwF.FileName);
                if (me2cF.Key == null)
                {
                    Log.Error(@"RCW mod specifies a file in coalesced that does not exist in the local one: " + rcwF);
                    return(ModInstallCompletedStatus.INSTALL_FAILED_MALFORMED_RCW_FILE);
                }

                foreach (var rcwS in rcwF.Sections)
                {
                    var section = me2cF.Value.Sections.FirstOrDefault(x => x.Header == rcwS.SectionName);
                    if (section == null)
                    {
                        Log.Error($@"RCW mod specifies a section in {rcwF.FileName} that does not exist in the local coalesced: {rcwS.SectionName}");
                        return(ModInstallCompletedStatus.INSTALL_FAILED_MALFORMED_RCW_FILE);
                    }
                }


                //Apply mod
                foreach (var rcwS in rcwF.Sections)
                {
                    var section = me2cF.Value.Sections.FirstOrDefault(x => x.Header == rcwS.SectionName);
                    Dictionary <string, int> keyCount = new Dictionary <string, int>();
                    foreach (var key in section.Entries)
                    {
                        if (keyCount.TryGetValue(key.Key, out var existingCount))
                        {
                            keyCount[key.Key] = existingCount + 1;
                        }
                        else
                        {
                            keyCount[key.Key] = 1;
                        }
                    }

                    Dictionary <string, bool> keysSupportingMulti = keyCount.ToDictionary(x => x.Key, x => x.Value > 1);

                    //Remove items
                    foreach (var itemToDelete in rcwS.KeysToDelete)
                    {
                        for (int i = section.Entries.Count - 1; i > 0; i--)
                        {
                            var entry = section.Entries[i];
                            if (entry.Key == itemToDelete.Key && entry.Value == itemToDelete.Value)
                            {
                                CLog.Information($@"Removing ini entry {entry.RawText} in section {section.Header} of file {me2cF.Key}", Settings.LogModInstallation);
                                section.Entries.RemoveAt(i);
                            }
                        }
                    }

                    foreach (var itemToAdd in rcwS.KeysToAdd)
                    {
                        var existingEntries = section.Entries.Where(x => x.Key == itemToAdd.Key).ToList();
                        if (existingEntries.Count <= 0)
                        {
                            //just add it
                            CLog.Information($@"Adding ini entry {itemToAdd.RawText} in section {section.Header} of file {me2cF.Key}", Settings.LogModInstallation);
                            section.Entries.Add(itemToAdd);
                        }
                        else if (existingEntries.Count > 1)
                        {
                            //Supports multi. Add this key - but making sure the data doesn't already exist!
                            if (existingEntries.Any(x => x.Value == itemToAdd.Value))
                            {
                                //Duplicate.
                                CLog.Information($@"Not adding duplicate ini entry {itemToAdd.RawText} in section {section.Header} of file {me2cF.Key}", Settings.LogModInstallation);
                            }
                            else
                            {
                                //Not duplicate - installing key
                                CLog.Information($@"Adding ini entry {itemToAdd.RawText} in section {section.Header} of file {me2cF.Key}", Settings.LogModInstallation);
                                section.Entries.Add(itemToAdd);
                            }
                        }
                        else
                        {
                            //Only one key exists currently. We need to check multi lookup to choose how to install
                            if (keysSupportingMulti[itemToAdd.Key])
                            {
                                //Supports multi. Add this key - but making sure the data doesn't already exist!
                                if (existingEntries.Any(x => x.Value == itemToAdd.Value))
                                {
                                    //Duplicate.
                                    CLog.Information($@"Not adding duplicate ini entry {itemToAdd.RawText} in section {section.Header} of file {me2cF.Key}", Settings.LogModInstallation);
                                }
                                else
                                {
                                    //Not duplicate - installing key
                                    CLog.Information($@"Adding ini entry {itemToAdd.RawText} in section {section.Header} of file {me2cF.Key}", Settings.LogModInstallation);
                                    section.Entries.Add(itemToAdd);
                                }
                            }
                            else
                            {
                                //Replace existing key
                                existingEntries[0].Value = itemToAdd.Value;
                            }
                        }
                    }
                }
            }
            me2c.Serialize();
            return(ModInstallCompletedStatus.INSTALL_SUCCESSFUL);
        }