public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            // Read min/max first
            valid &= ConfigNodeUtil.ParseValue <int?>(configNode, "minCount", x => minCount = x, this,
                                                      configNode.HasNode("VALIDATE") || configNode.HasNode("VALIDATE_ALL") || configNode.HasNode("NONE") ? (int?)null : 1, x => x == null || Validation.GE(x.Value, 0));
            valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxCount", x => maxCount = x, this, minCount != null && minCount.Value == 0 ? 0 : int.MaxValue, x => Validation.GE(x, 0));

            // Set the default match type
            ParameterDelegateMatchType defaultMatch = ParameterDelegateMatchType.FILTER;

            if (maxCount == 0)
            {
                defaultMatch = ParameterDelegateMatchType.NONE;
            }

            // Standard definition
            if (configNode.HasValue("part") || configNode.HasValue("partModule") || configNode.HasValue("partModuleType") || configNode.HasValue("category") || configNode.HasValue("manufacturer"))
            {
                PartValidation.Filter filter = new PartValidation.Filter(defaultMatch);
                valid &= ConfigNodeUtil.ParseValue <List <AvailablePart> >(configNode, "part", x => filter.parts = x, this, new List <AvailablePart>());
                valid &= ConfigNodeUtil.ParseValue <List <string> >(configNode, "partModule", x => filter.partModules = x, this, new List <string>(), x => x.All(Validation.ValidatePartModule));
                valid &= ConfigNodeUtil.ParseValue <List <string> >(configNode, "partModuleType", x => filter.partModuleTypes = x, this, new List <string>(), x => x.All(Validation.ValidatePartModuleType));
                valid &= ConfigNodeUtil.ParseValue <PartCategories?>(configNode, "category", x => filter.category = x, this, (PartCategories?)null);
                valid &= ConfigNodeUtil.ParseValue <string>(configNode, "manufacturer", x => filter.manufacturer = x, this, (string)null);

                // Add modules
                foreach (ConfigNode moduleNode in configNode.GetNodes("MODULE"))
                {
                    ConfigNode.ValueList tmp = new ConfigNode.ValueList();
                    foreach (ConfigNode.Value v in moduleNode.values)
                    {
                        tmp.Add(new ConfigNode.Value(v.name, v.value));
                    }
                    filter.partModuleExtended.Add(tmp);
                }

                filters.Add(filter);
            }

            // Extended definition
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode))
            {
                ParameterDelegateMatchType matchType;
                if (child.name == "FILTER")
                {
                    matchType = ParameterDelegateMatchType.FILTER;
                }
                else if (child.name == "VALIDATE")
                {
                    matchType = ParameterDelegateMatchType.VALIDATE;
                }
                else if (child.name == "VALIDATE_ALL")
                {
                    matchType = ParameterDelegateMatchType.VALIDATE_ALL;
                }
                else if (child.name == "NONE")
                {
                    matchType = ParameterDelegateMatchType.NONE;
                }
                else
                {
                    LoggingUtil.LogError(this, ErrorPrefix() + ": unexpected node '" + child.name + "'.");
                    valid = false;
                    continue;
                }

                if (defaultMatch == ParameterDelegateMatchType.NONE)
                {
                    matchType = ParameterDelegateMatchType.NONE;
                }

                PartValidation.Filter filter = new PartValidation.Filter(matchType);
                valid &= ConfigNodeUtil.ParseValue <List <AvailablePart> >(child, "part", x => filter.parts = x, this, new List <AvailablePart>());
                valid &= ConfigNodeUtil.ParseValue <List <string> >(child, "partModule", x => filter.partModules = x, this, new List <string>(), x => x.All(Validation.ValidatePartModule));
                valid &= ConfigNodeUtil.ParseValue <List <string> >(child, "partModuleType", x => filter.partModuleTypes = x, this, new List <string>());
                valid &= ConfigNodeUtil.ParseValue <PartCategories?>(child, "category", x => filter.category = x, this, (PartCategories?)null);
                valid &= ConfigNodeUtil.ParseValue <string>(child, "manufacturer", x => filter.manufacturer = x, this, (string)null);

                foreach (ConfigNode moduleNode in child.GetNodes("MODULE"))
                {
                    ConfigNode.ValueList tmp = new ConfigNode.ValueList();
                    foreach (ConfigNode.Value v in moduleNode.values)
                    {
                        tmp.Add(new ConfigNode.Value(v.name, v.value));
                    }
                    filter.partModuleExtended.Add(tmp);
                }

                if (matchType == ParameterDelegateMatchType.VALIDATE)
                {
                    valid &= ConfigNodeUtil.ParseValue <int>(child, "minCount", x => filter.minCount = x, this, 1, x => Validation.GE(x, 0));
                    valid &= ConfigNodeUtil.ParseValue <int>(child, "maxCount", x => filter.maxCount = x, this, int.MaxValue, x => Validation.GE(x, 0));
                }

                filters.Add(filter);
            }

            return(valid);
        }
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            valid &= ConfigNodeUtil.ParseValue <int>(configNode, "index", x => index = x, this, 0, x => Validation.GE(x, 0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "distance", x => distance = x, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "horizontalDistance", x => horizontalDistance = x, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <bool>(configNode, "hideOnCompletion", x => hideOnCompletion = x, this, true);
            valid &= ConfigNodeUtil.ParseValue <bool>(configNode, "showMessages", x => showMessages = x, this, false);

            return(valid);
        }
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            // Get altitude
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "altitude", ref altitude, this, x => Validation.GT(x, 0.0));

            return(valid);
        }
