예제 #1
0
        public DataNode(string name, DataNode parent, IContractConfiguratorFactory factory)
        {
            this.parent = parent;
            this.factory = factory;
            this.name = name;

            if (parent != null && parent.factory.GetType() != typeof(ContractGroup))
            {
                // Check for duplicate name - probably could be more efficient here
                int i = 1;
                while (parent.children.Any(dn => dn.name == this.name))
                {
                    this.name = name + "_" + i++;
                }

                parent.children.Add(this);
                root = parent.root;
            }
            else if (factory != null && factory.GetType() != typeof(ContractGroup))
            {
                root = this;
            }
            else
            {
                root = null;
            }
        }
예제 #2
0
        public DataNode(string name, DataNode parent, IContractConfiguratorFactory factory)
        {
            if (parent != null)
            {
                // Check for duplicate name - probably could be more efficient here
                string origName = name;
                int i = 1;
                while (parent.children.Any(dn => dn.name == name))
                {
                    name = origName + "_" + i++;
                }
            }

            this.parent = parent;
            this.factory = factory;
            this.name = name;
            if (parent != null)
            {
                parent.children.Add(this);
                root = parent.root;
            }
            else
            {
                root = this;
            }
        }
예제 #3
0
        public static bool InitializeIteratorKey(ConfigNode node, IContractConfiguratorFactory obj)
        {
            bool valid = true;

            // Nothing to do
            if (obj.iteratorType == null)
            {
                return(true);
            }

            // Set the correct data node
            ConfigNodeUtil.SetCurrentDataNode(obj.dataNode);

            // First initalize our iterator count variable (no reflection needed)
            valid &= ConfigNodeUtil.ParseValue <int>(node, "iteratorCount", x => { }, obj);

            // Check if it already exists (happens when using the an existing value for a key)
            if (obj.dataNode.data.ContainsKey(obj.iteratorKey))
            {
                return(valid);
            }

            // Create the setter function
            object   value      = null;
            Type     actionType = typeof(Action <>).MakeGenericType(obj.iteratorType);
            Delegate del        = Delegate.CreateDelegate(actionType, value, typeof(DataNode).GetMethod("NullAction"));

            // Invoke the ParseValue method
            MethodInfo parseMethod = parseMethodGeneric.MakeGenericMethod(new Type[] { obj.iteratorType });

            valid &= (bool)parseMethod.Invoke(null, new object[] { node, obj.iteratorKey, del, obj });

            return(valid);
        }
예제 #4
0
        /// <summary>
        /// Ensures the given config node has at least one of the given values.
        /// </summary>
        /// <param name="configNode"></param>
        /// <param name="values"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool AtLeastOne(ConfigNode configNode, string[] values, IContractConfiguratorFactory obj)
        {
            string output = "";

            foreach (string value in values)
            {
                if (configNode.HasValue(value))
                {
                    return(true);
                }

                if (value == values.First())
                {
                    output = value;
                }
                else if (value == values.Last())
                {
                    output += " or " + value;
                }
                else
                {
                    output += ", " + value;
                }
            }

            if (values.Count() == 2)
            {
                LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Either " + output + " is required.");
            }
            else
            {
                LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": One of " + output + " is required.");
            }
            return(false);
        }
예제 #5
0
        public DataNode(string name, DataNode parent, IContractConfiguratorFactory factory)
        {
            this.parent  = parent;
            this.factory = factory;
            this.name    = name;

            if (parent != null && parent.factory.GetType() != typeof(ContractGroup))
            {
                // Check for duplicate name - probably could be more efficient here
                int i = 1;
                while (parent.children.Any(dn => dn.name == this.name))
                {
                    this.name = name + "_" + i++;
                }

                parent.children.Add(this);
                root = parent.root;
            }
            else if (factory != null && factory.GetType() != typeof(ContractGroup))
            {
                root = this;
            }
            else
            {
                root = null;
            }
        }
예제 #6
0
        public static void LogWarning(System.Object obj, string message)
        {
            // Set the hasWarnings flag
            IContractConfiguratorFactory ccFactory = obj as IContractConfiguratorFactory;

            if (ccFactory != null)
            {
                ccFactory.hasWarnings = true;
            }

            LoggingUtil.Log(LogLevel.WARNING, obj.GetType(), message);
        }
예제 #7
0
 public DataNode(string name, DataNode parent, IContractConfiguratorFactory factory)
 {
     this.parent  = parent;
     this.factory = factory;
     this.name    = name;
     if (parent != null)
     {
         parent.children.Add(this);
         root = parent.root;
     }
     else
     {
         root = this;
     }
 }
예제 #8
0
        /// <summary>
        /// Performs validation to check if the given config node has values that were not expected.
        /// </summary>
        /// <param name="configNode">The ConfigNode to check.</param>
        /// <param name="obj">IContractConfiguratorFactory object for error reporting</param>
        /// <returns>Always true, but logs a warning if unexpected keys were found</returns>
        public static bool ValidateUnexpectedValues(ConfigNode configNode, IContractConfiguratorFactory obj)
        {
            bool valid = true;

            if (!keysFound.ContainsKey(configNode))
            {
                obj.hasWarnings = true;
                LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() +
                                       ": did not attempt to load values for ConfigNode!");
                return(false);
            }

            Dictionary <string, int> found = keysFound[configNode];

            foreach (ConfigNode.Value pair in configNode.values)
            {
                if (!found.ContainsKey(pair.name))
                {
                    obj.hasWarnings = true;
                    LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() +
                                           ": unexpected attribute '" + pair.name + "' found, ignored.");
                }
            }

            foreach (ConfigNode child in configNode.nodes)
            {
                // Exceptions
                if (child.name == "PARAMETER" && (obj is ContractType || obj is ParameterFactory) ||
                    child.name == "REQUIREMENT" && (obj is ContractType || obj is ParameterFactory || obj is ContractRequirement) ||
                    child.name == "BEHAVIOUR" && (obj is ContractType) ||
                    child.name == "ORBIT" && (obj is Behaviour.OrbitGeneratorFactory || obj is Behaviour.SpawnVesselFactory || obj is Behaviour.SpawnKerbalFactory))
                {
                    continue;
                }

                if (!found.ContainsKey(child.name))
                {
                    obj.hasWarnings = true;
                    LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() +
                                           ": unexpected child node '" + child.name + "' found, ignored.");
                }
            }


            return(valid);
        }
예제 #9
0
        /// <summary>
        /// Outputs the debugging info for the debug window.
        /// </summary>
        static string DebugInfo(IContractConfiguratorFactory obj)
        {
            if (!toolTipCache.ContainsKey(obj) || toolTipCache[obj].Key != obj.dataNode.lastModified)
            {
                string result = "";
                result += "<b><color=white>Config Node Details</color></b>\n";
                result += obj.config;
                result += "\n\n";
                result += "<b><color=white>Config Details After Expressions</color></b>\n";
                result += DataNodeDebug(obj.dataNode, obj is BehaviourFactory) + "\n";
                result += "<b><color=white>Log Details</color></b>\n";
                result += obj.log;

                toolTipCache[obj] = new KeyValuePair <double, string>(obj.dataNode.lastModified, result);
            }

            return(toolTipCache[obj].Value);
        }
예제 #10
0
        /// <summary>
        /// Performs validation to check if the given config node has values that were not expected.
        /// </summary>
        /// <param name="configNode">The ConfigNode to check.</param>
        /// <param name="obj">IContractConfiguratorFactory object for error reporting</param>
        /// <returns>Always true, but logs a warning if unexpected keys were found</returns>
        public static bool ValidateUnexpectedValues(ConfigNode configNode, IContractConfiguratorFactory obj)
        {
            if (!keysFound.ContainsKey(configNode))
            {
                LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() +
                                       ": did not attempt to load values for ConfigNode!");
                return(false);
            }

            Dictionary <string, int> found = keysFound[configNode];

            foreach (ConfigNode.Value pair in configNode.values)
            {
                if (!found.ContainsKey(pair.name))
                {
                    LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() +
                                           ": unexpected entry '" + pair.name + "' found, ignored.");
                }
            }

            return(true);
        }
