예제 #1
0
        public static IEnumerable <string> GenerateModList(IEnumerable <ModAddedByAssembly> modsAddedByAssemblies, IPatchProgress progress, IBasicLogger logger)
        {
            #region List of mods

            //string envInfo = "ModuleManager env info\n";
            //envInfo += "  " + Environment.OSVersion.Platform + " " + ModuleManager.intPtr.ToInt64().ToString("X16") + "\n";
            //envInfo += "  " + Convert.ToString(ModuleManager.intPtr.ToInt64(), 2)  + " " + Convert.ToString(ModuleManager.intPtr.ToInt64() >> 63, 2) + "\n";
            //string gamePath = Environment.GetCommandLineArgs()[0];
            //envInfo += "  Args: " + gamePath.Split(Path.DirectorySeparatorChar).Last() + " " + string.Join(" ", Environment.GetCommandLineArgs().Skip(1).ToArray()) + "\n";
            //envInfo += "  Executable SHA256 " + FileSHA(gamePath);
            //
            //log(envInfo);

            List <string> mods = new List <string>();

            StringBuilder modListInfo = new StringBuilder();

            modListInfo.Append("compiling list of loaded mods...\nMod DLLs found:\n");

            string format = "  {0,-40}{1,-25}{2,-25}{3,-25}{4}\n";

            modListInfo.AppendFormat(
                format,
                "Name",
                "Assembly Version",
                "Assembly File Version",
                "KSPAssembly Version",
                "SHA256"
                );

            modListInfo.Append('\n');

            foreach (AssemblyLoader.LoadedAssembly mod in AssemblyLoader.loadedAssemblies)
            {
                if (string.IsNullOrEmpty(mod.assembly.Location)) //Diazo Edit for xEvilReeperx AssemblyReloader mod
                {
                    continue;
                }

                FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(mod.assembly.Location);

                AssemblyName assemblyName = mod.assembly.GetName();

                string kspAssemblyVersion;
                if (mod.versionMajor == 0 && mod.versionMinor == 0)
                {
                    kspAssemblyVersion = "";
                }
                else
                {
                    kspAssemblyVersion = mod.versionMajor + "." + mod.versionMinor;
                }

                string fileSha = "";
                try
                {
                    fileSha = FileUtils.FileSHA(mod.assembly.Location);
                }
                catch (Exception e)
                {
                    progress.Exception("Exception while generating SHA for assembly " + assemblyName.Name, e);
                }

                modListInfo.AppendFormat(
                    format,
                    assemblyName.Name,
                    assemblyName.Version,
                    fileVersionInfo.FileVersion,
                    kspAssemblyVersion,
                    fileSha
                    );

                // modlist += String.Format("  {0,-50} SHA256 {1}\n", modInfo, FileSHA(mod.assembly.Location));

                if (!mods.Contains(assemblyName.Name, StringComparer.OrdinalIgnoreCase))
                {
                    mods.Add(assemblyName.Name);
                }
            }

            modListInfo.Append("Non-DLL mods added (:FOR[xxx]):\n");
            foreach (UrlDir.UrlConfig cfgmod in GameDatabase.Instance.root.AllConfigs)
            {
                if (CommandParser.Parse(cfgmod.type, out string name) != Command.Insert)
                {
                    if (name.Contains(":FOR["))
                    {
                        name = name.RemoveWS();

                        // check for FOR[] blocks that don't match loaded DLLs and add them to the pass list
                        try
                        {
                            string dependency = name.Substring(name.IndexOf(":FOR[") + 5);
                            dependency = dependency.Substring(0, dependency.IndexOf(']'));
                            if (!mods.Contains(dependency, StringComparer.OrdinalIgnoreCase))
                            {
                                // found one, now add it to the list.
                                mods.Add(dependency);
                                modListInfo.AppendFormat("  {0}\n", dependency);
                            }
                        }
                        catch (ArgumentOutOfRangeException)
                        {
                            progress.Error(cfgmod, "Skipping :FOR init for line " + name +
                                           ". The line most likely contains a space that should be removed");
                        }
                    }
                }
            }
            modListInfo.Append("Mods by directory (sub directories of GameData):\n");
            UrlDir gameData = GameDatabase.Instance.root.children.First(dir => dir.type == UrlDir.DirectoryType.GameData);
            foreach (UrlDir subDir in gameData.children)
            {
                string cleanName = subDir.name.RemoveWS();
                if (!mods.Contains(cleanName, StringComparer.OrdinalIgnoreCase))
                {
                    mods.Add(cleanName);
                    modListInfo.AppendFormat("  {0}\n", cleanName);
                }
            }

            modListInfo.Append("Mods added by assemblies:\n");
            foreach (ModAddedByAssembly mod in modsAddedByAssemblies)
            {
                if (!mods.Contains(mod.modName, StringComparer.OrdinalIgnoreCase))
                {
                    mods.Add(mod.modName);
                    modListInfo.AppendFormat("  {0}\n", mod);
                }
            }

            logger.Info(modListInfo.ToString());

            mods.Sort();

            #endregion List of mods

            return(mods);
        }