Esempio n. 4
0
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            // Read min/max first
            valid &= ConfigNodeUtil.ParseValue <int>(configNode, "minCount", ref minCount, this,
                                                     configNode.HasNode("VALIDATE_ALL") || configNode.HasNode("NONE") ? 0 : 1, x => Validation.GE(x, 0));
            valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxCount", ref maxCount, this, int.MaxValue, x => Validation.GE(x, 0));

            // Set the default match type
            ParameterDelegateMatchType defaultMatch = ParameterDelegateMatchType.FILTER;

            if (maxCount == 0)
            {
                defaultMatch = ParameterDelegateMatchType.NONE;
            }

            // Standard definition
            if (configNode.HasValue("part") || configNode.HasValue("partModule") || configNode.HasValue("category") || configNode.HasValue("manufacturer"))
            {
                PartValidation.Filter filter = new PartValidation.Filter(defaultMatch);
                valid &= ConfigNodeUtil.ParseValue <AvailablePart>(configNode, "part", ref filter.part, this, (AvailablePart)null);
                valid &= ConfigNodeUtil.ParseValue <List <string> >(configNode, "partModule", ref filter.partModules, this, new List <string>(), x => x.All(Validation.ValidatePartModule));
                valid &= ConfigNodeUtil.ParseValue <PartCategories?>(configNode, "category", ref filter.category, this, (PartCategories?)null);
                valid &= ConfigNodeUtil.ParseValue <string>(configNode, "manufacturer", ref filter.manufacturer, this, (string)null);
                filters.Add(filter);
            }

            // Extended definition
            foreach (ConfigNode child in configNode.GetNodes())
            {
                ParameterDelegateMatchType matchType;
                if (child.name == "FILTER")
                {
                    matchType = ParameterDelegateMatchType.FILTER;
                }
                else if (child.name == "VALIDATE_ALL")
                {
                    matchType = ParameterDelegateMatchType.VALIDATE_ALL;
                }
                else if (child.name == "NONE")
                {
                    matchType = ParameterDelegateMatchType.NONE;
                }
                else
                {
                    LoggingUtil.LogError(this, ErrorPrefix() + ": unexpected node '" + child.name + "'.");
                    valid = false;
                    continue;
                }

                if (defaultMatch == ParameterDelegateMatchType.NONE)
                {
                    matchType = ParameterDelegateMatchType.NONE;
                }

                PartValidation.Filter filter = new PartValidation.Filter(matchType);
                valid &= ConfigNodeUtil.ParseValue <AvailablePart>(child, "part", ref filter.part, this, (AvailablePart)null);
                valid &= ConfigNodeUtil.ParseValue <List <string> >(child, "partModule", ref filter.partModules, this, new List <string>(), x => x.All(Validation.ValidatePartModule));
                valid &= ConfigNodeUtil.ParseValue <PartCategories?>(child, "category", ref filter.category, this, (PartCategories?)null);
                valid &= ConfigNodeUtil.ParseValue <string>(child, "manufacturer", ref filter.manufacturer, this, (string)null);
                filters.Add(filter);
            }

            return(valid);
        }
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "minPeA", ref minPeA, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "maxPeA", ref maxPeA, this, double.MaxValue, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.AtLeastOne(configNode, new string[] { "minPeA", "maxPeA" }, this);
            valid &= ValidateTargetBody(configNode);

            LoggingUtil.LogError(this, "OrbitPeriapsis is obsolete as of ContractConfigurator 0.5.0, please use Orbit instead.  OrbitPeriapsis will be removed in a future release.");

            return(valid);
        }