예제 #11
0
        public static void LogWarning(System.Object obj, string message)
        {
            // Set the hasWarnings flag
            IContractConfiguratorFactory ccFactory = obj as IContractConfiguratorFactory;

            if (ccFactory == null && captureLog && ConfigNodeUtil.currentDataNode != null)
            {
                ccFactory = ConfigNodeUtil.currentDataNode.Factory;
            }
            else
            {
                DataNode dataNode = obj as DataNode;
                if (dataNode != null)
                {
                    ccFactory = dataNode.Factory;
                }
            }
            if (ccFactory != null)
            {
                ccFactory.hasWarnings = true;
            }

            LoggingUtil.Log(LogLevel.WARNING, obj.GetType(), message);
        }
        /// <summary>
        /// Ensures the given config node has at exactly  one of the given values.
        /// </summary>
        /// <param name="configNode"></param>
        /// <param name="values"></param>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static bool OnlyOne(ConfigNode configNode, string[] values, IContractConfiguratorFactory obj)
        {
            int    count  = 0;
            string output = "";

            foreach (string value in values)
            {
                if (configNode.HasValue(value))
                {
                    count++;
                }

                if (value == values.First())
                {
                    output = value;
                }
                else if (value == values.Last())
                {
                    output += " or " + value;
                }
                else
                {
                    output += ", " + value;
                }
            }

            if (count != 1)
            {
                LoggingUtil.LogError(obj, "{0}: Exactly one of the following types is allowed: {1}", obj.ErrorPrefix(configNode), output);
                return(false);
            }
            else
            {
                return(true);
            }
        }
예제 #13
0
 /// <summary>
 /// Attempts to parse a value from the config node.  Returns a default value if not found.
 /// </summary>
 /// <typeparam name="T">The type of value to convert to.</typeparam>
 /// <param name="configNode">The ConfigNode to read from.</param>
 /// <param name="key">The key to examine.</param>
 /// <param name="setter">Function used to set the output value</param>
 /// <param name="obj">Factory object for error messages.</param>
 /// <param name="defaultValue">Default value to use if there is no key in the config node</param>
 /// <returns>The parsed value (or default value if not found)</returns>
 public static bool ParseValue <T>(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj, T defaultValue)
 {
     return(ParseValue <T>(configNode, key, setter, obj, defaultValue, x => true));
 }
예제 #14
0
 public DeferredLoadObject(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj, Func <T, bool> validation,
                           DataNode dataNode)
 {
     this.key        = key;
     this.configNode = configNode;
     this.setter     = setter;
     this.obj        = obj;
     this.validation = validation;
     this.dataNode   = dataNode;
 }
예제 #15
0
        /// <summary>
        /// Validates that the given config node does NOT contain the given value.
        /// </summary>
        /// <param name="configNode">The ConfigNode to check.</param>
        /// <param name="field">The field to exclude</param>
        /// <param name="obj">IContractConfiguratorFactory object for error reporting</param>
        /// <returns>Always true, but logs a warning for an unexpected value.</returns>
        public static bool ValidateExcludedValue(ConfigNode configNode, string field, IContractConfiguratorFactory obj)
        {
            if (configNode.HasNode(field) || configNode.HasValue(field))
            {
                LoggingUtil.LogWarning(obj.GetType(), obj.ErrorPrefix() +
                                       ": unexpected entry '" + field + "' found, ignored.");
            }

            return(true);
        }
        /// <summary>
        /// Parses the child DATA nodes out of the given config node, and returns the parsed values back in dataValues.
        /// </summary>
        /// <param name="configNode">The ConfigNode to load child DATA nodes from.</param>
        /// <param name="obj">The ContractConfigurator object to load from.</param>
        /// <param name="dataValues"></param>
        /// <param name="uniquenessChecks"></param>
        /// <returns></returns>
        public bool ParseDataNodes(ConfigNode configNode, IContractConfiguratorFactory obj,
            Dictionary<string, ContractType.DataValueInfo> dataValues, Dictionary<string, UniquenessCheck> uniquenessChecks)
        {
            bool valid = true;

            foreach (ConfigNode data in ConfigNodeUtil.GetChildNodes(configNode, "DATA"))
            {
                Type type = null;
                bool requiredValue = true;
                bool hidden = true;
                string title = "";

                ConfigNodeUtil.SetCurrentDataNode(null);
                valid &= ConfigNodeUtil.ParseValue<Type>(data, "type", x => type = x, obj);
                valid &= ConfigNodeUtil.ParseValue<bool>(data, "requiredValue", x => requiredValue = x, obj, true);
                valid &= ConfigNodeUtil.ParseValue<string>(data, "title", x => title = x, obj, "");
                valid &= ConfigNodeUtil.ParseValue<bool>(data, "hidden", x => hidden = x, obj, false);

                bool doneTitleWarning = false;

                UniquenessCheck uniquenessCheck = UniquenessCheck.NONE;
                // Backwards compatibility for Contract Configurator 1.8.3
                if (data.HasValue("uniqueValue") || data.HasValue("activeUniqueValue"))
                {
                    LoggingUtil.LogWarning(this, "The use of uniqueValue and activeUniqueValue is obsolete since Contract Configurator 1.9.0, use uniquenessCheck instead.");

                    bool uniqueValue = false;
                    bool activeUniqueValue = false;
                    valid &= ConfigNodeUtil.ParseValue<bool>(data, "uniqueValue", x => uniqueValue = x, obj, false);
                    valid &= ConfigNodeUtil.ParseValue<bool>(data, "activeUniqueValue", x => activeUniqueValue = x, obj, false);

                    uniquenessCheck = activeUniqueValue ? UniquenessCheck.CONTRACT_ACTIVE : uniqueValue ? UniquenessCheck.CONTRACT_ALL : UniquenessCheck.NONE;
                }
                else
                {
                    valid &= ConfigNodeUtil.ParseValue<UniquenessCheck>(data, "uniquenessCheck", x => uniquenessCheck = x, obj, UniquenessCheck.NONE);
                }

                ConfigNodeUtil.SetCurrentDataNode(this);

                if (type != null)
                {
                    foreach (ConfigNode.Value pair in data.values)
                    {
                        string name = pair.name;
                        if (name != "type" && name != "title" && name != "hidden" && name != "requiredValue" && name != "uniqueValue" && name != "activeUniqueValue" && name != "uniquenessCheck")
                        {
                            if (uniquenessCheck != UniquenessCheck.NONE)
                            {
                                uniquenessChecks[name] = uniquenessCheck;
                            }

                            object value = null;

                            // Create the setter function
                            Type actionType = typeof(Action<>).MakeGenericType(type);
                            Delegate del = Delegate.CreateDelegate(actionType, value, typeof(DataNode).GetMethod("NullAction"));

                            // Set the ParseValue method generic
                            MethodInfo method = methodParseValue.MakeGenericMethod(new Type[] { type });

                            // Invoke the ParseValue method
                            valid &= (bool)method.Invoke(null, new object[] { data, name, del, obj });

                            dataValues[name] = new ContractType.DataValueInfo(title, requiredValue, hidden, type);

                            // Recommend a title
                            if (!data.HasValue("title") && requiredValue && !IsDeterministic(name) && !hidden && !doneTitleWarning && !dataValues[name].IsIgnoredType())
                            {
                                doneTitleWarning = true;

                                LoggingUtil.Log(obj.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING, this,
                                    obj.ErrorPrefix() + ": " + name + ": The field 'title' is required in for data node values where 'requiredValue' is true.  Alternatively, the attribute 'hidden' can be set to true (but be careful - this can cause player confusion if all lines for the contract type show as 'Met' and the contract isn't generating).");

                                // Error on newer versions of contract packs
                                if (obj.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION)
                                {
                                    valid = false;
                                }
                            }

                        }
                    }
                }
            }

            return valid;
        }
