internal static void Work()
        {
            var mod = LoadedModManager.RunningMods.First(m => m.Name == "No Water, No Life.");

            CreateCompatibilityXml(mod);

            var list = DirectXmlLoader.XmlAssetsInModFolder(mod, DirectoryName + @"\").ToList <LoadableXmlAsset>();

            foreach (var item in list)
            {
                if (item == null || item.xmlDoc == null || item.xmlDoc.DocumentElement == null)
                {
                    Log.Error(string.Format("{0}: unknown parse failure", item.fullFolderPath + @"\" + item.name));
                }
                else if (item.xmlDoc.DocumentElement.Name != "Defs")
                {
                    Log.Error(string.Format("{0}: root element named {1}; should be named Defs", item.fullFolderPath + @"\" + item.name, item.xmlDoc.DocumentElement.Name));
                }
                XmlInheritance.TryRegisterAllFrom(item, mod);
            }
            XmlInheritance.Resolve();
            //TODO: wtf is this?
            foreach (var item in list)
            {
                // TODO NoWaterNoLife compability
                //foreach (Def def in item.defPackage)
                //{
                //    Log.Message($"Added def {def.defName}");
                //    DefDatabase<ThinkTreeDef>.Add(def as ThinkTreeDef);
                //}
            }
            foreach (var def in DefDatabase <ThinkTreeDef> .AllDefs.Where(d => d.insertTag == "Humanlike_PostDuty").OrderByDescending(d => d.insertPriority))
            {
                Log.Message($"  ThinkTree {def.defName}");
            }
        }
Exemple #2
0
            private static IEnumerable <UpdateFeatureDef> LoadAndParseNewsFeatureDefs()
            {
                XmlInheritance.Clear();
                // As we're moving the updates out of /Defs and into /News, we can no longer rely on the DefDatabase to magically
                // load all the UpdateFeatureDefs. Instead, we'll have to manually point the reader to the relevant folders.
                // Overall, we'll stick as much as we can to the vanilla def loading experience, albeit without patches.
                // Patch metadata has already been cleared, and parsing it again would add too much overhead.
                // First, gather all XML nodes that represent an UpdateFeatureDef, and remember where they came from
                // We can't parse them info defs on the spot, because there is inheritance to consider.
                var newsItemNodes = new List <(ModContentPack pack, XmlNode node, LoadableXmlAsset asset)>();

                foreach (var modContentPack in LoadedModManager.RunningMods)
                {
                    try {
                        var modNewsXmlAssets = DirectXmlLoader.XmlAssetsInModFolder(modContentPack, UpdateFeatureDefFolder);
                        foreach (var xmlAsset in modNewsXmlAssets)
                        {
                            var rootElement = xmlAsset.xmlDoc?.DocumentElement;
                            if (rootElement != null)
                            {
                                foreach (var childNode in rootElement.ChildNodes.OfType <XmlNode>())
                                {
                                    newsItemNodes.Add((modContentPack, childNode, xmlAsset));
                                }
                            }
                        }
                    } catch (Exception e) {
                        HugsLibController.Logger.Error("Failed to load UpdateFeatureDefs for mod " +
                                                       $"{modContentPack.PackageIdPlayerFacing}: {e}");
                        throw;
                    }
                }

                // deal with inheritance
                foreach (var(modContent, node, _) in newsItemNodes)
                {
                    if (node != null && node.NodeType == XmlNodeType.Element)
                    {
                        XmlInheritance.TryRegister(node, modContent);
                    }
                }
                XmlInheritance.Resolve();

                var parsedFeatureDefs = new List <UpdateFeatureDef>();

                foreach (var(pack, node, asset) in newsItemNodes)
                {
                    // parse defs
                    try {
                        var def = DirectXmlLoader.DefFromNode(node, asset) as UpdateFeatureDef;
                        if (def != null)
                        {
                            def.modContentPack = pack;
                            def.ResolveReferences();
                            parsedFeatureDefs.Add(def);
                        }
                    } catch (Exception e) {
                        HugsLibController.Logger.Error($"Failed to parse UpdateFeatureDef from mod {pack.PackageIdPlayerFacing}:\n" +
                                                       $"{GetExceptionChainMessage(e)}\n" +
                                                       $"Context: {node?.OuterXml.ToStringSafe()}\n" +
                                                       $"File: {asset?.FullFilePath.ToStringSafe()}\n" +
                                                       $"Exception: {e}");
                    }
                }

                XmlInheritance.Clear();

                return(parsedFeatureDefs);
            }
        /// <summary>
        /// INTENT: Decrease compatibility issues caused by modders overwriting (abstract) bases, by making it easy to detect the existence of these bad practices.
        ///
        /// Run once on startup. Creates list of all (abstract) bases in vanilla, then compares with bases in mods. Warns with mod name, base and exact filename for any matches found.
        /// </summary>
        static XmlSharedBaseDetection()
        {
            //since some people have such wonderfully organised mod lists they hit the 1k limit on error logging:
            Log.ResetMessageCount();

            //get all bases in vanilla.
            List <string> vanillaXmlAttributes = new List <string>();

            //Dictionary<string, string> vanillaXmlAttributes = new Dictionary<string, string>();

            foreach (ModContentPack mod in LoadedModManager.RunningMods.Where(mod => mod.IsCoreMod))
            {
                foreach (LoadableXmlAsset asset in DirectXmlLoader.XmlAssetsInModFolder(mod, "Defs/"))
                {
                    if (asset.xmlDoc?.DocumentElement == null)
                    {
                        continue;
                    }
                    XmlNodeList childNodes = asset.xmlDoc.DocumentElement.ChildNodes;
                    {
                        for (int i = 0; i < childNodes.Count; i++)
                        {
                            if (childNodes[i].NodeType != XmlNodeType.Element)
                            {
                                continue;
                            }
                            if (childNodes[i]?.Attributes?["Name"] != null)
                            {
                                vanillaXmlAttributes.Add(childNodes[i].Attributes.GetNamedItem("Name").Value /*, childNodes[i].Name*/);
                            }
                        }
                    }
                }
            }

            if (Prefs.LogVerbose)
            {
                Log.Error("Verbose mode detected. AllYourBase will attempt to fix compatibility errors. If problem persists or gets worse, Verify File Integrity or redownload affected mods.", true);
            }

            //get all bases in mods and compare them to the vanilla list.
            foreach (ModContentPack mod in LoadedModManager.RunningMods.Where(mod => !mod.IsCoreMod))
            {
                foreach (LoadableXmlAsset asset in DirectXmlLoader.XmlAssetsInModFolder(mod, "Defs/"))
                {
                    bool dirty = false;
                    if (asset.xmlDoc?.DocumentElement == null)
                    {
                        continue;
                    }
                    XmlNodeList childNodes = asset.xmlDoc.DocumentElement.ChildNodes;
                    {
                        for (int i = childNodes.Count - 1; i >= 0; i--)
                        {
                            if (childNodes[i].NodeType != XmlNodeType.Element)
                            {
                                continue;
                            }

                            if (childNodes[i]?.Attributes?["Name"] != null &&
                                vanillaXmlAttributes.Contains(childNodes[i].Attributes.GetNamedItem("Name").Value)
                                /*&& vanillaXmlAttributes[childNodes[i].Attributes.GetNamedItem("Name").Value] == childNodes[i].Name*/)
                            {
                                Log.Warning("[" + asset.mod.Name + "]" + " causes compatibility errors by overwriting " +
                                            childNodes[i].Attributes.GetNamedItem("Name").Value + " in file " + asset.FullFilePath, true);

                                if (Prefs.LogVerbose)
                                {
                                    Log.Message($"Attempting fix for {childNodes[i].Attributes.GetNamedItem("Name").Value}", true);
                                    dirty = true;
                                    asset.xmlDoc.DocumentElement.RemoveChild(childNodes[i]);
                                }
                            }
                        }
                    }
                    if (dirty)
                    {
                        asset.xmlDoc.Save(asset.FullFilePath);
                    }
                }
            }

            foreach (ChemicalDef item in DefDatabase <ChemicalDef> .AllDefsListForReading)
            {
                if (item.addictionHediff?.hediffClass == null)
                {
                    Log.Error($"{item.defName} from mod {item.modContentPack.Name} has no addictionHediff (or missing hediffClass). This will break raids and worldgen. Misconfigured XML or parent.");
                }
            }
        }
Exemple #4
0
        static List <NewFieldData> CollectFields(int inCrc, out int outCrc)
        {
            outCrc = inCrc;
            var fieldsToAdd = new List <NewFieldData>();

            foreach (var mod in LoadedModManager.RunningModsListForReading)
            {
                var assets = DirectXmlLoader.XmlAssetsInModFolder(mod, PrepatchesFolder);
                foreach (var ass in assets)
                {
                    if (ass.name != FieldsXmlFile)
                    {
                        continue;
                    }

                    foreach (var e in ass.xmlDoc["Fields"].OfType <XmlElement>())
                    {
                        var parsed = ParseFieldData(e, out bool success);
                        parsed.ownerMod = mod.Name;

                        if (success)
                        {
                            fieldsToAdd.Add(parsed);
                        }
                        else
                        {
                            ErrorXML($"{mod.Name}: Error parsing {parsed}");
                        }
                    }

                    outCrc = Gen.HashCombineInt(outCrc, new CRC32().GetCrc32(new MemoryStream(Encoding.UTF8.GetBytes(ass.xmlDoc.InnerXml))));
                }
            }

            foreach (var fieldsPerType in fieldsToAdd.Where(f => f.isEnum).GroupBy(f => f.targetType))
            {
                var targetType = GenTypes.GetTypeInAnyAssembly(fieldsPerType.Key);
                var enumType   = Enum.GetUnderlyingType(targetType);
                var max        = Util.ToUInt64(enumType.GetField("MaxValue").GetRawConstantValue());
                var taken      = AccessTools.GetDeclaredFields(targetType).Where(f => f.IsLiteral).Select(f => Util.ToUInt64(f.GetRawConstantValue())).ToHashSet();

                foreach (var f in fieldsPerType)
                {
                    var free = Util.FindNotTaken(f.enumPreferred, max, taken);
                    if (free == null)
                    {
                        ErrorXML($"{f.ownerMod}: Couldn't assign a value for {f}");
                        fieldsToAdd.Remove(f);
                        continue;
                    }

                    f.defaultValue = Util.FromUInt64(free.Value, enumType);
                    taken.Add(free.Value);
                }
            }

            foreach (var f in fieldsToAdd)
            {
                InfoXML($"{f.ownerMod}: Parsed {f}");
            }

            return(fieldsToAdd);
        }