Esempio n. 6
0
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            valid &= ConfigNodeUtil.ParseValue <string>(configNode, "biome", x => biome = x, this, "");
            valid &= ConfigNodeUtil.ParseValue <Vessel.Situations?>(configNode, "situation", x => situation = x, this, (Vessel.Situations?)null);
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minAltitude", x => minAltitude = x, this, 0.0f, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxAltitude", x => maxAltitude = x, this, float.MaxValue, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minTerrainAltitude", x => minTerrainAltitude = x, this, 0.0f, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxTerrainAltitude", x => maxTerrainAltitude = x, this, float.MaxValue, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "minSpeed", x => minSpeed = x, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "maxSpeed", x => maxSpeed = x, this, double.MaxValue, x => Validation.GE(x, 0.0));

            // Validate target body
            valid &= ValidateTargetBody(configNode);

            // Validation minimum set
            valid &= ConfigNodeUtil.AtLeastOne(configNode, new string[] { "targetBody", "biome", "situation", "minAltitude", "maxAltitude",
                                                                          "minTerrainAltitude", "maxTerrainAltitude", "minSpeed", "maxSpeed" }, this);

            return(valid);
        }
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "minSpeed", ref minSpeed, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "maxSpeed", ref maxSpeed, this, double.MaxValue, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.AtLeastOne(configNode, new string[] { "minSpeed", "maxSpeed" }, this);

            LoggingUtil.LogError(this, "ReachSpeedEnvelope is obsolete as of ContractConfigurator 0.5.3, please use ReachState instead.  ReachSpeedEnvelope will be removed in a future release.");

            return(valid);
        }
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            IEnumerable <ConfigNode> nodes = ConfigNodeUtil.GetChildNodes(configNode, "RESOURCE");

            if (configNode.HasValue("resource"))
            {
                nodes = nodes.Concat(new ConfigNode[] { configNode });
            }

            foreach (ConfigNode childNode in nodes)
            {
                HasResource.Filter filter = new HasResource.Filter();

                valid &= ConfigNodeUtil.ParseValue <double>(childNode, "minQuantity", x => filter.minQuantity = x, this, 0.01, x => Validation.GE(x, 0.0));
                valid &= ConfigNodeUtil.ParseValue <double>(childNode, "maxQuantity", x => filter.maxQuantity = x, this, double.MaxValue, x => Validation.GE(x, 0.0));
                valid &= ConfigNodeUtil.ParseValue <PartResourceDefinition>(childNode, "resource", x => filter.resource = x, this);

                filters.Add(filter);
            }

            return(valid);
        }
Esempio n. 9
0
        public override bool LoadFromConfig(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.LoadFromConfig(configNode);

            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minReputation", x => minReputation = x, this, -1000.0f, x => Validation.Between(x, -1000.0f, 1000.0f));
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxReputation", x => maxReputation = x, this, 1000.0f, x => Validation.Between(x, -1000.0f, 1000.0f));
            valid &= ConfigNodeUtil.AtLeastOne(configNode, new string[] { "minReputation", "maxReputation" }, this);

            // Not invertable
            valid &= ConfigNodeUtil.ParseValue <bool>(configNode, "invertRequirement", x => invertRequirement = x, this, false, x => Validation.EQ(x, false));

            return(valid);
        }