예제 #2
0
        public static PatchList SortAndExtractPatches(UrlDir databaseRoot, IEnumerable <string> modList, IPatchProgress progress)
        {
            PatchList list = new PatchList(modList);

            // Have to convert to an array because we will be removing patches
            foreach (UrlDir.UrlConfig url in databaseRoot.AllConfigs.ToArray())
            {
                try
                {
                    if (!url.type.IsBracketBalanced())
                    {
                        progress.Error(url, "Error - node name does not have balanced brackets (or a space - if so replace with ?):\n" + url.SafeUrl());
                        url.parent.configs.Remove(url);
                        continue;
                    }

                    Command command = CommandParser.Parse(url.type, out _);;

                    Match firstMatch  = firstRegex.Match(url.type);
                    Match finalMatch  = finalRegex.Match(url.type);
                    Match beforeMatch = beforeRegex.Match(url.type);
                    Match forMatch    = forRegex.Match(url.type);
                    Match afterMatch  = afterRegex.Match(url.type);

                    int matchCount = 0;

                    if (firstMatch.Success)
                    {
                        matchCount++;
                    }
                    if (finalMatch.Success)
                    {
                        matchCount++;
                    }
                    if (beforeMatch.Success)
                    {
                        matchCount++;
                    }
                    if (forMatch.Success)
                    {
                        matchCount++;
                    }
                    if (afterMatch.Success)
                    {
                        matchCount++;
                    }

                    if (firstMatch.NextMatch().Success)
                    {
                        matchCount++;
                    }
                    if (finalMatch.NextMatch().Success)
                    {
                        matchCount++;
                    }
                    if (beforeMatch.NextMatch().Success)
                    {
                        matchCount++;
                    }
                    if (forMatch.NextMatch().Success)
                    {
                        matchCount++;
                    }
                    if (afterMatch.NextMatch().Success)
                    {
                        matchCount++;
                    }

                    bool error = false;

                    if (command == Command.Insert && matchCount > 0)
                    {
                        progress.Error(url, $"Error - pass specifier detected on an insert node (not a patch): {url.SafeUrl()}");
                        error = true;
                    }
                    else if (command == Command.Replace)
                    {
                        progress.Error(url, $"Error - replace command (%) is not valid on a root node: {url.SafeUrl()}");
                        error = true;
                    }
                    else if (command == Command.Create)
                    {
                        progress.Error(url, $"Error - create command (&) is not valid on a root node: {url.SafeUrl()}");
                        error = true;
                    }
                    else if (command == Command.Rename)
                    {
                        progress.Error(url, $"Error - rename command (|) is not valid on a root node: {url.SafeUrl()}");
                        error = true;
                    }
                    else if (command == Command.Paste)
                    {
                        progress.Error(url, $"Error - paste command (#) is not valid on a root node: {url.SafeUrl()}");
                        error = true;
                    }
                    else if (command == Command.Special)
                    {
                        progress.Error(url, $"Error - special command (*) is not valid on a root node: {url.SafeUrl()}");
                        error = true;
                    }

                    if (matchCount > 1)
                    {
                        progress.Error(url, $"Error - more than one pass specifier on a node: {url.SafeUrl()}");
                        error = true;
                    }
                    if (beforeMatch.Success && !beforeMatch.Groups[1].Success)
                    {
                        progress.Error(url, "Error - malformed :BEFORE patch specifier detected: " + url.SafeUrl());
                        error = true;
                    }
                    if (forMatch.Success && !forMatch.Groups[1].Success)
                    {
                        progress.Error(url, "Error - malformed :FOR patch specifier detected: " + url.SafeUrl());
                        error = true;
                    }
                    if (afterMatch.Success && !afterMatch.Groups[1].Success)
                    {
                        progress.Error(url, "Error - malformed :AFTER patch specifier detected: " + url.SafeUrl());
                        error = true;
                    }
                    if (error)
                    {
                        url.parent.configs.Remove(url);
                        continue;
                    }

                    if (command == Command.Insert)
                    {
                        continue;
                    }

                    url.parent.configs.Remove(url);

                    Match theMatch = null;
                    List <UrlDir.UrlConfig> thePass = null;
                    bool modNotFound = false;

                    if (firstMatch.Success)
                    {
                        theMatch = firstMatch;
                        thePass  = list.firstPatches;
                    }
                    else if (finalMatch.Success)
                    {
                        theMatch = finalMatch;
                        thePass  = list.finalPatches;
                    }
                    else if (beforeMatch.Success)
                    {
                        if (CheckMod(beforeMatch, list.modPasses, out string theMod))
                        {
                            theMatch = beforeMatch;
                            thePass  = list.modPasses[theMod].beforePatches;
                        }
                        else
                        {
                            modNotFound = true;
                            progress.NeedsUnsatisfiedBefore(url);
                        }
                    }
                    else if (forMatch.Success)
                    {
                        if (CheckMod(forMatch, list.modPasses, out string theMod))
                        {
                            theMatch = forMatch;
                            thePass  = list.modPasses[theMod].forPatches;
                        }
                        else
                        {
                            modNotFound = true;
                            progress.NeedsUnsatisfiedFor(url);
                        }
                    }
                    else if (afterMatch.Success)
                    {
                        if (CheckMod(afterMatch, list.modPasses, out string theMod))
                        {
                            theMatch = afterMatch;
                            thePass  = list.modPasses[theMod].afterPatches;
                        }
                        else
                        {
                            modNotFound = true;
                            progress.NeedsUnsatisfiedAfter(url);
                        }
                    }
                    else
                    {
                        thePass = list.legacyPatches;
                    }

                    if (modNotFound)
                    {
                        continue;
                    }

                    UrlDir.UrlConfig newUrl = url;
                    if (theMatch != null)
                    {
                        string     newName = url.type.Remove(theMatch.Index, theMatch.Length);
                        ConfigNode newNode = new ConfigNode(newName)
                        {
                            id = url.config.id
                        };
                        newNode.ShallowCopyFrom(url.config);
                        newUrl = new UrlDir.UrlConfig(url.parent, newNode);
                    }

                    thePass.Add(newUrl);
                    progress.PatchAdded();
                }
                catch (Exception e)
                {
                    progress.Exception(url, $"Exception while parsing pass for config: {url.SafeUrl()}", e);
                }
            }

            return(list);
        }