예제 #17
0
        /// <summary>
        /// Checks whether the mandatory field exists, and if not logs and error.  Returns true
        /// only if the validation succeeded.
        /// </summary>
        /// <param name="configNode">The ConfigNode to check.</param>
        /// <param name="field">The child that is expected</param>
        /// <param name="obj">IContractConfiguratorFactory object for error reporting</param>
        /// <returns>Whether the validation succeeded, additionally logs an error on failure.</returns>
        public static bool ValidateMandatoryChild(ConfigNode configNode, string field, IContractConfiguratorFactory obj)
        {
            if (!configNode.HasNode(field))
            {
                LoggingUtil.LogError(obj.GetType(), obj.ErrorPrefix() +
                                     ": missing required child node '" + field + "'.");
                return(false);
            }

            return(true);
        }
        /// <summary>
        /// Generates a ContractRequirement from a configuration node.
        /// </summary>
        /// <param name="configNode">ConfigNode to use in the generation.</param>
        /// <param name="contractType">ContractType that this requirement falls under</param>
        /// <param name="requirement">The ContractRequirement object.</param>
        /// <returns>Whether the load was successful</returns>
        public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement,
            IContractConfiguratorFactory parent = null)
        {
            // Logging on
            LoggingUtil.CaptureLog = true;
            bool valid = true;

            // Get the type
            string type = configNode.GetValue("type");
            string name = configNode.HasValue("name") ? configNode.GetValue("name") : type;
            if (string.IsNullOrEmpty(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," +
                    "REQUIREMENT '" + configNode.GetValue("name") + "' does not specify the mandatory 'type' attribute.");
                requirement = new InvalidContractRequirement();
                valid = false;
            }
            else if (!requirementTypes.ContainsKey(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," +
                    "REQUIREMENT '" + configNode.GetValue("name") + "' of type '" + configNode.GetValue("type") + "': " +
                    "Unknown requirement '" + type + "'.");
                requirement = new InvalidContractRequirement();
                valid = false;
            }
            else
            {
                // Create an instance of the ContractRequirement
                requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]);
            }

            // Set attributes
            requirement.contractType = contractType;
            requirement.dataNode = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement);

            // Load config
            valid &= requirement.Load(configNode);

            // Check for unexpected values - always do this last
            if (requirement.GetType() != typeof(InvalidContractRequirement))
            {
                valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement);
            }

            // Load child nodes
            foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT"))
            {
                ContractRequirement child = null;
                valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement);
                if (child != null)
                {
                    requirement.childNodes.Add(child);
                    if (child.hasWarnings)
                    {
                        requirement.hasWarnings = true;
                    }
                }
            }

            requirement.enabled = valid;
            requirement.log = LoggingUtil.capturedLog;
            LoggingUtil.CaptureLog = false;

            return valid;
        }
        /// <summary>
        /// Attempts to parse a value from the config node.  Returns a default value if not found.
        /// </summary>
        /// <typeparam name="T">The type of value to convert to.</typeparam>
        /// <param name="configNode">The ConfigNode to read from.</param>
        /// <param name="key">The key to examine.</param>
        /// <param name="setter">Function used to set the output value</param>
        /// <param name="obj">Factory object for error messages.</param>
        /// <returns>The parsed value (or default value if not found)</returns>
        public static bool ParseValue <T>(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj)
        {
            // Check for required value
            if (!configNode.HasValue(key) && !configNode.HasNode(key))
            {
                LoggingUtil.LogError(obj, "{0}: Missing required value '{1}'.", obj.ErrorPrefix(configNode), key);
                return(false);
            }

            return(ParseValue <T>(configNode, key, setter, obj, default(T), x => true));
        }
        /// <summary>
        /// Loads the ITERATOR nodes.
        /// </summary>
        /// <param name="node"></param>
        /// <returns>Whether the load was successful</returns>
        public static bool LoadIteratorNodes(ConfigNode node, IContractConfiguratorFactory obj)
        {
            bool valid = true;

            IEnumerable<ConfigNode> iteratorNodes = ConfigNodeUtil.GetChildNodes(node, "ITERATOR");
            if (!iteratorNodes.Any())
            {
                return true;
            }
            else if (iteratorNodes.Count() > 1)
            {
                LoggingUtil.LogError(obj, "Multiple ITERATOR nodes found - only one iterator node allowed.");
                return false;
            }

            ConfigNode iteratorNode = iteratorNodes.First();
            DataNode iteratorDataNode = new DataNode("ITERATOR", obj.dataNode, obj);
            try
            {
                ConfigNodeUtil.SetCurrentDataNode(iteratorDataNode);

                valid &= ConfigNodeUtil.ParseValue<Type>(iteratorNode, "type", x => obj.iteratorType = x, obj);
                if (obj.iteratorType != null)
                {
                    foreach (ConfigNode.Value pair in iteratorNode.values)
                    {
                        string name = pair.name;
                        if (name != "type")
                        {
                            if (!string.IsNullOrEmpty(obj.iteratorKey))
                            {
                                LoggingUtil.LogError(obj, "Multiple key values found in ITERATOR node - only one key allowed.");
                                return false;
                            }

                            // Create the list type
                            Type listType = typeof(List<>);
                            listType = listType.MakeGenericType(new Type[] { obj.iteratorType });

                            // Create the setter function
                            object value = null;
                            Type listActionType = typeof(Action<>).MakeGenericType(listType);
                            Delegate listDelegate = Delegate.CreateDelegate(listActionType, value, typeof(DataNode).GetMethod("NullAction"));

                            // Get the ParseValue method
                            MethodInfo parseListMethod = parseMethodGeneric.MakeGenericMethod(new Type[] { listType });

                            // Invoke the ParseValue method
                            valid &= (bool)parseListMethod.Invoke(null, new object[] { iteratorNode, name, listDelegate, obj });

                            // Store the iterator key for later
                            obj.iteratorKey = name;
                        }
                    }
                }

                // Load didn't get us a key
                if (string.IsNullOrEmpty(obj.iteratorKey))
                {
                    LoggingUtil.LogError(obj, "No key field was defined for the ITERATOR!.");
                    return false;
                }
            }
            finally
            {
                ConfigNodeUtil.SetCurrentDataNode(obj.dataNode);
            }

            // Add a dummy value to the parent data node
            node.AddValue(obj.iteratorKey, "@ITERATOR/" + obj.iteratorKey + ".ElementAt(IteratorCurrentIndex())");
            node.AddValue("iteratorCount", "@ITERATOR/" + obj.iteratorKey + ".Count()");

            return valid;
        }
예제 #21
0
 public DataNode(string name, IContractConfiguratorFactory factory)
     : this(name, null, factory)
 {
 }
예제 #22
0
        /// <summary>
        /// Attempts to parse a value from the config node.  Validates return values using the
        /// given function.
        /// </summary>
        /// <typeparam name="T">The type of value to convert to.</typeparam>
        /// <param name="configNode">The ConfigNode to read from.</param>
        /// <param name="key">The key to examine.</param>
        /// <param name="setter">Function used to set the output value</param>
        /// <param name="obj">Factory object for error messages.</param>
        /// <param name="validation">Validation function to run against the returned value</param>
        /// <returns>The parsed value (or default value if not found)</returns>
        public static bool ParseValue <T>(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj, Func <T, bool> validation)
        {
            // Check for required value
            if (!configNode.HasValue(key) && !configNode.HasNode(key))
            {
                LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Missing required value '" + key + "'.");
                return(false);
            }

            return(ParseValue <T>(configNode, key, setter, obj, default(T), validation));
        }
