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

            valid &= ConfigNodeUtil.ParseValue<string>(configNode, "basename", x => basename = x, this);

            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode, "CONDITION"))
            {
                DataNode childDataNode = new DataNode("CONDITION_" + index++, dataNode, this);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(childDataNode);
                    OpenBase.ConditionDetail cd = new OpenBase.ConditionDetail();
                    valid &= ConfigNodeUtil.ParseValue<OpenBase.ConditionDetail.Condition>(child, "condition", x => cd.condition = x, this);
                    valid &= ConfigNodeUtil.ParseValue<string>(child, "parameter", x => cd.parameter = x, this, "", x => ValidateMandatoryParameter(x, cd.condition));
                    conditions.Add(cd);
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);
                }
            }
            valid &= ConfigNodeUtil.ValidateMandatoryChild(configNode, "CONDITION", this);

            return valid;
        }
        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;
            }
        }
        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;
            }
        }
        public static Expression Parse(ConfigNode configNode, DataNode dataNode, ExpressionFactory factory)
        {
            Expression e = new Expression(dataNode);
            e.factory = factory;
            e.Load(configNode);
            e.factory = null;

            return e;
        }
 /// <summary>
 /// Copy constructor. 
 /// </summary>
 /// <param name="source"></param>
 public Expression(Expression source)
 {
     dataNode = source.dataNode;
     onOfferExpr = new List<ExpVal>(source.onOfferExpr);
     onAcceptExpr = new List<ExpVal>(source.onAcceptExpr);
     onSuccessExpr = new List<ExpVal>(source.onSuccessExpr);
     onFailExpr = new List<ExpVal>(source.onFailExpr);
     onParameterComplete = new Dictionary<string, List<ExpVal>>(source.onParameterComplete);
     SetupMap();
 }
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            valid &= ConfigNodeUtil.ParseValue<TriggeredBehaviour.State>(configNode, "onState", x => onState = x, this, TriggeredBehaviour.State.CONTRACT_SUCCESS);
            if (onState == TriggeredBehaviour.State.PARAMETER_COMPLETED || onState == TriggeredBehaviour.State.PARAMETER_FAILED)
            {
                valid &= ConfigNodeUtil.ParseValue<List<string>>(configNode, "parameter", x => parameter = x, this);
            }

            kerbalInfo = new List<ChangeKerbalType.KerbalInfo>();
            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode, "KERBAL_INFO"))
            {
                string kerbInfoNode = "KERBAL_INFO" + index++;
                DataNode childDataNode = new DataNode(kerbInfoNode, dataNode, this);

                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(childDataNode);
                    ChangeKerbalType.KerbalInfo kerb = new ChangeKerbalType.KerbalInfo();
                    kerbalInfo.Add(kerb);

                    valid &= ConfigNodeUtil.ParseValue<Kerbal>(child, "kerbal", x => kerb.kerbal = x, this);
                    valid &= ConfigNodeUtil.ParseValue<ProtoCrewMember.KerbalType?>(child, "kerbalType", x => kerb.kerbalType = x, this, (ProtoCrewMember.KerbalType?)null);
                    valid &= ConfigNodeUtil.ParseValue<string>(child, "trait", x => kerb.trait = x, this, "");
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);
                }
            }
            valid &= ConfigNodeUtil.ValidateMandatoryChild(configNode, "KERBAL_INFO", this);

            return valid;
        }
        /// <summary>
        /// Loads the contract type details from the given config node.
        /// </summary>
        /// <param name="configNode">The config node to load from.</param>
        /// <returns>Whether the load was successful.</returns>
        public bool Load(ConfigNode configNode)
        {
            LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel;

            try
            {
                // Logging on
                LoggingUtil.CaptureLog = true;
                ConfigNodeUtil.SetCurrentDataNode(null);

                // Load values that are immediately required
                bool valid = true;
                valid &= ConfigNodeUtil.ParseValue<ContractGroup>(configNode, "group", x => group = x, this, (ContractGroup)null);

                // Set up the data node
                dataNode = new DataNode(configNode.GetValue("name"), group != null ? group.dataNode : null, this);
                ConfigNodeUtil.SetCurrentDataNode(dataNode);

                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "name", x => name = x, this);

                // Try to turn on trace mode
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "trace", x => trace = x, this, false);
                if (trace)
                {
                    LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE;
                    LoggingUtil.LogWarning(this, "Tracing enabled for contract type " + name);
                }

                // Load contract text details
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "title", x => title = x, this);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "tag", x => tag = x, this, "");
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "description", x => description = x, this, (string)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "topic", x => topic = x, this, "");
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "subject", x => subject = x, this, "");
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "motivation", x => motivation = x, this, "");
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "notes", x => notes = x, this, (string)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "synopsis", x => synopsis = x, this);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "completedMessage", x => completedMessage = x, this);

                // Load optional attributes
                valid &= ConfigNodeUtil.ParseValue<Agent>(configNode, "agent", x => agent = x, this, (Agent)null);
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "minExpiry", x => minExpiry = x, this, 1.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "maxExpiry", x => maxExpiry = x, this, 7.0f, x => Validation.GE(x, minExpiry));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "deadline", x => deadline = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "cancellable", x => cancellable = x, this, true);
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "declinable", x => declinable = x, this, true);
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "autoAccept", x => autoAccept = x, this, false);
                valid &= ConfigNodeUtil.ParseValue<List<Contract.ContractPrestige>>(configNode, "prestige", x => prestige = x, this, new List<Contract.ContractPrestige>());
                valid &= ConfigNodeUtil.ParseValue<CelestialBody>(configNode, "targetBody", x => targetBody = x, this, (CelestialBody)null);
            
                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));

                // Load rewards
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardFunds", x => rewardFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardReputation", x => rewardReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardScience", x => rewardScience = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureFunds", x => failureFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureReputation", x => failureReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "advanceFunds", x => advanceFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f));

                // Load other values
                valid &= ConfigNodeUtil.ParseValue<double>(configNode, "weight", x => weight = x, this, 1.0, x => Validation.GE(x, 0.0f));

                // Merge in data from the parent contract group
                for (ContractGroup currentGroup = group; currentGroup != null; currentGroup = currentGroup.parent)
                {
                    // Merge dataValues - this is a flag saying what values need to be unique at the contract level
                    foreach (KeyValuePair<string, bool> pair in currentGroup.dataValues)
                    {
                        dataValues[group.name + ":" + pair.Key] = pair.Value;
                    }

                    // Merge uniquenessChecks
                    foreach (KeyValuePair<string, DataNode.UniquenessCheck> pair in currentGroup.uniquenessChecks)
                    {
                        uniquenessChecks[group.name + ":" + pair.Key] = pair.Value;
                    }
                }

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

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

                log = LoggingUtil.capturedLog;
                LoggingUtil.CaptureLog = false;

                // Load parameters
                foreach (ConfigNode contractParameter in ConfigNodeUtil.GetChildNodes(configNode, "PARAMETER"))
                {
                    ParameterFactory paramFactory = null;
                    valid &= ParameterFactory.GenerateParameterFactory(contractParameter, this, out paramFactory);
                    if (paramFactory != null)
                    {
                        paramFactories.Add(paramFactory);
                        if (paramFactory.hasWarnings)
                        {
                            hasWarnings = true;
                        }
                    }
                }

                // Load behaviours
                foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "BEHAVIOUR"))
                {
                    BehaviourFactory behaviourFactory = null;
                    valid &= BehaviourFactory.GenerateBehaviourFactory(requirementNode, this, out behaviourFactory);
                    if (behaviourFactory != null)
                    {
                        behaviourFactories.Add(behaviourFactory);
                        if (behaviourFactory.hasWarnings)
                        {
                            hasWarnings = true;
                        }
                    }
                }

                // Load requirements
                foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT"))
                {
                    ContractRequirement requirement = null;
                    valid &= ContractRequirement.GenerateRequirement(requirementNode, this, out requirement);
                    if (requirement != null)
                    {
                        requirements.Add(requirement);
                        if (requirement.hasWarnings)
                        {
                            hasWarnings = true;
                        }
                    }
                }

                // Logging on
                LoggingUtil.CaptureLog = true;

                // Check we have at least one valid parameter
                if (paramFactories.Count() == 0)
                {
                    LoggingUtil.LogError(this.GetType(), ErrorPrefix() + ": Need at least one parameter for a contract!");
                    valid = false;
                }

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

                config = configNode.ToString();
                hash = config.GetHashCode();
                enabled = valid;
                log += LoggingUtil.capturedLog;

				if (LoggingUtil.logLevel == LoggingUtil.LogLevel.VERBOSE || LoggingUtil.logLevel == LoggingUtil.LogLevel.DEBUG)
				{
					//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
					// to write the complete config and log for contract to both the system log and
					// a seperate CC log file
					//
					string pattern = @"\[(VERBOSE|DEBUG|INFO|WARNING|ERROR)\] ContractConfigurator\.ExpressionParser.BaseParser.+\n";
					string replacement = "";
					Regex rgx = new Regex(pattern);

					// First, write to the standard log file.  the regex strips out the leading text of the line, but 
					// if you want the text there, then just remove the rgx.Replace
					LoggingUtil.LogDebug(this, config);
					// Write the log out, ignoring the BaseParser lines
					LoggingUtil.LogDebug(this, rgx.Replace(log, replacement));

					// Now write to the CC log file, in a much cleaner manner 
					string path = ccLogFile;

					// Delete the file first time through, ignore any errors
					if (deleteCCLogfile)
					{
						deleteCCLogfile = false;
						try {
							if (File.Exists(path))
								File.Delete(path);
						} catch { 
							LoggingUtil.LogError(this, "Exception while attempting to delete the file: " + path);
						}
					}
					// Create the file if it doesn't exist
					if (!File.Exists(path)) 
					{
						// Create a file to write to.
						try {
							using (StreamWriter sw = File.CreateText(path)) {}
						} catch {
							LoggingUtil.LogError(this, "Exception while attempting to create the file: " + path);
						}
					}

					// This regex also strips out the second part of the line, so that the output is very clean 

					string pattern2 = @"\[(VERBOSE|DEBUG|INFO|WARNING|ERROR)\] ContractConfigurator\.ExpressionParser\.DataNode: ";
					Regex rgx2 = new Regex(pattern2);

					// Now write the config and the cleaned up log to it
					try {
						using (StreamWriter sw = File.AppendText (path)) {
							sw.WriteLine (config);
							sw.WriteLine("++++++++++\n");
							sw.WriteLine(rgx2.Replace(rgx.Replace(log, replacement), replacement));
							sw.WriteLine("==================================================================================");
	        		    }
					} catch {
						LoggingUtil.LogError(this, "Exception while attempting to write to the file: " + path);
					}
					//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
				}
				LoggingUtil.CaptureLog = false;

				return valid;
			}
            catch
            {
                enabled = false;
                throw;
            }
            finally
            {
                LoggingUtil.logLevel = origLogLevel;
                loaded = true;
            }
        }
        public static WaypointGenerator Create(ConfigNode configNode, WaypointGeneratorFactory factory)
        {
            WaypointGenerator wpGenerator = new WaypointGenerator();

            bool valid = true;
            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode))
            {
                DataNode dataNode = new DataNode("WAYPOINT_" + index, factory.dataNode, factory);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);
                    dataNode["type"] = child.name;

                    double? altitude = null;
                    WaypointData wpData = new WaypointData(child.name);

                    // Use an expression to default - then it'll work for dynamic contracts
                    if (!child.HasValue("targetBody"))
                    {
                        child.AddValue("targetBody", "@/targetBody");
                    }
                    valid &= ConfigNodeUtil.ParseValue<CelestialBody>(child, "targetBody", x => wpData.waypoint.celestialName = x != null ? x.name : "", factory);

                    valid &= ConfigNodeUtil.ParseValue<List<string>>(child, "name", x => wpData.names = x, factory, new List<string>());
                    valid &= ConfigNodeUtil.ParseValue<double?>(child, "altitude", x => altitude = x, factory, (double?)null);
                    valid &= ConfigNodeUtil.ParseValue<List<string>>(child, "parameter", x => wpData.parameter = x, factory, new List<string>());
                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "hidden", x => wpData.waypoint.visible = !x, factory, false);
                    if (!wpData.waypoint.visible)
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "icon", x => wpData.waypoint.id = x, factory, "");
                    }
                    else
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "icon", x => wpData.waypoint.id = x, factory);
                    }

                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "underwater", x => wpData.underwater = x, factory, false);
                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "clustered", x => wpData.waypoint.isClustered = x, factory, false);

                    // Track the index
                    wpData.waypoint.index = index++;

                    // Get altitude
                    if (altitude == null)
                    {
                        wpData.waypoint.altitude = 0.0;
                        wpData.randomAltitude = true;
                    }
                    else
                    {
                        wpData.waypoint.altitude = altitude.Value;
                    }

                    // Get settings that differ by type
                    if (child.name == "WAYPOINT")
                    {
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "latitude", x => wpData.waypoint.latitude = x, factory);
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "longitude", x => wpData.waypoint.longitude = x, factory);
                    }
                    else if (child.name == "RANDOM_WAYPOINT")
                    {
                        // Get settings for randomization
                        valid &= ConfigNodeUtil.ParseValue<bool>(child, "waterAllowed", x => wpData.waterAllowed = x, factory, true);
                        valid &= ConfigNodeUtil.ParseValue<bool>(child, "forceEquatorial", x => wpData.forceEquatorial = x, factory, false);
                        valid &= ConfigNodeUtil.ParseValue<int>(child, "count", x => wpData.count = x, factory, 1, x => Validation.GE(x, 1));
                    }
                    else if (child.name == "RANDOM_WAYPOINT_NEAR")
                    {
                        // Get settings for randomization
                        valid &= ConfigNodeUtil.ParseValue<bool>(child, "waterAllowed", x => wpData.waterAllowed = x, factory, true);

                        // Get near waypoint details
                        valid &= ConfigNodeUtil.ParseValue<int>(child, "nearIndex", x => wpData.nearIndex = x, factory,
                            x => Validation.GE(x, 0) && Validation.LT(x, wpGenerator.waypoints.Count));
                        valid &= ConfigNodeUtil.ParseValue<bool>(child, "chained", x => wpData.chained = x, factory, false);
                        valid &= ConfigNodeUtil.ParseValue<int>(child, "count", x => wpData.count = x, factory, 1, x => Validation.GE(x, 1));

                        // Get distances
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "minDistance", x => wpData.minDistance = x, factory, 0.0, x => Validation.GE(x, 0.0));
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "maxDistance", x => wpData.maxDistance = x, factory, x => Validation.GT(x, 0.0));
                    }
                    else if (child.name == "PQS_CITY")
                    {
                        wpData.randomAltitude = false;
                        string dummy = null;
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "pqsCity", x => dummy = x, factory, x =>
                        {
                            bool v = true;
                            if (!string.IsNullOrEmpty(wpData.waypoint.celestialName))
                            {
                                try
                                {
                                    CelestialBody body = FlightGlobals.Bodies.Where(b => b.name == wpData.waypoint.celestialName).First();
                                    wpData.pqsCity = body.GetComponentsInChildren<PQSCity>(true).Where(pqs => pqs.name == x).First();
                                }
                                catch (Exception e)
                                {
                                    LoggingUtil.LogError(typeof(WaypointGenerator), "Couldn't load PQSCity with name '" + x + "'");
                                    LoggingUtil.LogException(e);
                                    v = false;
                                }
                            }
                            else
                            {
                                // Force this to get re-run when the targetBody is loaded
                                throw new DataNode.ValueNotInitialized("/targetBody");
                            }
                            return v;
                        });
                        valid &= ConfigNodeUtil.ParseValue<Vector3d>(child, "pqsOffset", x => wpData.pqsOffset = x, factory, new Vector3d());
                    }
                    else
                    {
                        LoggingUtil.LogError(factory, "Unrecognized waypoint node: '" + child.name + "'");
                        valid = false;
                    }

                    // Check for unexpected values
                    valid &= ConfigNodeUtil.ValidateUnexpectedValues(child, factory);

                    // Copy waypoint data
                    WaypointData old = wpData;
                    for (int i = 0; i < old.count; i++)
                    {
                        wpData = new WaypointData(old, null);
                        wpGenerator.waypoints.Add(wpData);

                        if (old.parameter.Any())
                        {
                            wpData.parameter = new List<string>();
                            wpData.parameter.Add(old.parameter.Count() == 1 ? old.parameter.First() : old.parameter.ElementAtOrDefault(i));
                        }

                        // Set the name
                        if (old.names.Any())
                        {
                            wpData.waypoint.name = (old.names.Count() == 1 ? old.names.First() : old.names.ElementAtOrDefault(i));
                        }
                        if (string.IsNullOrEmpty(wpData.waypoint.name) || wpData.waypoint.name.ToLower() == "site")
                        {
                            wpData.waypoint.name = StringUtilities.GenerateSiteName(random.Next(), wpData.waypoint.celestialBody, !wpData.waterAllowed);
                        }

                        // Handle waypoint chaining
                        if (wpData.chained && i != 0)
                        {
                            wpData.nearIndex = wpGenerator.waypoints.Count - 2;
                        }
                    }
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(factory.dataNode);
                }
            }

            return valid ? wpGenerator : null;
        }
        /// <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;

                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 => minVersion = 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>());

                if (!string.IsNullOrEmpty(minVersion))
                {
                    if (Util.Version.VerifyAssemblyVersion("ContractConfigurator", minVersion) == 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 " + minVersion +
                            " to work, and you are running version " + ainfoV.InformationalVersion +
                            ".  Please upgrade Contract Configurator to use the contracts in this group.";
                        DialogOption dialogOption = new DialogOption("Okay", new Callback(DoNothing), true);
                        PopupDialog.SpawnPopupDialog(new MultiOptionDialog(message, title, HighLogic.Skin, dialogOption), false, HighLogic.Skin);
                    }
                }

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

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

                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;
                    }

                    valid &= child.Load(childNode);
                    child.parent = this;
                    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;
            }
        }
 public Expression(DataNode dataNode)
 {
     this.dataNode = dataNode;
     SetupMap();
 }