Esempio n. 10
0
        public override bool Load(ConfigNode configNode)
        {
            // Ignore the targetBody in the base class
            configNode.AddValue("ignoreTargetBody", true);

            // Load base class
            bool valid = base.Load(configNode);

            valid &= ConfigNodeUtil.ParseValue <bool>(configNode, "failWhenUnmet", x => failWhenUnmet = x, this, false);
            valid &= ConfigNodeUtil.ParseValue <Biome>(configNode, "biome", x => biome = x, this, (Biome)null);
            valid &= ConfigNodeUtil.ParseValue <List <Vessel.Situations> >(configNode, "situation", x => situation = x, this, new List <Vessel.Situations>());
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minAltitude", x => minAltitude = x, this, float.MinValue);
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxAltitude", x => maxAltitude = x, this, float.MaxValue);
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minTerrainAltitude", x => minTerrainAltitude = x, this, 0.0f, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxTerrainAltitude", x => maxTerrainAltitude = x, this, float.MaxValue, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "minSpeed", x => minSpeed = x, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "maxSpeed", x => maxSpeed = x, this, double.MaxValue, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "minRateOfClimb", x => minRateOfClimb = x, this, double.MinValue);
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "maxRateOfClimb", x => maxRateOfClimb = x, this, double.MaxValue);
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "minAcceleration", x => minAcceleration = x, this, 0.0f, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <float>(configNode, "maxAcceleration", x => maxAcceleration = x, this, float.MaxValue, x => Validation.GE(x, 0.0f));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "minDeltaVeeActual", x => minDeltaVeeActual = x, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "maxDeltaVeeActual", x => maxDeltaVeeActual = x, this, double.MaxValue, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "minDeltaVeeVacuum", x => minDeltaVeeVacuum = x, this, 0.0, x => Validation.GE(x, 0.0));
            valid &= ConfigNodeUtil.ParseValue <double>(configNode, "maxDeltaVeeVacuum", x => maxDeltaVeeVacuum = x, this, double.MaxValue, x => Validation.GE(x, 0.0));

            // Overload targetBody
            if (!configNode.HasValue("targetBody"))
            {
                configNode.AddValue("targetBody", "[ @/targetBody ]");
            }
            valid &= ConfigNodeUtil.ParseValue <List <CelestialBody> >(configNode, "targetBody", x => targetBodies = x, this);

            // Validation minimum set
            valid &= ConfigNodeUtil.AtLeastOne(configNode, new string[] { "targetBody", "biome", "situation", "minAltitude", "maxAltitude",
                                                                          "minTerrainAltitude", "maxTerrainAltitude", "minSpeed", "maxSpeed", "minRateOfClimb", "maxRateOfClimb", "minAcceleration", "maxAcceleration", "minDeltaVeeActual", "maxDeltaVeeActual", "minDeltaVeeVacuum", "maxDeltaVeeVacuum" }, this);

            return(valid);
        }
        /// <summary>
        /// Loads the contract group details from the given config node.
        /// </summary>
        /// <param name="configNode">The config node to load from</param>
        /// <returns>Whether we were successful.</returns>
        public bool Load(ConfigNode configNode)
        {
            try
            {
                dataNode = new DataNode(configNode.GetValue("name"), this);

                LoggingUtil.CaptureLog = true;
                ConfigNodeUtil.SetCurrentDataNode(dataNode);
                bool   valid = true;
                string unused;

                valid &= ConfigNodeUtil.ParseValue <string>(configNode, "name", x => name = x, this);
                valid &= ConfigNodeUtil.ParseValue <string>(configNode, "displayName", x => displayName = x, this, name);
                valid &= ConfigNodeUtil.ParseValue <string>(configNode, "minVersion", x => minVersionStr = x, this, "");
                valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxCompletions", x => maxCompletions = x, this, 0, x => Validation.GE(x, 0));
                valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxSimultaneous", x => maxSimultaneous = x, this, 0, x => Validation.GE(x, 0));
                valid &= ConfigNodeUtil.ParseValue <List <string> >(configNode, "disabledContractType", x => disabledContractType = x, this, new List <string>());
                valid &= ConfigNodeUtil.ParseValue <Agent>(configNode, "agent", x => agent = x, this, (Agent)null);
                valid &= ConfigNodeUtil.ParseValue <string>(configNode, "sortKey", x => sortKey = x, this, displayName);
                valid &= ConfigNodeUtil.ParseValue <string>(configNode, "tip", x => unused = x, this, "");

                if (configNode.HasValue("sortKey") && parent == null)
                {
                    sortKey = displayName;
                    LoggingUtil.LogWarning(this, ErrorPrefix() + ": Using the sortKey field is only applicable on child CONTRACT_GROUP elements");
                }

                if (!string.IsNullOrEmpty(minVersionStr))
                {
                    if (Util.Version.VerifyAssemblyVersion("ContractConfigurator", minVersionStr) == null)
                    {
                        valid = false;

                        var    ainfoV  = Attribute.GetCustomAttribute(typeof(ExceptionLogWindow).Assembly, typeof(AssemblyInformationalVersionAttribute)) as AssemblyInformationalVersionAttribute;
                        string title   = "Contract Configurator " + ainfoV.InformationalVersion + " Message";
                        string message = "The contract group '" + name + "' requires at least Contract Configurator " + minVersionStr +
                                         " to work, and you are running version " + ainfoV.InformationalVersion +
                                         ".  Please upgrade Contract Configurator to use the contracts in this group.";
                        DialogGUIButton dialogOption = new DialogGUIButton("Okay", new Callback(DoNothing), true);
                        PopupDialog.SpawnPopupDialog(new MultiOptionDialog("ContractConfiguratorMsg", message, title, UISkinManager.GetSkin("default"), dialogOption), false, UISkinManager.GetSkin("default"));
                    }
                }

                // Load DATA nodes
                valid &= dataNode.ParseDataNodes(configNode, this, dataValues, uniquenessChecks);

                // Do the deferred loads
                valid &= ConfigNodeUtil.ExecuteDeferredLoads();

                // Do post-deferred load warnings
                if (agent == null)
                {
                    LoggingUtil.LogWarning(this, ErrorPrefix() + ": Providing the agent field for all CONTRACT_GROUP nodes is highly recommended, as the agent is used to group contracts in Mission Control.");
                }
                if (string.IsNullOrEmpty(minVersionStr) || minVersion < ContractConfigurator.ENHANCED_UI_VERSION)
                {
                    LoggingUtil.LogWarning(this, ErrorPrefix() + ": No minVersion or older minVersion provided.  It is recommended that the minVersion is set to at least 1.15.0 to turn important warnings for deprecated functionality into errors.");
                }
                if (!configNode.HasValue("displayName"))
                {
                    LoggingUtil.LogWarning(this, ErrorPrefix() + ": No display name provided.  A display name is recommended, as it is used in the Mission Control UI.");
                }

                config = configNode.ToString();
                log   += LoggingUtil.capturedLog;
                LoggingUtil.CaptureLog = false;

                // Load child groups
                foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "CONTRACT_GROUP"))
                {
                    ContractGroup child     = null;
                    string        childName = childNode.GetValue("name");
                    try
                    {
                        child = new ContractGroup(childName);
                    }
                    catch (ArgumentException)
                    {
                        LoggingUtil.LogError(this, "Couldn't load CONTRACT_GROUP '" + childName + "' due to a duplicate name.");
                        valid = false;
                        continue;
                    }

                    child.parent          = this;
                    valid                &= child.Load(childNode);
                    child.dataNode.Parent = dataNode;
                    if (child.hasWarnings)
                    {
                        hasWarnings = true;
                    }
                }

                // Check for unexpected values - always do this last
                valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, this);

                // Invalidate children
                if (!valid)
                {
                    Invalidate();
                }

                enabled = valid;
                return(valid);
            }
            catch
            {
                enabled = false;
                throw;
            }
        }
Esempio n. 12
0
        public override bool LoadFromConfig(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.LoadFromConfig(configNode);

            // Check on active contracts too
            checkOnActiveContract = configNode.HasValue("checkOnActiveContract") ? checkOnActiveContract : true;

            valid &= ConfigNodeUtil.ParseValue <SpaceCenterFacility>(configNode, "facility", x => facility = x, this);
            valid &= ConfigNodeUtil.ParseValue <int>(configNode, "minLevel", x => minLevel = x, this, 1, x => Validation.Between(x, 1, 3));
            valid &= ConfigNodeUtil.ParseValue <int>(configNode, "maxLevel", x => maxLevel = x, this, 3, x => Validation.Between(x, 1, 3));
            valid &= ConfigNodeUtil.AtLeastOne(configNode, new string[] { "minLevel", "maxLevel" }, this);

            // Not invertable
            valid &= ConfigNodeUtil.ParseValue <bool>(configNode, "invertRequirement", x => invertRequirement = x, this, false, x => Validation.EQ(x, false));

            return(valid);
        }