예제 #23
0
        /// <summary>
        /// Generates a ContractRequirement from a configuration node.
        /// </summary>
        /// <param name="configNode">ConfigNode to use in the generation.</param>
        /// <param name="contractType">ContractType that this requirement falls under</param>
        /// <param name="requirement">The ContractRequirement object.</param>
        /// <returns>Whether the load was successful</returns>
        public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement,
                                               IContractConfiguratorFactory parent = null)
        {
            // Logging on
            LoggingUtil.CaptureLog = true;
            bool valid = true;

            // Get the type
            string type = configNode.GetValue("type");
            string name = configNode.HasValue("name") ? configNode.GetValue("name") : type;

            if (string.IsNullOrEmpty(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '{0}', REQUIREMENT '{1}' does not specify the mandatory 'type' attribute.",
                                     contractType.name, configNode.GetValue("name"));
                requirement = new InvalidContractRequirement();
                valid       = false;
            }
            else if (!requirementTypes.ContainsKey(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '{0}', REQUIREMENT '{1}' of type '{2}': Unknown requirement '{3}'.",
                                     contractType.name, configNode.GetValue("name"), configNode.GetValue("type"), type);
                requirement = new InvalidContractRequirement();
                valid       = false;
            }
            else
            {
                // Create an instance of the ContractRequirement
                requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]);
            }

            // Set attributes
            requirement.contractType = contractType;
            requirement.dataNode     = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement);

            // Load config
            valid &= requirement.LoadFromConfig(configNode);

            // Override the needsTitle if we have a parent node with hideChildren
            ContractRequirement parentRequirement = parent as ContractRequirement;

            if (parentRequirement != null)
            {
                if (parentRequirement.hideChildren)
                {
                    requirement.hideChildren = true;
                    requirement.needsTitle   = false;
                }
            }

            // Check for unexpected values - always do this last
            if (requirement.GetType() != typeof(InvalidContractRequirement))
            {
                valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement);
            }

            // Load child nodes
            foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT"))
            {
                ContractRequirement child = null;
                valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement);
                if (child != null)
                {
                    requirement.childNodes.Add(child);
                    if (child.hasWarnings)
                    {
                        requirement.hasWarnings = true;
                    }
                }
            }

            // Error for missing title
            if (requirement.needsTitle && string.IsNullOrEmpty(requirement.title))
            {
                valid = contractType.minVersion < ContractConfigurator.ENHANCED_UI_VERSION;
                LoggingUtil.Log(contractType.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING,
                                requirement, "{0}: missing required attribute 'title'.", requirement.ErrorPrefix(configNode));
            }

            requirement.enabled    = valid;
            requirement.log        = LoggingUtil.capturedLog;
            LoggingUtil.CaptureLog = false;

            return(valid);
        }
        /// <summary>
        /// Generates a ContractRequirement from a configuration node.
        /// </summary>
        /// <param name="configNode">ConfigNode to use in the generation.</param>
        /// <param name="contractType">ContractType that this requirement falls under</param>
        /// <param name="requirement">The ContractRequirement object.</param>
        /// <returns>Whether the load was successful</returns>
        public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement,
            IContractConfiguratorFactory parent = null)
        {
            // Logging on
            LoggingUtil.CaptureLog = true;
            bool valid = true;

            // Get the type
            string type = configNode.GetValue("type");
            string name = configNode.HasValue("name") ? configNode.GetValue("name") : type;
            if (string.IsNullOrEmpty(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," +
                    "REQUIREMENT '" + configNode.GetValue("name") + "' does not specify the mandatory 'type' attribute.");
                requirement = new InvalidContractRequirement();
                valid = false;
            }
            else if (!requirementTypes.ContainsKey(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," +
                    "REQUIREMENT '" + configNode.GetValue("name") + "' of type '" + configNode.GetValue("type") + "': " +
                    "Unknown requirement '" + type + "'.");
                requirement = new InvalidContractRequirement();
                valid = false;
            }
            else
            {
                // Create an instance of the ContractRequirement
                requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]);
            }

            // Set attributes
            requirement.contractType = contractType;
            requirement.dataNode = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement);

            // Load config
            valid &= requirement.LoadFromConfig(configNode);

            // Override the needsTitle if we have a parent node with hideChildren
            ContractRequirement parentRequirement = parent as ContractRequirement;
            if (parentRequirement != null)
            {
                if (parentRequirement.hideChildren)
                {
                    requirement.hideChildren = true;
                    requirement.needsTitle = false;
                }
            }

            // Check for unexpected values - always do this last
            if (requirement.GetType() != typeof(InvalidContractRequirement))
            {
                valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement);
            }

            // Load child nodes
            foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT"))
            {
                ContractRequirement child = null;
                valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement);
                if (child != null)
                {
                    requirement.childNodes.Add(child);
                    if (child.hasWarnings)
                    {
                        requirement.hasWarnings = true;
                    }
                }
            }

            // Error for missing title
            if (requirement.needsTitle && string.IsNullOrEmpty(requirement.title))
            {
                valid = contractType.minVersion < ContractConfigurator.ENHANCED_UI_VERSION;
                LoggingUtil.Log(contractType.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING,
                    requirement, requirement.ErrorPrefix(configNode) + ": missing required attribute 'title'.");
            }

            requirement.enabled = valid;
            requirement.log = LoggingUtil.capturedLog;
            LoggingUtil.CaptureLog = false;

            return valid;
        }
예제 #25
0
 /*
  * Attempts to parse a value from the config node.  Returns a default value if not found.
  * Validates return values using the given function.
  */
 public static bool ParseValue <T>(ConfigNode configNode, string key, ref T value, IContractConfiguratorFactory obj, T defaultValue, Func <T, bool> validation)
 {
     if (ParseValue <T>(configNode, key, ref value, obj, defaultValue))
     {
         try
         {
             if (!validation.Invoke(value))
             {
                 // In general, the validation function should throw an exception and give a much better message
                 LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": The value supplied for " + key + " (" + value + ") is invalid.");
                 return(false);
             }
         }
         catch (Exception e)
         {
             LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": The value supplied for " + key + " (" + value + ") is invalid: " + e.Message);
             LoggingUtil.LogDebug(obj, e.StackTrace);
             return(false);
         }
         return(true);
     }
     return(false);
 }
예제 #26
0
 /*
  * Attempts to parse a value from the config node.  Returns a default value if not found.
  */
 public static bool ParseValue <T>(ConfigNode configNode, string key, ref T value, IContractConfiguratorFactory obj, T defaultValue)
 {
     if (configNode.HasValue(key))
     {
         return(ParseValue <T>(configNode, key, ref value, obj));
     }
     else
     {
         value = defaultValue;
         return(true);
     }
 }
예제 #27
0
 /*
  * Attempts to parse a value from the config node.
  */
 public static bool ParseValue <T>(ConfigNode configNode, string key, ref T value, IContractConfiguratorFactory obj)
 {
     try
     {
         value = ParseValue <T>(configNode, key);
         return(value != null);
     }
     catch (Exception e)
     {
         LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Error parsing " + key + ": " + configNode.id + e.Message);
         LoggingUtil.LogDebug(obj, e.StackTrace);
         return(false);
     }
     finally
     {
         AddFoundKey(configNode, key);
     }
 }