예제 #3
0
        public IPatch ExtractPatch(UrlDir.UrlConfig urlConfig)
        {
            if (urlConfig == null)
            {
                throw new ArgumentNullException(nameof(urlConfig));
            }

            try
            {
                if (!urlConfig.type.IsBracketBalanced())
                {
                    progress.Error(urlConfig, "Error - node name does not have balanced brackets (or a space - if so replace with ?):\n" + urlConfig.SafeUrl());
                    return(null);
                }

                Command command = CommandParser.Parse(urlConfig.type, out string name);

                if (command == Command.Replace)
                {
                    progress.Error(urlConfig, $"Error - replace command (%) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Create)
                {
                    progress.Error(urlConfig, $"Error - create command (&) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Rename)
                {
                    progress.Error(urlConfig, $"Error - rename command (|) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Paste)
                {
                    progress.Error(urlConfig, $"Error - paste command (#) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }
                else if (command == Command.Special)
                {
                    progress.Error(urlConfig, $"Error - special command (*) is not valid on a root node: {urlConfig.SafeUrl()}");
                    return(null);
                }

                ITagList tagList;
                try
                {
                    tagList = tagListParser.Parse(name, urlConfig);
                }
                catch (FormatException ex)
                {
                    progress.Error(urlConfig, $"Cannot parse node name as tag list: {ex.Message}\non: {urlConfig.SafeUrl()}");
                    return(null);
                }

                ProtoPatch protoPatch = protoPatchBuilder.Build(urlConfig, command, tagList);

                if (protoPatch == null)
                {
                    return(null);
                }

                if (protoPatch.needs != null && !needsChecker.CheckNeedsExpression(protoPatch.needs))
                {
                    progress.NeedsUnsatisfiedRoot(urlConfig);
                    return(null);
                }
                else if (!protoPatch.passSpecifier.CheckNeeds(needsChecker, progress))
                {
                    return(null);
                }

                needsChecker.CheckNeedsRecursive(urlConfig.config, urlConfig);
                return(patchCompiler.CompilePatch(protoPatch));
            }
            catch (Exception e)
            {
                progress.Exception(urlConfig, $"Exception while attempting to create patch from config: {urlConfig.SafeUrl()}", e);
                return(null);
            }
        }