Exemple #1
0
        private static void CheckNeeds(NodeStack stack, PatchContext context, IEnumerable <string> mods, UrlDir gameData)
        {
            ConfigNode original = stack.value;

            for (int i = 0; i < original.values.Count; ++i)
            {
                ConfigNode.Value val     = original.values[i];
                string           valname = val.name;
                try
                {
                    if (CheckNeeds(ref valname, mods, gameData))
                    {
                        val.name = valname;
                    }
                    else
                    {
                        original.values.Remove(val);
                        i--;
                        context.progress.NeedsUnsatisfiedValue(context.patchUrl, stack, val.name);
                    }
                }
                catch (ArgumentOutOfRangeException e)
                {
                    context.progress.Exception("ArgumentOutOfRangeException in CheckNeeds for value \"" + val.name + "\"", e);
                    throw;
                }
                catch (Exception e)
                {
                    context.progress.Exception("General Exception in CheckNeeds for value \"" + val.name + "\"", e);
                    throw;
                }
            }

            for (int i = 0; i < original.nodes.Count; ++i)
            {
                ConfigNode node     = original.nodes[i];
                string     nodeName = node.name;

                if (nodeName == null)
                {
                    context.progress.Error(context.patchUrl, "Error - Node in file " + context.patchUrl.SafeUrl() + " subnode: " + stack.GetPath() +
                                           " has config.name == null");
                }

                try
                {
                    if (CheckNeeds(ref nodeName, mods, gameData))
                    {
                        node.name = nodeName;
                        CheckNeeds(stack.Push(node), context, mods, gameData);
                    }
                    else
                    {
                        original.nodes.Remove(node);
                        i--;
                        context.progress.NeedsUnsatisfiedNode(context.patchUrl, stack.Push(node));
                    }
                }
                catch (ArgumentOutOfRangeException e)
                {
                    context.progress.Exception("ArgumentOutOfRangeException in CheckNeeds for node \"" + node.name + "\"", e);
                    throw;
                }
                catch (Exception e)
                {
                    context.progress.Exception("General Exception " + e.GetType().Name + " for node \"" + node.name + "\"", e);
                    throw;
                }
            }
        }
Exemple #2
0
        private void ApplyPatches(string stage, IEnumerable <UrlDir.UrlConfig> patches)
        {
            logger.Info(stage + " pass");
            Activity = "ModuleManager " + stage;

            foreach (UrlDir.UrlConfig mod in patches)
            {
                try
                {
                    string  name = mod.type.RemoveWS();
                    Command cmd  = CommandParser.Parse(name, out string tmp);

                    if (cmd == Command.Insert)
                    {
                        logger.Warning("Warning - Encountered insert node that should not exist at this stage: " + mod.SafeUrl());
                        continue;
                    }
                    else if (cmd != Command.Edit && cmd != Command.Copy && cmd != Command.Delete)
                    {
                        logger.Warning("Invalid command encountered on a patch: " + mod.SafeUrl());
                        continue;
                    }

                    string       upperName = name.ToUpper();
                    PatchContext context   = new PatchContext(mod, databaseRoot, logger, progress);
                    char[]       sep       = { '[', ']' };
                    string       condition = "";

                    if (upperName.Contains(":HAS["))
                    {
                        int start = upperName.IndexOf(":HAS[");
                        condition = name.Substring(start + 5, name.LastIndexOf(']') - start - 5);
                        name      = name.Substring(0, start);
                    }

                    string[] splits   = name.Split(sep, 3);
                    string[] patterns = splits.Length > 1 ? splits[1].Split(',', '|') : null;
                    string   type     = splits[0].Substring(1);

                    bool loop = mod.config.HasNode("MM_PATCH_LOOP");

                    foreach (UrlDir.UrlFile file in allConfigFiles)
                    {
                        if (cmd == Command.Edit)
                        {
                            foreach (UrlDir.UrlConfig url in file.configs)
                            {
                                if (!IsMatch(url, type, patterns, condition))
                                {
                                    continue;
                                }
                                if (loop)
                                {
                                    logger.Info("Looping on " + mod.SafeUrl() + " to " + url.SafeUrl());
                                }

                                do
                                {
                                    progress.ApplyingUpdate(url, mod);
                                    url.config = MMPatchLoader.ModifyNode(new NodeStack(url.config), mod.config, context);
                                } while (loop && IsMatch(url, type, patterns, condition));

                                if (loop)
                                {
                                    url.config.RemoveNodes("MM_PATCH_LOOP");
                                }
                            }
                        }
                        else if (cmd == Command.Copy)
                        {
                            // Avoid checking the new configs we are creating
                            int count = file.configs.Count;
                            for (int i = 0; i < count; i++)
                            {
                                UrlDir.UrlConfig url = file.configs[i];
                                if (!IsMatch(url, type, patterns, condition))
                                {
                                    continue;
                                }

                                ConfigNode clone = MMPatchLoader.ModifyNode(new NodeStack(url.config), mod.config, context);
                                if (url.config.HasValue("name") && url.config.GetValue("name") == clone.GetValue("name"))
                                {
                                    progress.Error(mod, $"Error - when applying copy {mod.SafeUrl()} to {url.SafeUrl()} - the copy needs to have a different name than the parent (use @name = xxx)");
                                }
                                else
                                {
                                    progress.ApplyingCopy(url, mod);
                                    file.AddConfig(clone);
                                }
                            }
                        }
                        else if (cmd == Command.Delete)
                        {
                            int i = 0;
                            while (i < file.configs.Count)
                            {
                                UrlDir.UrlConfig url = file.configs[i];

                                if (IsMatch(url, type, patterns, condition))
                                {
                                    progress.ApplyingDelete(url, mod);
                                    file.configs.RemoveAt(i);
                                }
                                else
                                {
                                    i++;
                                }
                            }
                        }
                        else
                        {
                            throw new NotImplementedException("This code should not be reachable");
                        }
                    }
                    progress.PatchApplied();
                }
                catch (Exception e)
                {
                    progress.Exception(mod, "Exception while processing node : " + mod.SafeUrl(), e);

                    try
                    {
                        logger.Error("Processed node was\n" + mod.PrettyPrint());
                    }
                    catch (Exception ex2)
                    {
                        logger.Exception("Exception while attempting to print a node", ex2);
                    }
                }
            }
        }