예제 #28
0
        /// <summary>
        /// Attempts to parse a value from the config node.  Returns a default value if not found.
        /// Validates return values using the given function.
        /// </summary>
        /// <typeparam name="T">The type of value to convert to.</typeparam>
        /// <param name="configNode">The ConfigNode to read from.</param>
        /// <param name="key">The key to examine.</param>
        /// <param name="setter">Function used to set the output value</param>
        /// <param name="obj">Factory object for error messages.</param>
        /// <param name="defaultValue">Default value to use if there is no key in the config node</param>
        /// <param name="validation">Validation function to run against the returned value</param>
        /// <returns>The parsed value (or default value if not found)</returns>
        public static bool ParseValue <T>(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj, T defaultValue, Func <T, bool> validation)
        {
            // Initialize the data type of the expression
            if (currentDataNode != null && !currentDataNode.IsInitialized(key))
            {
                currentDataNode.BlankInit(key, typeof(T));
            }

            bool valid = true;
            T    value = defaultValue;

            if (configNode.HasValue(key) || configNode.HasNode(key))
            {
                try
                {
                    // Check whether there's a value
                    if (configNode.HasValue(key) && string.IsNullOrEmpty(configNode.GetValue(key)))
                    {
                        LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Required value '" + key + "' is empty.");
                        valid = false;
                    }
                    else
                    {
                        // Load value
                        value = ParseValue <T>(configNode, key, true);
                    }

                    // If value was non-null, run validation
                    if (value != null && (typeof(T) != typeof(string) || ((string)(object)value) != ""))
                    {
                        try
                        {
                            valid = validation.Invoke(value);
                            if (!valid)
                            {
                                // In general, the validation function should throw an exception and give a much better message
                                LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": A validation error occured while loading the key '" + key + "' with value '" + value + "'.");
                            }
                        }
                        catch (Exception e)
                        {
                            if (e is DataNode.ValueNotInitialized)
                            {
                                throw;
                            }

                            LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": A validation error occured while loading the key '" + key + "' with value '" + value + "'.");
                            LoggingUtil.LogException(e);
                            valid = false;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (e.GetType() == typeof(DataNode.ValueNotInitialized))
                    {
                        string dependency = ((DataNode.ValueNotInitialized)e).key;
                        string path       = currentDataNode.Path() + key;

                        LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), "Trying to load " + path + ", but " + dependency + " is uninitialized.");

                        // Defer loading this value
                        DeferredLoadObject <T> loadObj = null;
                        if (!deferredLoads.ContainsKey(path) || deferredLoads[path].GetType().GetGenericArguments().First() != typeof(T))
                        {
                            deferredLoads[path] = new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode);
                        }
                        loadObj = (DeferredLoadObject <T>)deferredLoads[path];

                        // New dependency - try again
                        if (!loadObj.dependencies.Contains(dependency))
                        {
                            LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), "    New dependency, will re-attempt to load later.");
                            loadObj.dependencies.Add(dependency);
                            return(true);
                        }
                    }

                    LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Error parsing " + key);

                    // Return immediately on deferred load error
                    if (e.GetType() == typeof(DataNode.ValueNotInitialized))
                    {
                        DataNode.ValueNotInitialized vni = e as DataNode.ValueNotInitialized;
                        LoggingUtil.LogException(new Exception("Unknown identifier '@" + vni.key + "'."));
                        return(false);
                    }
                    LoggingUtil.LogException(e);

                    valid = false;
                }
                finally
                {
                    AddFoundKey(configNode, key);
                }
            }

            // Store the value
            if (currentDataNode != null)
            {
                currentDataNode[key] = value;

                if (!currentDataNode.IsDeterministic(key) && initialLoad)
                {
                    currentDataNode.DeferredLoads.Add(new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode));
                }
            }

            // Invoke the setter function
            if (valid)
            {
                setter.Invoke(value);
            }

            return(valid);
        }
예제 #29
0
        /// <summary>
        /// Parses the child DATA nodes out of the given config node, and returns the parsed values back in dataValues.
        /// </summary>
        /// <param name="configNode">The ConfigNode to load child DATA nodes from.</param>
        /// <param name="obj">The ContractConfigurator object to load from.</param>
        /// <param name="dataValues"></param>
        /// <param name="uniquenessChecks"></param>
        /// <returns></returns>
        public bool ParseDataNodes(ConfigNode configNode, IContractConfiguratorFactory obj,
                                   Dictionary <string, ContractType.DataValueInfo> dataValues, Dictionary <string, UniquenessCheck> uniquenessChecks)
        {
            bool valid = true;

            foreach (ConfigNode data in ConfigNodeUtil.GetChildNodes(configNode, "DATA"))
            {
                Type   type          = null;
                bool   requiredValue = true;
                bool   hidden        = true;
                bool   isLiteral     = false;
                string title         = "";

                ConfigNodeUtil.SetCurrentDataNode(null);
                valid &= ConfigNodeUtil.ParseValue <Type>(data, "type", x => type = x, obj);
                valid &= ConfigNodeUtil.ParseValue <bool>(data, "requiredValue", x => requiredValue = x, obj, true);
                valid &= ConfigNodeUtil.ParseValue <string>(data, "title", x => title = x, obj, "");
                valid &= ConfigNodeUtil.ParseValue <bool>(data, "hidden", x => hidden = x, obj, false);
                valid &= ConfigNodeUtil.ParseValue <bool>(data, "isLiteral", x => isLiteral = x, obj, false);

                bool doneTitleWarning = false;

                UniquenessCheck uniquenessCheck = UniquenessCheck.NONE;
                // Backwards compatibility for Contract Configurator 1.8.3
                if (data.HasValue("uniqueValue") || data.HasValue("activeUniqueValue"))
                {
                    LoggingUtil.LogWarning(this, "The use of uniqueValue and activeUniqueValue is obsolete since Contract Configurator 1.9.0, use uniquenessCheck instead.");

                    bool uniqueValue       = false;
                    bool activeUniqueValue = false;
                    valid &= ConfigNodeUtil.ParseValue <bool>(data, "uniqueValue", x => uniqueValue = x, obj, false);
                    valid &= ConfigNodeUtil.ParseValue <bool>(data, "activeUniqueValue", x => activeUniqueValue = x, obj, false);

                    uniquenessCheck = activeUniqueValue ? UniquenessCheck.CONTRACT_ACTIVE : uniqueValue ? UniquenessCheck.CONTRACT_ALL : UniquenessCheck.NONE;
                }
                else
                {
                    valid &= ConfigNodeUtil.ParseValue <UniquenessCheck>(data, "uniquenessCheck", x => uniquenessCheck = x, obj, UniquenessCheck.NONE);
                }

                ConfigNodeUtil.SetCurrentDataNode(this);

                if (type != null)
                {
                    foreach (ConfigNode.Value pair in data.values)
                    {
                        string name = pair.name;
                        if (name != "type" && name != "title" && name != "hidden" && name != "requiredValue" && name != "uniqueValue" && name != "activeUniqueValue" && name != "uniquenessCheck" && name != "isLiteral")
                        {
                            if (uniquenessCheck != UniquenessCheck.NONE)
                            {
                                uniquenessChecks[name] = uniquenessCheck;
                            }

                            object value = null;

                            // Create the setter function
                            Type     actionType = typeof(Action <>).MakeGenericType(type);
                            Delegate del        = Delegate.CreateDelegate(actionType, value, typeof(DataNode).GetMethod("NullAction"));

                            // Set the ParseValue method generic
                            MethodInfo method = (isLiteral ? methodParseValueLiteral : methodParseValue).MakeGenericMethod(new Type[] { type });

                            // Invoke the ParseValue method
                            if (isLiteral)
                            {
                                this[name] = method.Invoke(null, new object[] { data, name, false });
                            }
                            else
                            {
                                valid &= (bool)method.Invoke(null, new object[] { data, name, del, obj });
                            }

                            dataValues[name] = new ContractType.DataValueInfo(title, requiredValue, hidden, type);

                            // Recommend a title
                            if (!data.HasValue("title") && requiredValue && !IsDeterministic(name) && !hidden && !doneTitleWarning && !dataValues[name].IsIgnoredType())
                            {
                                doneTitleWarning = true;

                                LoggingUtil.Log(obj.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION ? LoggingUtil.LogLevel.ERROR : LoggingUtil.LogLevel.WARNING, this,
                                                obj.ErrorPrefix() + ": " + name + ": The field 'title' is required in for data node values where 'requiredValue' is true.  Alternatively, the attribute 'hidden' can be set to true (but be careful - this can cause player confusion if all lines for the contract type show as 'Met' and the contract isn't generating).");

                                // Error on newer versions of contract packs
                                if (obj.minVersion >= ContractConfigurator.ENHANCED_UI_VERSION)
                                {
                                    valid = false;
                                }
                            }
                        }
                    }
                }
            }

            return(valid);
        }
