/// <summary>Reads custom type fields from the part's config.</summary> /// <remarks> /// <para> /// The consumer code must call this method from the <c>OnLoad</c> method to capture the /// PartLoader initalization. This method automatically detects the game loading phase, so it's /// safe to call it in every <c>OnLoad</c> inovacation. /// </para> /// </remarks> /// <param name="module">The module to load the data for.</param> /// <param name="cfgNode">The config node, passed by the game to the module.</param> /// <seealso cref="PersistentFieldAttribute"/> /// <seealso cref="StdPersistentGroups.PartConfigLoadGroup"/> /// <seealso cref="CopyPartConfigFromPrefab"/> /// <example> /// <code source="Examples/ConfigUtils/ConfigAccessor-Examples.cs" region="ReadPartConfigExample"/> /// </example> public static void ReadPartConfig(PartModule module, ConfigNode cfgNode) { if (!PartLoader.Instance.IsReady()) { ConfigAccessor.ReadFieldsFromNode( cfgNode, module.GetType(), module, group: StdPersistentGroups.PartConfigLoadGroup); } }
/// <summary>Makes pacth from a config node.</summary> /// <remarks> /// The critical settings will be checked for the sane values. If a bad value found, then the /// menthod will throw. /// </remarks> /// <param name="node">The node to create from.</param> /// <param name="context"> /// The context of node loading. It can be any object, e.g. <c>UrlDir.UrlConfig</c> or /// <c>ConfigNode</c>. It's only used for logging errors to give a context for debugging. /// </param> /// <param name="url">The URL to the node in the game's DB.</param> /// <returns>The patch. It's never <c>null.</c></returns> static ConfigNodePatch MakeFromNodeInternal(ConfigNode node, object context, string url = null) { var patchNode = new ConfigNodePatch(); if (url != null) { patchNode.sourceConfigUrl = url; } ConfigAccessor.ReadFieldsFromNode(node, patchNode.GetType(), patchNode); // Sanity check of the test rules. Preconditions.ConfValueExists(patchNode.name, "node/name", context: context); Preconditions.ConfValueExists(patchNode.testSection, "node/TEST", context: context); Preconditions.ConfValueExists( patchNode.testSection.partTests, "node/TEST/PART", context: context); Preconditions.ConfValueExists( patchNode.testSection.partTests.GetValue("name"), "node/TEST/PART/name", context: context); foreach (var moduleNode in patchNode.testSection.moduleTests) { Preconditions.ConfValueExists( moduleNode.GetValue("name"), "node/TEST/MODULE/name", context: context); } // Sanity check of the upgrade rules Preconditions.ConfValueExists(patchNode.upgradeSection, "node/UPGRADE", context: context); Preconditions.ConfValueExists( patchNode.upgradeSection.partRules, "node/UPGRADE/PART", context: context); Preconditions.OneOf(patchNode.upgradeSection.partRules.action, new[] { PatchAction.Drop, PatchAction.Fix }, "node/UPGRADE/PART/action", context: context); foreach (var moduleRule in patchNode.upgradeSection.moduleRules) { Preconditions.ConfValueExists(moduleRule.name, "node/TEST/MODULE/name", context: context); } // Check the patch age. var patchAgeDays = (DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalDays - patchNode.patchCreationTimestamp / (24 * 60 * 60); if (patchAgeDays > 180) { DebugEx.Warning("Patch is too old: patch={0}, age={1} days", patchNode, patchAgeDays); } return(patchNode); }