Esempio n. 11
0
        public Type GetType(string key)
        {
            DataNode node = NodeForKey(ref key);

            return(node.data.ContainsKey(key) && node.data[key] != null ? node.data[key].type : null);
        }
Esempio n. 12
0
        /// <summary>
        /// Validates whether the given value is initialized or not.
        /// </summary>
        /// <param name="key">The key to check for</param>
        /// <returns>True if the value has been read</returns>
        public bool IsInitialized(string key)
        {
            DataNode node = NodeForKey(ref key);

            return(node.data.ContainsKey(key) && node.data[key] != null && node.data[key].initialized);
        }
Esempio n. 13
0
 public abstract object ParseExpressionGeneric(string key, string expression, DataNode dataNode);
Esempio n. 14
0
 public abstract void ExecuteAndStoreExpression(string key, string expression, DataNode dataNode);
        public static SpawnVessel Create(ConfigNode configNode, SpawnVesselFactory factory)
        {
            SpawnVessel spawnVessel = new SpawnVessel();

            ConfigNodeUtil.ParseValue<bool>(configNode, "deferVesselCreation", x => spawnVessel.deferVesselCreation = x, factory, false);

            bool valid = true;
            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode, "VESSEL"))
            {
                DataNode dataNode = new DataNode("VESSEL_" + index++, factory.dataNode, factory);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);

                    VesselData vessel = new VesselData();

                    // Get name
                    if (child.HasValue("name"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "name", x => vessel.name = x, factory);
                    }

                    // Get craft details
                    if (child.HasValue("craftURL"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "craftURL", x => vessel.craftURL = x, factory);
                    }
                    if (child.HasValue("craftPart"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<AvailablePart>(child, "craftPart", x => vessel.craftPart = x, factory);
                    }
                    valid &= ConfigNodeUtil.AtLeastOne(child, new string[] { "craftURL", "craftPart" }, factory);

                    valid &= ConfigNodeUtil.ParseValue<string>(child, "flagURL", x => vessel.flagURL = x, factory, (string)null);
                    valid &= ConfigNodeUtil.ParseValue<VesselType>(child, "vesselType", x => vessel.vesselType = x, factory, VesselType.Ship);

                    // Use an expression to default - then it'll work for dynamic contracts
                    if (!child.HasValue("targetBody"))
                    {
                        child.AddValue("targetBody", "@/targetBody");
                    }
                    valid &= ConfigNodeUtil.ParseValue<CelestialBody>(child, "targetBody", x => vessel.body = x, factory);

                    // Get landed stuff
                    if (child.HasValue("pqsCity"))
                    {
                        string pqsCityStr = null;
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "pqsCity", x => pqsCityStr = x, factory);
                        if (pqsCityStr != null)
                        {
                            try
                            {
                                vessel.pqsCity = vessel.body.GetComponentsInChildren<PQSCity>(true).Where(pqs => pqs.name == pqsCityStr).First();
                            }
                            catch (Exception e)
                            {
                                LoggingUtil.LogError(typeof(WaypointGenerator), "Couldn't load PQSCity with name '" + pqsCityStr + "'");
                                LoggingUtil.LogException(e);
                                valid = false;
                            }
                        }
                        valid &= ConfigNodeUtil.ParseValue<Vector3d>(child, "pqsOffset", x => vessel.pqsOffset = x, factory, new Vector3d());

                        // Don't expect these to load anything, but do it to mark as initialized
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lat", x => vessel.latitude = x, factory, 0.0);
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lon", x => vessel.longitude = x, factory, 0.0);

                        // Do load alt and height
                        valid &= ConfigNodeUtil.ParseValue<double?>(child, "alt", x => vessel.altitude = x, factory, (double?)null);
                        valid &= ConfigNodeUtil.ParseValue<float>(child, "height", x => vessel.height = x, factory,
                            !string.IsNullOrEmpty(vessel.craftURL) ? 0.0f : 2.5f);
                        vessel.orbiting = false;

                        // Generate PQS city coordinates
                        LoggingUtil.LogVerbose(factory, "Generating coordinates from PQS city for Vessel " + vessel.name);

                        // Translate by the PQS offset (inverse transform of coordinate system)
                        Vector3d position = vessel.pqsCity.transform.position;
                        Vector3d v = vessel.pqsOffset;
                        Vector3d i = vessel.pqsCity.transform.right;
                        Vector3d j = vessel.pqsCity.transform.forward;
                        Vector3d k = vessel.pqsCity.transform.up;
                        Vector3d offsetPos = new Vector3d(
                            (j.y * k.z - j.z * k.y) * v.x + (i.z * k.y - i.y * k.z) * v.y + (i.y * j.z - i.z * j.y) * v.z,
                            (j.z * k.x - j.x * k.z) * v.x + (i.x * k.z - i.z * k.x) * v.y + (i.z * j.x - i.x * j.z) * v.z,
                            (j.x * k.y - j.y * k.x) * v.x + (i.y * k.x - i.x * k.y) * v.y + (i.x * j.y - i.y * j.x) * v.z
                        );
                        offsetPos *= (i.x * j.y * k.z) + (i.y * j.z * k.x) + (i.z * j.x * k.y) - (i.z * j.y * k.x) - (i.y * j.x * k.z) - (i.x * j.z * k.y);
                        vessel.latitude = vessel.body.GetLatitude(position + offsetPos);
                        vessel.longitude = vessel.body.GetLongitude(position + offsetPos);
                    }
                    else if (child.HasValue("lat") && child.HasValue("lon"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lat", x => vessel.latitude = x, factory);
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lon", x => vessel.longitude = x, factory);
                        valid &= ConfigNodeUtil.ParseValue<double?>(child, "alt", x => vessel.altitude = x, factory, (double?)null);
                        valid &= ConfigNodeUtil.ParseValue<float>(child, "height", x => vessel.height = x, factory,
                            !string.IsNullOrEmpty(vessel.craftURL) ? 0.0f : 2.5f);
                        vessel.orbiting = false;
                    }
                    // Get orbit
                    else
                    {
                        valid &= ConfigNodeUtil.ParseValue<Orbit>(child, "ORBIT", x => vessel.orbit = x, factory);
                        vessel.orbiting = true;
                    }

                    valid &= ConfigNodeUtil.ParseValue<float>(child, "heading", x => vessel.heading = x, factory, 0.0f);
                    valid &= ConfigNodeUtil.ParseValue<float>(child, "pitch", x => vessel.pitch = x, factory, 0.0f);
                    valid &= ConfigNodeUtil.ParseValue<float>(child, "roll", x => vessel.roll = x, factory, 0.0f);

                    // Get additional flags
                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "owned", x => vessel.owned = x, factory, false);

                    // Handle the CREW nodes
                    foreach (ConfigNode crewNode in ConfigNodeUtil.GetChildNodes(child, "CREW"))
                    {
                        int count = 1;
                        valid &= ConfigNodeUtil.ParseValue<int>(crewNode, "count", x => count = x, factory, 1);
                        for (int i = 0; i < count; i++)
                        {
                            CrewData cd = new CrewData();

                            // Read crew details
                            valid &= ConfigNodeUtil.ParseValue<string>(crewNode, "name", x => cd.name = x, factory, (string)null);
                            valid &= ConfigNodeUtil.ParseValue<bool>(crewNode, "addToRoster", x => cd.addToRoster = x, factory, true);

                            // Check for unexpected values
                            valid &= ConfigNodeUtil.ValidateUnexpectedValues(crewNode, factory);

                            // Add the record
                            vessel.crew.Add(cd);
                        }
                    }

                    // Check for unexpected values
                    valid &= ConfigNodeUtil.ValidateUnexpectedValues(child, factory);

                    // Add to the list
                    spawnVessel.vessels.Add(vessel);
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(factory.dataNode);
                }
            }

            if (!configNode.HasNode("VESSEL"))
            {
                valid = false;
                LoggingUtil.LogError(factory, "SpawnVessel requires at least one VESSEL node.");
            }

            return valid ? spawnVessel : null;
        }
        public static SpawnVessel Create(ConfigNode configNode, SpawnVesselFactory factory)
        {
            SpawnVessel spawnVessel = new SpawnVessel();

            ConfigNodeUtil.ParseValue<bool>(configNode, "deferVesselCreation", x => spawnVessel.deferVesselCreation = x, factory, false);

            bool valid = true;
            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode, "VESSEL"))
            {
                DataNode dataNode = new DataNode("VESSEL_" + index++, factory.dataNode, factory);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);

                    VesselData vessel = new VesselData();

                    // Get name
                    if (child.HasValue("name"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "name", x => vessel.name = x, factory);
                    }

                    // Get craft details
                    if (child.HasValue("craftURL"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "craftURL", x => vessel.craftURL = x, factory);
                    }
                    if (child.HasValue("craftPart"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<AvailablePart>(child, "craftPart", x => vessel.craftPart = x, factory);
                    }
                    valid &= ConfigNodeUtil.AtLeastOne(child, new string[] { "craftURL", "craftPart" }, factory);

                    valid &= ConfigNodeUtil.ParseValue<string>(child, "flagURL", x => vessel.flagURL = x, factory, (string)null);
                    valid &= ConfigNodeUtil.ParseValue<VesselType>(child, "vesselType", x => vessel.vesselType = x, factory, VesselType.Ship);

                    // Use an expression to default - then it'll work for dynamic contracts
                    if (!child.HasValue("targetBody"))
                    {
                        child.AddValue("targetBody", "@/targetBody");
                    }
                    valid &= ConfigNodeUtil.ParseValue<CelestialBody>(child, "targetBody", x => vessel.body = x, factory);

                    // Get landed stuff
                    if (child.HasValue("lat") && child.HasValue("lon"))
                    {
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lat", x => vessel.latitude = x, factory);
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lon", x => vessel.longitude = x, factory);
                        valid &= ConfigNodeUtil.ParseValue<double?>(child, "alt", x => vessel.altitude = x, factory, (double?)null);
                        valid &= ConfigNodeUtil.ParseValue<float>(child, "height", x => vessel.height = x, factory,
                            !string.IsNullOrEmpty(vessel.craftURL) ? 0.0f : 2.5f);
                        vessel.orbiting = false;
                    }
                    // Get orbit
                    else
                    {
                        valid &= ConfigNodeUtil.ParseValue<Orbit>(child, "ORBIT", x => vessel.orbit = x, factory);
                        vessel.orbiting = true;
                    }

                    valid &= ConfigNodeUtil.ParseValue<float>(child, "heading", x => vessel.heading = x, factory, 0.0f);
                    valid &= ConfigNodeUtil.ParseValue<float>(child, "pitch", x => vessel.pitch = x, factory, 0.0f);
                    valid &= ConfigNodeUtil.ParseValue<float>(child, "roll", x => vessel.roll = x, factory, 0.0f);

                    // Get additional flags
                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "owned", x => vessel.owned = x, factory, false);

                    // Handle the CREW nodes
                    foreach (ConfigNode crewNode in ConfigNodeUtil.GetChildNodes(child, "CREW"))
                    {
                        int count = 1;
                        valid &= ConfigNodeUtil.ParseValue<int>(crewNode, "count", x => count = x, factory, 1);
                        for (int i = 0; i < count; i++)
                        {
                            CrewData cd = new CrewData();

                            // Read crew details
                            valid &= ConfigNodeUtil.ParseValue<string>(crewNode, "name", x => cd.name = x, factory, (string)null);
                            valid &= ConfigNodeUtil.ParseValue<bool>(crewNode, "addToRoster", x => cd.addToRoster = x, factory, true);

                            // Check for unexpected values
                            valid &= ConfigNodeUtil.ValidateUnexpectedValues(crewNode, factory);

                            // Add the record
                            vessel.crew.Add(cd);
                        }
                    }

                    // Check for unexpected values
                    valid &= ConfigNodeUtil.ValidateUnexpectedValues(child, factory);

                    // Add to the list
                    spawnVessel.vessels.Add(vessel);
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(factory.dataNode);
                }
            }

            if (!configNode.HasNode("VESSEL"))
            {
                valid = false;
                LoggingUtil.LogError(factory, "SpawnVessel requires at least one VESSEL node.");
            }

            return valid ? spawnVessel : null;
        }
        /// <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(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;
            }
        }
        public static WaypointGenerator Create(ConfigNode configNode, WaypointGeneratorFactory factory)
        {
            WaypointGenerator wpGenerator = new WaypointGenerator();

            bool valid = true;
            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode))
            {
                DataNode dataNode = new DataNode("WAYPOINT_" + index, factory.dataNode, factory);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);
                    dataNode["type"] = child.name;

                    double? altitude = null;
                    WaypointData wpData = new WaypointData(child.name);

                    // Use an expression to default - then it'll work for dynamic contracts
                    if (!child.HasValue("targetBody"))
                    {
                        child.AddValue("targetBody", "@/targetBody.Name()");
                    }
                    valid &= ConfigNodeUtil.ParseValue<string>(child, "targetBody", x => wpData.waypoint.celestialName = x, factory, Validation.CheckCelestialBody);

                    valid &= ConfigNodeUtil.ParseValue<string>(child, "name", x => wpData.waypoint.name = x, factory, (string)null);
                    valid &= ConfigNodeUtil.ParseValue<double?>(child, "altitude", x => altitude = x, factory, (double?)null);
                    valid &= ConfigNodeUtil.ParseValue<string>(child, "parameter", x => wpData.parameter = x, factory, "");
                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "hidden", x => wpData.waypoint.visible = !x, factory, false);
                    if (!wpData.waypoint.visible)
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "icon", x => wpData.waypoint.id = x, factory, "");
                    }
                    else
                    {
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "icon", x => wpData.waypoint.id = x, factory);
                    }

                    // The FinePrint logic is such that it will only look in Squad/Contracts/Icons for icons.
                    // Cheat this by hacking the path in the game database.
                    if (wpData.waypoint.id.Contains("/"))
                    {
                        GameDatabase.TextureInfo texInfo = GameDatabase.Instance.databaseTexture.Where(t => t.name == wpData.waypoint.id).FirstOrDefault();
                        if (texInfo != null)
                        {
                            texInfo.name = "Squad/Contracts/Icons/" + wpData.waypoint.id;
                        }
                    }

                    // Track the index
                    wpData.waypoint.index = index++;

                    // Get altitude
                    if (altitude == null)
                    {
                        wpData.waypoint.altitude = 0.0;
                        wpData.randomAltitude = true;
                    }
                    else
                    {
                        wpData.waypoint.altitude = altitude.Value;
                    }

                    // Get settings that differ by type
                    if (child.name == "WAYPOINT")
                    {
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "latitude", x => wpData.waypoint.latitude = x, factory);
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "longitude", x => wpData.waypoint.longitude = x, factory);
                    }
                    else if (child.name == "RANDOM_WAYPOINT")
                    {
                        // Get settings for randomization
                        valid &= ConfigNodeUtil.ParseValue<bool>(child, "waterAllowed", x => wpData.waterAllowed = x, factory, true);
                        valid &= ConfigNodeUtil.ParseValue<bool>(child, "forceEquatorial", x => wpData.forceEquatorial = x, factory, false);
                        valid &= ConfigNodeUtil.ParseValue<int>(child, "count", x => wpData.count = x, factory, 1, x => Validation.GE(x, 1));
                    }
                    else if (child.name == "RANDOM_WAYPOINT_NEAR")
                    {
                        // Get settings for randomization
                        valid &= ConfigNodeUtil.ParseValue<bool>(child, "waterAllowed", x => wpData.waterAllowed = x, factory, true);

                        // Get near waypoint details
                        valid &= ConfigNodeUtil.ParseValue<int>(child, "nearIndex", x => wpData.nearIndex = x, factory,
                            x => Validation.GE(x, 0) && Validation.LT(x, wpGenerator.waypoints.Count));
                        valid &= ConfigNodeUtil.ParseValue<int>(child, "count", x => wpData.count = x, factory, 1, x => Validation.GE(x, 1));

                        // Get distances
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "minDistance", x => wpData.minDistance = x, factory, 0.0, x => Validation.GE(x, 0.0));
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "maxDistance", x => wpData.maxDistance = x, factory, x => Validation.GT(x, wpData.minDistance));
                    }
                    else if (child.name == "PQS_CITY")
                    {
                        wpData.randomAltitude = false;
                        string pqsCity = null;
                        valid &= ConfigNodeUtil.ParseValue<string>(child, "pqsCity", x => pqsCity = x, factory);
                        if (pqsCity != null && !string.IsNullOrEmpty(wpData.waypoint.celestialName))
                        {
                            try
                            {
                                CelestialBody body = FlightGlobals.Bodies.Where(b => b.name == wpData.waypoint.celestialName).First();
                                wpData.pqsCity = body.GetComponentsInChildren<PQSCity>(true).Where(pqs => pqs.name == pqsCity).First();
                            }
                            catch (Exception e)
                            {
                                LoggingUtil.LogError(typeof(WaypointGenerator), "Couldn't load PQSCity with name '" + pqsCity + "'");
                                LoggingUtil.LogException(e);
                                valid = false;
                            }
                        }
                        valid &= ConfigNodeUtil.ParseValue<Vector3d>(child, "pqsOffset", x => wpData.pqsOffset = x, factory, new Vector3d());
                    }
                    else
                    {
                        LoggingUtil.LogError(factory, "Unrecognized waypoint node: '" + child.name + "'");
                        valid = false;
                    }

                    // Check for unexpected values
                    valid &= ConfigNodeUtil.ValidateUnexpectedValues(child, factory);

                    // Generate a random name
                    if (!child.HasValue("name"))
                    {
                        wpData.randomName = true;
                    }

                    // Add to the list
                    wpGenerator.waypoints.Add(wpData);
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(factory.dataNode);
                }
            }

            return valid ? wpGenerator : null;
        }
        public static SpawnKerbal Create(ConfigNode configNode, SpawnKerbalFactory factory)
        {
            SpawnKerbal spawnKerbal = new SpawnKerbal();

            bool valid = true;
            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode, "KERBAL"))
            {
                DataNode dataNode = new DataNode("KERBAL_" + index++, factory.dataNode, factory);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);

                    KerbalData kerbal = new KerbalData();

                    // Get name
                    valid &= ConfigNodeUtil.ParseValue<string>(child, "name", x => { kerbal.name = x; if (kerbal.crewMember != null) kerbal.crewMember.name = x; },
                        factory, (string)null);

                    // Use an expression to default - then it'll work for dynamic contracts
                    if (!child.HasValue("targetBody"))
                    {
                        child.AddValue("targetBody", "@/targetBody");
                    }
                    valid &= ConfigNodeUtil.ParseValue<CelestialBody>(child, "targetBody", x => kerbal.body = x, factory);

                    // Get landed stuff
                    if (child.HasValue("lat") && child.HasValue("lon") || child.HasValue("pqsCity"))
                    {
                        kerbal.landed = true;
                        if (child.HasValue("pqsCity"))
                        {
                            string pqsCityStr = null;
                            valid &= ConfigNodeUtil.ParseValue<string>(child, "pqsCity", x => pqsCityStr = x, factory);
                            if (pqsCityStr != null)
                            {
                                try
                                {
                                    kerbal.pqsCity = kerbal.body.GetComponentsInChildren<PQSCity>(true).Where(pqs => pqs.name == pqsCityStr).First();
                                }
                                catch (Exception e)
                                {
                                    LoggingUtil.LogError(typeof(WaypointGenerator), "Couldn't load PQSCity with name '" + pqsCityStr + "'");
                                    LoggingUtil.LogException(e);
                                    valid = false;
                                }
                            }
                            valid &= ConfigNodeUtil.ParseValue<Vector3d>(child, "pqsOffset", x => kerbal.pqsOffset = x, factory, new Vector3d());

                            // Don't expect these to load anything, but do it to mark as initialized
                            valid &= ConfigNodeUtil.ParseValue<double>(child, "lat", x => kerbal.latitude = x, factory, 0.0);
                            valid &= ConfigNodeUtil.ParseValue<double>(child, "lon", x => kerbal.longitude = x, factory, 0.0);
                        }
                        else
                        {
                            valid &= ConfigNodeUtil.ParseValue<double>(child, "lat", x => kerbal.latitude = x, factory);
                            valid &= ConfigNodeUtil.ParseValue<double>(child, "lon", x => kerbal.longitude = x, factory);
                        }

                        valid &= ConfigNodeUtil.ParseValue<float>(child, "heading", x => kerbal.heading = x, factory, 0.0f);
                    }
                    // Get orbit
                    else if (child.HasNode("ORBIT"))
                    {
                        // Don't expect these to load anything, but do it to mark as initialized
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lat", x => kerbal.latitude = x, factory, 0.0);
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "lon", x => kerbal.longitude = x, factory, 0.0);

                        valid &= ConfigNodeUtil.ParseValue<Orbit>(child, "ORBIT", x => kerbal.orbit = x, factory);
                    }
                    else
                    {
                        // Will error
                        valid &= ConfigNodeUtil.ValidateMandatoryChild(child, "ORBIT", factory);
                    }

                    valid &= ConfigNodeUtil.ParseValue<double?>(child, "alt", x => kerbal.altitude = x, factory, (double?)null);

                    // Get additional stuff
                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "owned", x => kerbal.owned = x, factory, false);
                    valid &= ConfigNodeUtil.ParseValue<bool>(child, "addToRoster", x => kerbal.addToRoster = x, factory, true);
                    valid &= ConfigNodeUtil.ParseValue<ProtoCrewMember.Gender?>(child, "gender", x => kerbal.gender = x, factory, (ProtoCrewMember.Gender?)null);
                    valid &= ConfigNodeUtil.ParseValue<ProtoCrewMember.KerbalType>(child, "kerbalType", x => kerbal.kerbalType = x, factory, ProtoCrewMember.KerbalType.Unowned);

                    // Check for unexpected values
                    valid &= ConfigNodeUtil.ValidateUnexpectedValues(child, factory);

                    // Add to the list
                    spawnKerbal.kerbals.Add(kerbal);
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(factory.dataNode);
                }
            }

            return valid ? spawnKerbal : null;
        }