예제 #30
0
        /// <summary>
        /// Ensures that the config node does not have items from the two mutually exclusive groups.
        /// </summary>
        /// <param name="configNode">The configNode to verify.</param>
        /// <param name="group1">The first group of keys.</param>
        /// <param name="group2">The second group of keys</param>
        /// <param name="obj">IContractConfiguratorFactory for logging</param>
        /// <returns>Whether the condition is satisfied</returns>
        public static bool MutuallyExclusive(ConfigNode configNode, string[] group1, string[] group2, IContractConfiguratorFactory obj)
        {
            string group1String = "";
            string group2String = "";
            bool   group1Value  = false;
            bool   group2Value  = false;

            foreach (string value in group1)
            {
                if (configNode.HasValue(value))
                {
                    group1Value = true;
                }

                if (value == group1.First())
                {
                    group1String = value;
                }
                else
                {
                    group1String += ", " + value;
                }
            }
            foreach (string value in group2)
            {
                if (configNode.HasValue(value))
                {
                    group2Value = true;
                }

                if (value == group2.First())
                {
                    group2String = value;
                }
                else
                {
                    group2String += ", " + value;
                }
            }

            if (group1Value && group2Value)
            {
                LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": The values " + group1String + " and " + group2String + " are mutually exclusive.");
                return(false);
            }

            return(true);
        }
예제 #31
0
        protected static T SelectUnique(List <T> input)
        {
            // Check if there's no values
            if (input == null || !input.Any())
            {
                return(default(T));
            }

            // Get details from the base parser
            ContractType contractType = BaseParser.currentParser.currentDataNode.Root.Factory as ContractType;
            string       key          = BaseParser.currentParser.currentKey;

            DataNode.UniquenessCheck uniquenessCheck = contractType.uniquenessChecks.ContainsKey(key) ? contractType.uniquenessChecks[key] : DataNode.UniquenessCheck.NONE;
            DataNode dataNode = BaseParser.currentParser.currentDataNode;

            // Provide warning of a better method
            if (dataNode != null && dataNode.IsDeterministic(key) && (uniquenessCheck == DataNode.UniquenessCheck.CONTRACT_ALL || uniquenessCheck == DataNode.UniquenessCheck.CONTRACT_ACTIVE))
            {
                IContractConfiguratorFactory factory = BaseParser.currentParser.currentDataNode.Factory;
                LoggingUtil.LogWarning(factory, factory.ErrorPrefix() + ": Consider using a DATA_EXPAND node instead of the SelectUnique function when the values are deterministic - this will cause the player to see the full set of values in mission control before the contract is offered.");
            }

            // Check for properly uniquness check
            if (uniquenessCheck == DataNode.UniquenessCheck.NONE)
            {
                throw new NotSupportedException("The SelectUnique method can only be used in DATA nodes with the uniquenessCheck attribute set.");
            }

            // Get the active/offered contract lists
            IEnumerable <ConfiguredContract> contractList = ConfiguredContract.CurrentContracts.
                                                            Where(c => c != null && c.contractType != null);

            // Add in finished contracts
            if (uniquenessCheck == DataNode.UniquenessCheck.CONTRACT_ALL || uniquenessCheck == DataNode.UniquenessCheck.GROUP_ALL)
            {
                contractList = contractList.Union(ConfiguredContract.CompletedContracts.
                                                  Where(c => c != null && c.contractType != null));
            }

            // Filter anything that doesn't have our key
            contractList = contractList.Where(c => c.uniqueData.ContainsKey(key));

            // Check for contracts of the same type
            if (uniquenessCheck == DataNode.UniquenessCheck.CONTRACT_ALL || uniquenessCheck == DataNode.UniquenessCheck.CONTRACT_ACTIVE)
            {
                contractList = contractList.Where(c => c.contractType.name == contractType.name);
            }
            // Check for a shared group
            else if (contractType.group != null)
            {
                contractList = contractList.Where(c => c.contractType.group != null && c.contractType.group.name == contractType.group.name);
            }
            // Shared lack of group
            else
            {
                contractList = contractList.Where(c => c.contractType.group == null);
            }

            // Get the valid values
            IEnumerable <T> values;

            // Special case for vessels
            if (typeof(T) == typeof(Vessel))
            {
                values = input.Where(t => !contractList.Any(c => c.uniqueData[key].Equals(((Vessel)(object)t).id)));
            }
            else
            {
                values = input.Where(t => !contractList.Any(c => c.uniqueData[key].Equals(t)));
            }

            // Make a random selection from what's left
            return(values.Skip(r.Next(values.Count())).FirstOrDefault());
        }
예제 #32
0
 public DataNode(string name, IContractConfiguratorFactory factory)
     : this(name, null, factory)
 {
 }
        public static bool InitializeIteratorKey(ConfigNode node, IContractConfiguratorFactory obj)
        {
            bool valid = true;

            // Nothing to do
            if (obj.iteratorType == null)
            {
                return true;
            }

            // Set the correct data node
            ConfigNodeUtil.SetCurrentDataNode(obj.dataNode);

            // First initalize our iterator count variable (no reflection needed)
            valid &= ConfigNodeUtil.ParseValue<int>(node, "iteratorCount", x => { }, obj);

            // Check if it already exists (happens when using the an existing value for a key)
            if (obj.dataNode.data.ContainsKey(obj.iteratorKey))
            {
                return valid;
            }

            // Create the setter function
            object value = null;
            Type actionType = typeof(Action<>).MakeGenericType(obj.iteratorType);
            Delegate del = Delegate.CreateDelegate(actionType, value, typeof(DataNode).GetMethod("NullAction"));

            // Invoke the ParseValue method
            MethodInfo parseMethod = parseMethodGeneric.MakeGenericMethod(new Type[] { obj.iteratorType });
            valid &= (bool)parseMethod.Invoke(null, new object[] { node, obj.iteratorKey, del, obj });

            return valid;
        }