Exemple #3
0
        public static void CheckNeeds(UrlDir gameDatabaseRoot, IEnumerable <string> mods, IPatchProgress progress, IBasicLogger logger)
        {
            UrlDir gameData = gameDatabaseRoot.children.First(dir => dir.type == UrlDir.DirectoryType.GameData && dir.name == "");

            foreach (UrlDir.UrlConfig mod in gameDatabaseRoot.AllConfigs.ToArray())
            {
                UrlDir.UrlConfig currentMod = mod;
                try
                {
                    if (mod.config.name == null)
                    {
                        progress.Error(currentMod, "Error - Node in file " + currentMod.parent.url + " subnode: " + currentMod.type +
                                       " has config.name == null");
                    }

                    UrlDir.UrlConfig newMod;

                    if (currentMod.type.IndexOf(":NEEDS[", StringComparison.OrdinalIgnoreCase) >= 0)
                    {
                        string type = currentMod.type;

                        if (CheckNeeds(ref type, mods, gameData))
                        {
                            ConfigNode copy = new ConfigNode(type);
                            copy.ShallowCopyFrom(currentMod.config);
                            int index = mod.parent.configs.IndexOf(currentMod);
                            newMod = new UrlDir.UrlConfig(currentMod.parent, copy);
                            mod.parent.configs[index] = newMod;
                        }
                        else
                        {
                            progress.NeedsUnsatisfiedRoot(currentMod);
                            mod.parent.configs.Remove(currentMod);
                            continue;
                        }
                    }
                    else
                    {
                        newMod = currentMod;
                    }

                    // Recursively check the contents
                    PatchContext context = new PatchContext(newMod, gameDatabaseRoot, logger, progress);
                    CheckNeeds(new NodeStack(newMod.config), context, mods, gameData);
                }
                catch (Exception ex)
                {
                    try
                    {
                        mod.parent.configs.Remove(currentMod);
                    }
                    catch (Exception ex2)
                    {
                        logger.Exception("Exception while attempting to ensure config removed", ex2);
                    }

                    try
                    {
                        progress.Exception(mod, "Exception while checking needs on root node :\n" + mod.PrettyPrint(), ex);
                    }
                    catch (Exception ex2)
                    {
                        progress.Exception("Exception while attempting to log an exception", ex2);
                    }
                }
            }
        }