Esempio n. 20
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);
        }
        public static OrbitGenerator Create(ConfigNode configNode, OrbitGeneratorFactory factory)
        {
            OrbitGenerator obGenerator = new OrbitGenerator();

            bool valid = true;
            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode))
            {
                DataNode dataNode = new DataNode("ORBIT_" + index++, factory.dataNode, factory);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);

                    OrbitData obData = new OrbitData(child.name);

                    // Get settings that differ by type
                    if (child.name == "FIXED_ORBIT")
                    {
                        valid &= ConfigNodeUtil.ParseValue<Orbit>(child, "ORBIT", x => obData.orbit = x, factory);
                    }
                    else if (child.name == "RANDOM_ORBIT")
                    {
                        valid &= ConfigNodeUtil.ParseValue<OrbitType>(child, "type", x => obData.orbitType = x, factory);
                        valid &= ConfigNodeUtil.ParseValue<int>(child, "count", x => obData.count = x, factory, 1, x => Validation.GE(x, 1));
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "altitudeFactor", x => obData.altitudeFactor = x, factory, 0.8, x => Validation.Between(x, 0.0, 1.0));
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "inclinationFactor", x => obData.inclinationFactor = x, factory, 0.8, x => Validation.Between(x, 0.0, 1.0));
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "eccentricity", x => obData.eccentricity = x, factory, 0.0, x => Validation.GE(x, 0.0));
                        valid &= ConfigNodeUtil.ParseValue<double>(child, "deviationWindow", x => obData.deviationWindow = x, factory, 10.0, x => Validation.GE(x, 0.0));
                    }
                    else
                    {
                        throw new ArgumentException("Unrecognized orbit node: '" + child.name + "'");
                    }

                    // Use an expression to default - then it'll work for dynamic contracts
                    if (!child.HasValue("targetBody"))
                    {
                        child.AddValue("targetBody", "@/targetBody");
                    }
                    valid &= ConfigNodeUtil.ParseValue<CelestialBody>(child, "targetBody", x => obData.targetBody = x, factory);

                    // Check for unexpected values
                    valid &= ConfigNodeUtil.ValidateUnexpectedValues(child, factory);

                    // Add to the list
                    obGenerator.orbits.Add(obData);
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(factory.dataNode);
                }
            }

            allOrbitGenerators.Add(obGenerator);

            return valid ? obGenerator : null;
        }
        /// <summary>
        /// Loads the contract type details from the given config node.
        /// </summary>
        /// <param name="configNode">The config node to load from.</param>
        /// <returns>Whether the load was successful.</returns>
        public bool Load(ConfigNode configNode)
        {
            LoggingUtil.LogLevel origLogLevel = LoggingUtil.logLevel;

            try
            {
                // Logging on
                LoggingUtil.CaptureLog = true;

                dataNode = new DataNode(configNode.GetValue("name"), this);

                ConfigNodeUtil.SetCurrentDataNode(dataNode);
                bool valid = true;

                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "name", x => name = x, this);

                // Try to turn on trace mode
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "trace", x => trace = x, this, false);
                if (trace)
                {
                    LoggingUtil.logLevel = LoggingUtil.LogLevel.VERBOSE;
                    LoggingUtil.LogWarning(this, "Tracing enabled for contract type " + name);
                }

                // Load contract text details
                valid &= ConfigNodeUtil.ParseValue<ContractGroup>(configNode, "group", x => group = x, this, (ContractGroup)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "title", x => title = x, this);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "tag", x => tag = x, this, "");
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "description", x => description = x, this, (string)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "topic", x => topic = x, this, (string)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "subject", x => subject = x, this, (string)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "motivation", x => motivation = x, this, (string)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "notes", x => notes = x, this, (string)null);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "synopsis", x => synopsis = x, this);
                valid &= ConfigNodeUtil.ParseValue<string>(configNode, "completedMessage", x => completedMessage = x, this);

                // Load optional attributes
                valid &= ConfigNodeUtil.ParseValue<Agent>(configNode, "agent", x => agent = x, this, (Agent)null);
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "minExpiry", x => minExpiry = x, this, 1.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "maxExpiry", x => maxExpiry = x, this, 7.0f, x => Validation.GE(x, minExpiry));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "deadline", x => deadline = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "cancellable", x => cancellable = x, this, true);
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "declinable", x => declinable = x, this, true);
                valid &= ConfigNodeUtil.ParseValue<bool>(configNode, "autoAccept", x => autoAccept = x, this, false);
                valid &= ConfigNodeUtil.ParseValue<List<Contract.ContractPrestige>>(configNode, "prestige", x => prestige = x, this, new List<Contract.ContractPrestige>());
                valid &= ConfigNodeUtil.ParseValue<CelestialBody>(configNode, "targetBody", x => targetBody = x, this, (CelestialBody)null);

                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));

                // Load rewards
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardFunds", x => rewardFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardReputation", x => rewardReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "rewardScience", x => rewardScience = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureFunds", x => failureFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "failureReputation", x => failureReputation = x, this, 0.0f, x => Validation.GE(x, 0.0f));
                valid &= ConfigNodeUtil.ParseValue<float>(configNode, "advanceFunds", x => advanceFunds = x, this, 0.0f, x => Validation.GE(x, 0.0f));

                // Load other values
                valid &= ConfigNodeUtil.ParseValue<double>(configNode, "weight", x => weight = x, this, 1.0, x => Validation.GE(x, 0.0f));

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

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

                log = LoggingUtil.capturedLog;
                LoggingUtil.CaptureLog = false;

                // Load parameters
                foreach (ConfigNode contractParameter in ConfigNodeUtil.GetChildNodes(configNode, "PARAMETER"))
                {
                    ParameterFactory paramFactory = null;
                    valid &= ParameterFactory.GenerateParameterFactory(contractParameter, this, out paramFactory);
                    if (paramFactory != null)
                    {
                        paramFactories.Add(paramFactory);
                        if (paramFactory.hasWarnings)
                        {
                            hasWarnings = true;
                        }
                    }
                }

                // Load behaviours
                foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "BEHAVIOUR"))
                {
                    BehaviourFactory behaviourFactory = null;
                    valid &= BehaviourFactory.GenerateBehaviourFactory(requirementNode, this, out behaviourFactory);
                    if (behaviourFactory != null)
                    {
                        behaviourFactories.Add(behaviourFactory);
                        if (behaviourFactory.hasWarnings)
                        {
                            hasWarnings = true;
                        }
                    }
                }

                // Load requirements
                foreach (ConfigNode requirementNode in ConfigNodeUtil.GetChildNodes(configNode, "REQUIREMENT"))
                {
                    ContractRequirement requirement = null;
                    valid &= ContractRequirement.GenerateRequirement(requirementNode, this, out requirement);
                    if (requirement != null)
                    {
                        requirements.Add(requirement);
                        if (requirement.hasWarnings)
                        {
                            hasWarnings = true;
                        }
                    }
                }

                // Logging on
                LoggingUtil.CaptureLog = true;

                // Check we have at least one valid parameter
                if (paramFactories.Count() == 0)
                {
                    LoggingUtil.LogError(this.GetType(), ErrorPrefix() + ": Need at least one parameter for a contract!");
                    valid = false;
                }

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

                config = configNode.ToString();
                hash = config.GetHashCode();
                enabled = valid;
                log += LoggingUtil.capturedLog;
                LoggingUtil.CaptureLog = false;

                return valid;
            }
            catch
            {
                enabled = false;
                throw;
            }
            finally
            {
                LoggingUtil.logLevel = origLogLevel;
                loaded = true;
            }
        }
        public override bool Load(ConfigNode configNode)
        {
            // Load base class
            bool valid = base.Load(configNode);

            int index = 0;
            foreach (ConfigNode child in ConfigNodeUtil.GetChildNodes(configNode, "DIALOG_BOX"))
            {
                string dialogBoxNode = "DIALOG_BOX_" + index++;
                DataNode childDataNode = new DataNode(dialogBoxNode, dataNode, this);
                try
                {
                    ConfigNodeUtil.SetCurrentDataNode(childDataNode);
                    DialogBox.DialogDetail detail = new DialogBox.DialogDetail();
                    details.Add(detail);

                    valid &= ConfigNodeUtil.ParseValue<DialogBox.TriggerCondition>(child, "condition", x => detail.condition = x, this);
                    valid &= ConfigNodeUtil.ParseValue<DialogBox.Position>(child, "position", x => detail.position = x, this, DialogBox.Position.LEFT);
                    valid &= ConfigNodeUtil.ParseValue<float>(child, "width", x => detail.width = x, this, 0.8f, x => Validation.Between(x, 0.0f, 1.0f));
                    valid &= ConfigNodeUtil.ParseValue<float>(child, "height", x => detail.height = x, this, 0.0f, x => Validation.Between(x, 0.0f, 1.0f));
                    valid &= ConfigNodeUtil.ParseValue<string>(child, "title", x => detail.title = x, this, "");
                    valid &= ConfigNodeUtil.ParseValue<Color>(child, "titleColor", x => detail.titleColor = x, this, Color.white);
                    valid &= ConfigNodeUtil.ParseValue<string>(child, "parameter", x => detail.parameter = x, this, (string)null,
                        x => ValidateMandatoryParameter(x, detail.condition));

                    int sectionIndex = 0;
                    foreach (ConfigNode sectionNode in child.GetNodes())
                    {
                        DataNode sectionDataNode = new DataNode(dialogBoxNode + "_" + sectionIndex++, childDataNode, this);
                        ConfigNodeUtil.SetCurrentDataNode(sectionDataNode);

                        if (sectionNode.name == "TEXT")
                        {
                            DialogBox.TextSection section = new DialogBox.TextSection();
                            detail.sections.Add(section);

                            // Parse the text twice, once to ensure parsability, the other to get the unexpanded text
                            valid &= ConfigNodeUtil.ParseValue<string>(sectionNode, "text", x => { }, this);
                            if (valid)
                            {
                                section.text = ConfigNodeUtil.ParseValue<string>(sectionNode, "text");
                            }

                            valid &= ConfigNodeUtil.ParseValue<Color>(sectionNode, "textColor", x => section.textColor = x, this, new Color(0.8f, 0.8f, 0.8f));
                            valid &= ConfigNodeUtil.ParseValue<int>(sectionNode, "fontSize", x => section.fontSize = x, this, 20);
                        }
                        else if (sectionNode.name == "IMAGE")
                        {
                            DialogBox.ImageSection section = new DialogBox.ImageSection();
                            detail.sections.Add(section);

                            valid &= ConfigNodeUtil.ParseValue<string>(sectionNode, "url", x => section.imageURL = x, this, ValidateImageURL);
                            valid &= ConfigNodeUtil.ParseValue<string>(sectionNode, "characterName",
                                x => { section.characterName = x; section.showName = !string.IsNullOrEmpty(x); }, this, "");
                             
                            valid &= ConfigNodeUtil.ParseValue<Color>(sectionNode, "textColor", x => section.textColor = x, this, new Color(0.729f, 0.855f, 0.333f));
                        }
                        else if (sectionNode.name == "INSTRUCTOR")
                        {
                            DialogBox.InstructorSection section = new DialogBox.InstructorSection();
                            detail.sections.Add(section);

                            valid &= ConfigNodeUtil.ParseValue<string>(sectionNode, "name", x => section.name = x, this);
                            valid &= ConfigNodeUtil.ParseValue<bool>(sectionNode, "showName", x => section.showName = x, this, true);
                            valid &= ConfigNodeUtil.ParseValue<string>(sectionNode, "characterName", x => section.characterName = x, this, "");
                            valid &= ConfigNodeUtil.ParseValue<Color>(sectionNode, "textColor", x => section.textColor = x, this, new Color(0.729f, 0.855f, 0.333f));
                            valid &= ConfigNodeUtil.ParseValue<DialogBox.InstructorSection.Animation?>(sectionNode, "animation", x => section.animation = x, this,
                                (DialogBox.InstructorSection.Animation?)null);
                        }
                        else if (sectionNode.name == "KERBAL")
                        {
                            DialogBox.KerbalSection section = new DialogBox.KerbalSection();
                            detail.sections.Add(section);

                            valid &= ConfigNodeUtil.ParseValue<bool>(sectionNode, "showName", x => section.showName = x, this, true);
                            valid &= ConfigNodeUtil.ParseValue<string>(sectionNode, "characterName", x => section.characterName = x, this, "");
                            valid &= ConfigNodeUtil.ParseValue<ProtoCrewMember.Gender>(sectionNode, "gender", x => section.gender = x, this, ProtoCrewMember.Gender.Male);
                            valid &= ConfigNodeUtil.ParseValue<Color>(sectionNode, "textColor", x => section.textColor = x, this, new Color(0.729f, 0.855f, 0.333f));

                            valid &= ConfigNodeUtil.ParseValue<int>(sectionNode, "crewIndex", x => section.crewIndex = x, this, 0);
                            valid &= ConfigNodeUtil.ParseValue<List<string>>(sectionNode, "excludeName", x => section.excludeName = x, this, new List<string>());
                        }
                        else if (sectionNode.name == "BREAK")
                        {
                            DialogBox.BreakSection section = new DialogBox.BreakSection();
                            detail.sections.Add(section);
                        }
                    }
                }
                finally
                {
                    ConfigNodeUtil.SetCurrentDataNode(dataNode);
                }
            }
            valid &= ConfigNodeUtil.ValidateMandatoryChild(configNode, "DIALOG_BOX", this);

            return valid;
        }
        /// <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;
        }
            public override void OnGUI()
            {
                if (labelStyle == null)
                {
                    labelStyle = new GUIStyle(UnityEngine.GUI.skin.label);
                    labelStyle.alignment = TextAnchor.UpperLeft;
                    labelStyle.richText = true;
                    labelStyle.normal.textColor = textColor;
                    labelStyle.fontSize = fontSize;
                }

                if (expandedText == null)
                {
                    DataNode emptyNode = new DataNode("empty", null);
                    ExpressionParser<string> parser = BaseParser.GetParser<string>();
                    expandedText = parser.ExecuteExpression("null", text, emptyNode);
                }

                GUILayout.Label(expandedText, labelStyle, GUILayout.ExpandWidth(true));
            }
        public bool IsChildOf(DataNode node)
        {
            for (DataNode p = this; p != null; p = p.parent)
            {
                if (node == p)
                {
                    return true;
                }
            }

            return false;
        }
        static string DataNodeDebug(DataNode node, int indent = 0)
        {
            if (node == null)
            {
                return "";
            }

            string indentStr = new string('\t', indent);
            string result = indentStr + node.DebugString().Replace("\n", "\n" + indentStr) + "\n";
            foreach (DataNode child in node.Children)
            {
                if (child.Factory == node.Factory)
                {
                    result += DataNodeDebug(child, indent + 1);
                }
            }

            return result;
        }
Esempio n. 28
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());
        }