예제 #34
0
        /// <summary>
        /// Loads the ITERATOR nodes.
        /// </summary>
        /// <param name="node"></param>
        /// <returns>Whether the load was successful</returns>
        public static bool LoadIteratorNodes(ConfigNode node, IContractConfiguratorFactory obj)
        {
            bool valid = true;

            IEnumerable <ConfigNode> iteratorNodes = ConfigNodeUtil.GetChildNodes(node, "ITERATOR");

            if (!iteratorNodes.Any())
            {
                return(true);
            }
            else if (iteratorNodes.Count() > 1)
            {
                LoggingUtil.LogError(obj, "Multiple ITERATOR nodes found - only one iterator node allowed.");
                return(false);
            }

            ConfigNode iteratorNode     = iteratorNodes.First();
            DataNode   iteratorDataNode = new DataNode("ITERATOR", obj.dataNode, obj);

            try
            {
                ConfigNodeUtil.SetCurrentDataNode(iteratorDataNode);

                valid &= ConfigNodeUtil.ParseValue <Type>(iteratorNode, "type", x => obj.iteratorType = x, obj);
                if (obj.iteratorType != null)
                {
                    foreach (ConfigNode.Value pair in iteratorNode.values)
                    {
                        string name = pair.name;
                        if (name != "type")
                        {
                            if (!string.IsNullOrEmpty(obj.iteratorKey))
                            {
                                LoggingUtil.LogError(obj, "Multiple key values found in ITERATOR node - only one key allowed.");
                                return(false);
                            }

                            // Create the list type
                            Type listType = typeof(List <>);
                            listType = listType.MakeGenericType(new Type[] { obj.iteratorType });

                            // Create the setter function
                            object   value          = null;
                            Type     listActionType = typeof(Action <>).MakeGenericType(listType);
                            Delegate listDelegate   = Delegate.CreateDelegate(listActionType, value, typeof(DataNode).GetMethod("NullAction"));

                            // Get the ParseValue method
                            MethodInfo parseListMethod = parseMethodGeneric.MakeGenericMethod(new Type[] { listType });

                            // Invoke the ParseValue method
                            valid &= (bool)parseListMethod.Invoke(null, new object[] { iteratorNode, name, listDelegate, obj });

                            // Store the iterator key for later
                            obj.iteratorKey = name;
                        }
                    }
                }

                // Load didn't get us a key
                if (string.IsNullOrEmpty(obj.iteratorKey))
                {
                    LoggingUtil.LogError(obj, "No key field was defined for the ITERATOR!.");
                    return(false);
                }
            }
            finally
            {
                ConfigNodeUtil.SetCurrentDataNode(obj.dataNode);
            }

            // Add a dummy value to the parent data node
            node.AddValue(obj.iteratorKey, "@ITERATOR/" + obj.iteratorKey + ".ElementAt(IteratorCurrentIndex())");
            node.AddValue("iteratorCount", "@ITERATOR/" + obj.iteratorKey + ".Count()");

            return(valid);
        }
        /// <summary>
        /// Outputs the debugging info for the debug window.
        /// </summary>
        static string DebugInfo(IContractConfiguratorFactory obj)
        {
            if (obj.dataNode == null)
            {
                return "";
            }

            if (!toolTipCache.ContainsKey(obj) || toolTipCache[obj].Key != obj.dataNode.lastModified)
            {
                string result = "";
                result += "<b><color=white>Config Node Details</color></b>\n";
                result += obj.config;
                result += "\n\n";
                result += "<b><color=white>Config Details After Expressions</color></b>\n";
                result += DataNodeDebug(obj.dataNode) + "\n";
                result += "<b><color=white>Log Details</color></b>\n";
                result += obj.log;

                toolTipCache[obj] = new KeyValuePair<double,string>(obj.dataNode.lastModified, result);
            }

            return toolTipCache[obj].Value;
        }
예제 #36
0
        /// <summary>
        /// Parses the child DATA nodes out of the given config node, and returns the parsed values back in dataValues.
        /// </summary>
        /// <param name="configNode">The ConfigNode to load child DATA nodes from.</param>
        /// <param name="obj">The ContractConfigurator object to load from.</param>
        /// <param name="dataValues"></param>
        /// <param name="uniqueValues"></param>
        /// <returns></returns>
        public static bool ParseDataNodes(ConfigNode configNode, IContractConfiguratorFactory obj,
            Dictionary<string, bool> dataValues, Dictionary<string, bool> uniqueValues)
        {
            bool valid = true;

            foreach (ConfigNode data in ConfigNodeUtil.GetChildNodes(configNode, "DATA"))
            {
                Type type = null;
                bool requiredValue = true;
                bool uniqueValue = false;
                bool activeUniqueValue = false;
                valid &= ConfigNodeUtil.ParseValue<Type>(data, "type", x => type = x, obj);
                valid &= ConfigNodeUtil.ParseValue<bool>(data, "requiredValue", x => requiredValue = x, obj, true);
                valid &= ConfigNodeUtil.ParseValue<bool>(data, "uniqueValue", x => uniqueValue = x, obj, false);
                valid &= ConfigNodeUtil.ParseValue<bool>(data, "activeUniqueValue", x => activeUniqueValue = x, obj, false);

                if (type != null)
                {
                    foreach (ConfigNode.Value pair in data.values)
                    {
                        string name = pair.name;
                        if (name != "type" && name != "requiredValue" && name != "uniqueValue" && name != "activeUniqueValue")
                        {
                            object value = null;

                            // Create the setter function
                            Type actionType = typeof(Action<>).MakeGenericType(type);
                            Delegate del = Delegate.CreateDelegate(actionType, value, typeof(ContractType).GetMethod("NullAction"));

                            // Get the ParseValue method
                            MethodInfo method = typeof(ConfigNodeUtil).GetMethods(BindingFlags.Static | BindingFlags.Public).
                                Where(m => m.Name == "ParseValue" && m.GetParameters().Count() == 4).Single();
                            method = method.MakeGenericMethod(new Type[] { type });

                            // Invoke the ParseValue method
                            valid &= (bool)method.Invoke(null, new object[] { data, name, del, obj });

                            dataValues[name] = requiredValue;

                            if (uniqueValue || activeUniqueValue)
                            {
                                uniqueValues[name] = activeUniqueValue;
                            }
                        }
                    }
                }
            }

            return valid;
        }
예제 #37
0
        /// <summary>
        /// Attempts to parse a value from the config node.  Returns a default value if not found.
        /// Validates return values using the given function.
        /// </summary>
        /// <typeparam name="T">The type of value to convert to.</typeparam>
        /// <param name="configNode">The ConfigNode to read from.</param>
        /// <param name="key">The key to examine.</param>
        /// <param name="setter">Function used to set the output value</param>
        /// <param name="obj">Factory object for error messages.</param>
        /// <param name="defaultValue">Default value to use if there is no key in the config node</param>
        /// <param name="validation">Validation function to run against the returned value</param>
        /// <returns>The parsed value (or default value if not found)</returns>
        public static bool ParseValue <T>(ConfigNode configNode, string key, Action <T> setter, IContractConfiguratorFactory obj, T defaultValue, Func <T, bool> validation)
        {
            // Initialize the data type of the expression
            if (currentDataNode != null && !currentDataNode.IsInitialized(key))
            {
                currentDataNode.BlankInit(key, typeof(T));
            }

            bool valid = true;
            T    value = defaultValue;

            if (configNode.HasValue(key))
            {
                try
                {
                    // Load value
                    value = ParseValue <T>(configNode, key, true);

                    // If value was non-null, run validation
                    if (value != null)
                    {
                        try
                        {
                            valid = validation.Invoke(value);
                            if (!valid)
                            {
                                // In general, the validation function should throw an exception and give a much better message
                                LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": The value supplied for " + key + " (" + value + ") is invalid.");
                            }
                        }
                        catch (Exception e)
                        {
                            LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": The value supplied for " + key + " (" + value + ") is invalid.");
                            LoggingUtil.LogException(e);
                            valid = false;
                        }
                    }
                }
                catch (Exception e)
                {
                    if (e.GetType() == typeof(DataNode.ValueNotInitialized))
                    {
                        string dependency = ((DataNode.ValueNotInitialized)e).key;
                        string path       = currentDataNode.Path() + key;

                        LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), "Trying to load " + key + ", but " + dependency + " is uninitialized.");

                        // Defer loading this value
                        DeferredLoadObject <T> loadObj = null;
                        if (!deferredLoads.ContainsKey(path))
                        {
                            deferredLoads[path] = new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode);
                        }
                        loadObj = (DeferredLoadObject <T>)deferredLoads[path];

                        // New dependency - try again
                        if (!loadObj.dependencies.Contains(dependency))
                        {
                            LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), "    New dependency, will re-attempt to load later.");
                            loadObj.dependencies.Add(dependency);
                            return(true);
                        }
                    }

                    LoggingUtil.LogError(obj, obj.ErrorPrefix(configNode) + ": Error parsing " + key);
                    LoggingUtil.LogException(e);

                    // Return immediately on deferred load error
                    if (e.GetType() == typeof(DataNode.ValueNotInitialized))
                    {
                        return(false);
                    }

                    valid = false;
                }
                finally
                {
                    AddFoundKey(configNode, key);
                }
            }

            // Store the value
            if (currentDataNode != null)
            {
                LoggingUtil.LogVerbose(typeof(ConfigNodeUtil), "DataNode[" + currentDataNode.Name + "], storing " + key + " = " + value);
                currentDataNode[key] = value;

                if (!currentDataNode.IsDeterministic(key) && initialLoad)
                {
                    currentDataNode.DeferredLoads.Add(new DeferredLoadObject <T>(configNode, key, setter, obj, validation, currentDataNode));
                }
            }

            // Invoke the setter function
            if (valid)
            {
                setter.Invoke(value);
            }

            return(valid);
        }
예제 #38
0
        /// <summary>
        /// Generates a ContractRequirement from a configuration node.
        /// </summary>
        /// <param name="configNode">ConfigNode to use in the generation.</param>
        /// <param name="contractType">ContractType that this requirement falls under</param>
        /// <param name="requirement">The ContractRequirement object.</param>
        /// <returns>Whether the load was successful</returns>
        public static bool GenerateRequirement(ConfigNode configNode, ContractType contractType, out ContractRequirement requirement,
                                               IContractConfiguratorFactory parent = null)
        {
            // Logging on
            LoggingUtil.CaptureLog = true;
            bool valid = true;

            // Get the type
            string type = configNode.GetValue("type");
            string name = configNode.HasValue("name") ? configNode.GetValue("name") : type;

            if (string.IsNullOrEmpty(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," +
                                     "REQUIREMENT '" + configNode.GetValue("name") + "' does not specify the mandatory 'type' attribute.");
                requirement = new InvalidContractRequirement();
                valid       = false;
            }
            else if (!requirementTypes.ContainsKey(type))
            {
                LoggingUtil.LogError(typeof(ParameterFactory), "CONTRACT_TYPE '" + contractType.name + "'," +
                                     "REQUIREMENT '" + configNode.GetValue("name") + "' of type '" + configNode.GetValue("type") + "': " +
                                     "No ContractRequirement has been registered for type '" + type + "'.");
                requirement = new InvalidContractRequirement();
                valid       = false;
            }
            else
            {
                // Create an instance of the ContractRequirement
                requirement = (ContractRequirement)Activator.CreateInstance(requirementTypes[type]);
            }

            // Set attributes
            requirement.contractType = contractType;
            requirement.dataNode     = new DataNode(name, parent != null ? parent.dataNode : contractType.dataNode, requirement);

            // Load config
            valid &= requirement.Load(configNode);

            // Check for unexpected values - always do this last
            if (requirement.GetType() != typeof(InvalidContractRequirement))
            {
                valid &= ConfigNodeUtil.ValidateUnexpectedValues(configNode, requirement);
            }

            // Load child nodes
            foreach (ConfigNode childNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT"))
            {
                ContractRequirement child = null;
                valid &= ContractRequirement.GenerateRequirement(childNode, contractType, out child, requirement);
                if (child != null)
                {
                    requirement.childNodes.Add(child);
                    if (child.hasWarnings)
                    {
                        requirement.hasWarnings = true;
                    }
                }
            }

            requirement.enabled    = valid;
            requirement.log        = LoggingUtil.capturedLog;
            LoggingUtil.CaptureLog = false;

            return(valid);
        }
        /// <summary>
        /// Parses the child DATA nodes out of the given config node, and returns the parsed values back in dataValues.
        /// </summary>
        /// <param name="configNode">The ConfigNode to load child DATA nodes from.</param>
        /// <param name="obj">The ContractConfigurator object to load from.</param>
        /// <param name="dataValues"></param>
        /// <param name="uniquenessChecks"></param>
        /// <returns></returns>
        public bool ParseDataNodes(ConfigNode configNode, IContractConfiguratorFactory obj,
            Dictionary<string, bool> dataValues, Dictionary<string, UniquenessCheck> uniquenessChecks)
        {
            bool valid = true;

            foreach (ConfigNode data in ConfigNodeUtil.GetChildNodes(configNode, "DATA"))
            {
                Type type = null;
                bool requiredValue = true;

                ConfigNodeUtil.SetCurrentDataNode(null);
                valid &= ConfigNodeUtil.ParseValue<Type>(data, "type", x => type = x, obj);
                valid &= ConfigNodeUtil.ParseValue<bool>(data, "requiredValue", x => requiredValue = x, obj, true);

                UniquenessCheck uniquenessCheck = UniquenessCheck.NONE;
                // Backwards compatibility for Contract Configurator 1.8.3
                if (configNode.HasValue("uniqueValue") || configNode.HasValue("activeUniqueValue"))
                {
                    LoggingUtil.LogWarning(this, "The use of uniqueValue and activeUniqueValue is obsolete since Contract Configurator 1.9.0, use uniquenessCheck instead.");
                    
                    bool uniqueValue = false;
                    bool activeUniqueValue = false;
                    valid &= ConfigNodeUtil.ParseValue<bool>(data, "uniqueValue", x => uniqueValue = x, obj, false);
                    valid &= ConfigNodeUtil.ParseValue<bool>(data, "activeUniqueValue", x => activeUniqueValue = x, obj, false);

                    uniquenessCheck = activeUniqueValue ? UniquenessCheck.CONTRACT_ACTIVE : uniqueValue ? UniquenessCheck.CONTRACT_ALL : UniquenessCheck.NONE;
                }
                else
                {
                    valid &= ConfigNodeUtil.ParseValue<UniquenessCheck>(data, "uniquenessCheck", x => uniquenessCheck = x, obj, UniquenessCheck.NONE);
                }

                ConfigNodeUtil.SetCurrentDataNode(this);

                if (type != null)
                {
                    foreach (ConfigNode.Value pair in data.values)
                    {
                        string name = pair.name;
                        if (name != "type" && name != "requiredValue" && name != "uniqueValue" && name != "activeUniqueValue" && name != "uniquenessCheck")
                        {
                            object value = null;

                            // Create the setter function
                            Type actionType = typeof(Action<>).MakeGenericType(type);
                            Delegate del = Delegate.CreateDelegate(actionType, value, typeof(DataNode).GetMethod("NullAction"));

                            // Get the ParseValue method
                            MethodInfo method = typeof(ConfigNodeUtil).GetMethods(BindingFlags.Static | BindingFlags.Public).
                                Where(m => m.Name == "ParseValue" && m.GetParameters().Count() == 4).Single();
                            method = method.MakeGenericMethod(new Type[] { type });

                            // Invoke the ParseValue method
                            valid &= (bool)method.Invoke(null, new object[] { data, name, del, obj });

                            dataValues[name] = requiredValue;
                            if (uniquenessCheck != UniquenessCheck.NONE)
                            {
                                uniquenessChecks[name] = uniquenessCheck;
                            }
                        }
                    }
                }
            }

            return valid;
        }